mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 17:47:53 +00:00
Compare commits
46 Commits
connect_re
...
SP-1218
Author | SHA1 | Date | |
---|---|---|---|
60bf58d5fd | |||
8d072ee6bb | |||
de614d40a5 | |||
45f6599c40 | |||
ec502214f4 | |||
64adf516f6 | |||
ef777cfce9 | |||
6e90f81760 | |||
51cfa8d5ae | |||
4469efe465 | |||
c7c8e9a519 | |||
692b05a600 | |||
7607e5f80d | |||
b84513c09d | |||
41605bef6b | |||
fd24d6bd27 | |||
5ea29efaf5 | |||
70cb12236b | |||
9f75ce817e | |||
aa23daa0b4 | |||
61f0c3ad2b | |||
553c77d1e3 | |||
27fef7ddaa | |||
010176cc25 | |||
d08a1d1037 | |||
e634154fb3 | |||
c0f59aba61 | |||
7ee7681e09 | |||
57c5f4752c | |||
ad4f2ae382 | |||
eafb811d2e | |||
2d0dcc41df | |||
d89e3fac8e | |||
25acd67351 | |||
0c2a092f4d | |||
b968b5a6eb | |||
05edc7641a | |||
b8204f1015 | |||
d87fec796b | |||
b00b0c82dc | |||
0aa029a2fc | |||
dec3a25639 | |||
581dcf7016 | |||
e1609309cf | |||
da445e11aa | |||
55de7fab0f |
6
assets/icons/delete_space_model.svg
Normal file
6
assets/icons/delete_space_model.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.4 2.10938H11.7333V1.58203C11.7333 0.709699 11.0156 0 10.1333 0H5.86667C4.98443 0 4.26667 0.709699 4.26667 1.58203V2.10938H1.6C0.71776 2.10938 0 2.81907 0 3.69141C0 4.392 0.463111 4.9873 1.1024 5.19472L2.05369 16.5493C2.1222 17.3628 2.82258 18 3.64814 18H12.3519C13.1775 18 13.8778 17.3628 13.9464 16.5491L14.8976 5.19469C15.5369 4.9873 16 4.392 16 3.69141C16 2.81907 15.2822 2.10938 14.4 2.10938ZM5.33333 1.58203C5.33333 1.29125 5.57259 1.05469 5.86667 1.05469H10.1333C10.4274 1.05469 10.6667 1.29125 10.6667 1.58203V2.10938H5.33333V1.58203ZM12.8833 16.4618C12.8605 16.7329 12.6271 16.9453 12.3519 16.9453H3.64814C3.37298 16.9453 3.13952 16.7329 3.11673 16.462L2.17934 5.27344H13.8207L12.8833 16.4618ZM14.4 4.21875H1.6C1.30592 4.21875 1.06667 3.98218 1.06667 3.69141C1.06667 3.40063 1.30592 3.16406 1.6 3.16406H14.4C14.6941 3.16406 14.9333 3.40063 14.9333 3.69141C14.9333 3.98218 14.6941 4.21875 14.4 4.21875Z" fill="#999999"/>
|
||||
<path d="M5.86561 15.3307L5.33228 6.82286C5.31404 6.53215 5.05957 6.31106 4.76698 6.32916C4.47297 6.3472 4.24943 6.59744 4.26764 6.88811L4.80097 15.396C4.8185 15.6756 5.05331 15.8907 5.33278 15.8907C5.64165 15.8907 5.88456 15.6335 5.86561 15.3307Z" fill="#999999"/>
|
||||
<path d="M7.99989 6.32812C7.70534 6.32812 7.46655 6.56423 7.46655 6.85547V15.3633C7.46655 15.6545 7.70534 15.8906 7.99989 15.8906C8.29443 15.8906 8.53322 15.6545 8.53322 15.3633V6.85547C8.53322 6.56423 8.29443 6.32812 7.99989 6.32812Z" fill="#999999"/>
|
||||
<path d="M11.233 6.32915C10.9396 6.31112 10.6859 6.53215 10.6677 6.82285L10.1343 15.3307C10.1162 15.6213 10.3397 15.8716 10.6337 15.8896C10.9278 15.9076 11.1808 15.6865 11.199 15.3959L11.7323 6.8881C11.7505 6.5974 11.527 6.34715 11.233 6.32915Z" fill="#999999"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -20,15 +20,22 @@ class DialogTextfieldDropdown extends StatefulWidget {
|
||||
|
||||
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
bool _isOpen = false;
|
||||
late OverlayEntry _overlayEntry;
|
||||
OverlayEntry? _overlayEntry;
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
late List<String> _filteredItems; // Filtered items list
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
List<String> _filteredItems = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller.text = widget.initialValue ?? 'Select Tag';
|
||||
_filteredItems = List.from(widget.items); // Initialize filtered items
|
||||
_controller.text = widget.initialValue ?? '';
|
||||
_filteredItems = List.from(widget.items);
|
||||
|
||||
_focusNode.addListener(() {
|
||||
if (!_focusNode.hasFocus) {
|
||||
_closeDropdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _toggleDropdown() {
|
||||
@ -41,14 +48,17 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
|
||||
void _openDropdown() {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry);
|
||||
Overlay.of(context).insert(_overlayEntry!);
|
||||
_isOpen = true;
|
||||
}
|
||||
|
||||
void _closeDropdown() {
|
||||
_overlayEntry.remove();
|
||||
if (_isOpen && _overlayEntry != null) {
|
||||
_overlayEntry!.remove();
|
||||
_overlayEntry = null;
|
||||
_isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() {
|
||||
final renderBox = context.findRenderObject() as RenderBox;
|
||||
@ -58,9 +68,7 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
return OverlayEntry(
|
||||
builder: (context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_closeDropdown();
|
||||
},
|
||||
onTap: _closeDropdown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Stack(
|
||||
children: [
|
||||
@ -72,14 +80,15 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
elevation: 4.0,
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 200.0,
|
||||
),
|
||||
child: ListView.builder(
|
||||
constraints: const BoxConstraints(maxHeight: 200.0),
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setStateDropdown) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _filteredItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _filteredItems[index];
|
||||
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
@ -95,7 +104,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: ColorsManager.textPrimaryColor)),
|
||||
color: ColorsManager
|
||||
.textPrimaryColor)),
|
||||
onTap: () {
|
||||
_controller.text = item;
|
||||
widget.onSelected(item);
|
||||
@ -108,6 +118,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -122,7 +134,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: _toggleDropdown,
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||
decoration: BoxDecoration(
|
||||
@ -135,23 +148,26 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: _controller,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_filteredItems = widget.items
|
||||
.where((item) =>
|
||||
item.toLowerCase().contains(value.toLowerCase()))
|
||||
.toList(); // Filter items dynamically
|
||||
});
|
||||
focusNode: _focusNode,
|
||||
onFieldSubmitted: (value) {
|
||||
widget.onSelected(value);
|
||||
_closeDropdown();
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
widget.onSelected(_controller.text);
|
||||
_closeDropdown();
|
||||
},
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter or Select tag',
|
||||
hintText: 'Enter or Select a tag',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
GestureDetector(
|
||||
onTap: _toggleDropdown,
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -56,24 +56,6 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
// Checkbox with independent state management
|
||||
Checkbox(
|
||||
value: false,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {});
|
||||
},
|
||||
side: WidgetStateBorderSide.resolveWith((states) {
|
||||
return const BorderSide(color: ColorsManager.grayBorder);
|
||||
}),
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return ColorsManager.grayBorder;
|
||||
} else {
|
||||
return ColorsManager.checkBoxFillColor;
|
||||
}
|
||||
}),
|
||||
checkColor: ColorsManager.whiteColors,
|
||||
),
|
||||
// Expand/collapse icon, now wrapped in a GestureDetector for specific onTap
|
||||
if (widget.children != null && widget.children!.isNotEmpty)
|
||||
GestureDetector(
|
||||
@ -84,7 +66,9 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
_isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
|
||||
_isExpanded
|
||||
? Icons.keyboard_arrow_down
|
||||
: Icons.keyboard_arrow_right,
|
||||
color: ColorsManager.lightGrayColor,
|
||||
size: 16.0, // Adjusted size for better alignment
|
||||
),
|
||||
@ -101,8 +85,10 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
||||
_capitalizeFirstLetter(widget.title),
|
||||
style: TextStyle(
|
||||
color: widget.isSelected
|
||||
? ColorsManager.blackColor // Change color to black when selected
|
||||
: ColorsManager.lightGrayColor, // Gray when not selected
|
||||
? ColorsManager
|
||||
.blackColor // Change color to black when selected
|
||||
: ColorsManager
|
||||
.lightGrayColor, // Gray when not selected
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
@ -111,7 +97,9 @@ class CustomExpansionTileState extends State<CustomExpansionTile> {
|
||||
],
|
||||
),
|
||||
// The expanded section (children) that shows when the tile is expanded
|
||||
if (_isExpanded && widget.children != null && widget.children!.isNotEmpty)
|
||||
if (_isExpanded &&
|
||||
widget.children != null &&
|
||||
widget.children!.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 48.0), // Indented children
|
||||
child: Column(
|
||||
|
@ -3,18 +3,33 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class CustomSearchBar extends StatelessWidget {
|
||||
class CustomSearchBar extends StatefulWidget {
|
||||
final TextEditingController? controller;
|
||||
final String hintText;
|
||||
final String? searchQuery;
|
||||
final Function(String)? onSearchChanged; // Callback for search input changes
|
||||
|
||||
const CustomSearchBar({
|
||||
super.key,
|
||||
this.controller,
|
||||
this.searchQuery = '',
|
||||
this.hintText = 'Search',
|
||||
this.onSearchChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CustomSearchBar> createState() => _CustomSearchBarState();
|
||||
}
|
||||
|
||||
class _CustomSearchBarState extends State<CustomSearchBar> {
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.controller != null) {
|
||||
widget.controller!.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@ -36,16 +51,17 @@ class CustomSearchBar extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
child: TextFormField(
|
||||
controller: widget.controller,
|
||||
initialValue: widget.searchQuery,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
),
|
||||
onChanged: onSearchChanged, // Call the callback on text change
|
||||
onChanged: widget.onSearchChanged, // Call the callback on text change
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: ColorsManager.textFieldGreyColor,
|
||||
hintText: hintText,
|
||||
hintText: widget.hintText,
|
||||
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 12,
|
||||
|
@ -1,25 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
|
||||
class SpacesSideTree extends StatefulWidget {
|
||||
final List<CommunityModel> communities;
|
||||
final String? selectedSpaceUuid;
|
||||
const SpacesSideTree({
|
||||
super.key,
|
||||
required this.communities,
|
||||
this.selectedSpaceUuid,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SpacesSideTree> createState() => _SpacesSideTreeState();
|
||||
}
|
||||
|
||||
class _SpacesSideTreeState extends State<SpacesSideTree> {
|
||||
String _searchQuery = '';
|
||||
String? _selectedSpaceUuid;
|
||||
String? _selectedId;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.da
|
||||
import 'package:syncrow_web/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/app_routes.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
import 'package:syncrow_web/utils/theme/theme.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
@ -33,9 +34,8 @@ Future<void> main() async {
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
MyApp({
|
||||
super.key,
|
||||
});
|
||||
|
||||
MyApp({super.key});
|
||||
|
||||
final GoRouter _router = GoRouter(
|
||||
initialLocation: RoutesConst.auth,
|
||||
@ -78,6 +78,8 @@ class MyApp extends StatelessWidget {
|
||||
PointerDeviceKind.unknown,
|
||||
},
|
||||
),
|
||||
key: NavigationService.navigatorKey,
|
||||
// scaffoldMessengerKey: NavigationService.snackbarKey,
|
||||
theme: myTheme,
|
||||
routerConfig: _router,
|
||||
));
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
@ -30,8 +31,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
Future<void> _onFetchTableData(
|
||||
FetchTableData event, Emitter<AccessState> emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
emit(AccessLoaded());
|
||||
data = await AccessMangApi().fetchVisitorPassword();
|
||||
data = await AccessMangApi().fetchVisitorPassword(projectUuid);
|
||||
filteredData = data;
|
||||
updateTabsCount();
|
||||
emit(TableLoaded(data));
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_table.dart';
|
||||
|
@ -9,9 +9,13 @@ import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/services/auth_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
@ -31,8 +35,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
|
||||
////////////////////////////// forget password //////////////////////////////////
|
||||
final TextEditingController forgetEmailController = TextEditingController();
|
||||
final TextEditingController forgetPasswordController =
|
||||
TextEditingController();
|
||||
final TextEditingController forgetPasswordController = TextEditingController();
|
||||
final TextEditingController forgetOtp = TextEditingController();
|
||||
final forgetFormKey = GlobalKey<FormState>();
|
||||
final forgetEmailKey = GlobalKey<FormState>();
|
||||
@ -49,8 +52,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
return;
|
||||
}
|
||||
_remainingTime = 1;
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
try {
|
||||
forgetEmailValidate = '';
|
||||
_remainingTime = (await AuthenticationAPI.sendOtp(
|
||||
@ -87,8 +89,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
_timer?.cancel();
|
||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||
} else {
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -98,8 +99,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||
}
|
||||
|
||||
Future<void> changePassword(
|
||||
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
Future<void> changePassword(ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
emit(LoadingForgetState());
|
||||
try {
|
||||
var response = await AuthenticationAPI.verifyOtp(
|
||||
@ -115,8 +115,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage =
|
||||
errorData['error']['message'] ?? 'something went wrong';
|
||||
String errorMessage = errorData['error']['message'] ?? 'something went wrong';
|
||||
validate = errorMessage;
|
||||
emit(AuthInitialState());
|
||||
}
|
||||
@ -130,9 +129,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||
emit(TimerState(
|
||||
isButtonEnabled: event.isButtonEnabled,
|
||||
remainingTime: event.remainingTime));
|
||||
emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
|
||||
}
|
||||
|
||||
///////////////////////////////////// login /////////////////////////////////////
|
||||
@ -180,18 +177,15 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (token.accessTokenIsNotEmpty) {
|
||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||
await storage.write(
|
||||
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
const FlutterSecureStorage().write(
|
||||
key: UserModel.userUuidKey,
|
||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||
user = UserModel.fromToken(token);
|
||||
loginEmailController.clear();
|
||||
loginPasswordController.clear();
|
||||
debugPrint("token " + token.accessToken);
|
||||
emit(LoginSuccess());
|
||||
} else {
|
||||
emit(const LoginFailure(error: 'Something went wrong'));
|
||||
@ -342,14 +336,12 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
static Future<String> getTokenAndValidate() async {
|
||||
try {
|
||||
const storage = FlutterSecureStorage();
|
||||
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
|
||||
StringsManager.firstLaunch) ??
|
||||
true;
|
||||
final firstLaunch =
|
||||
await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
||||
if (firstLaunch) {
|
||||
storage.deleteAll();
|
||||
}
|
||||
await SharedPreferencesHelper.saveBoolToSP(
|
||||
StringsManager.firstLaunch, false);
|
||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||
if (value.isEmpty) {
|
||||
return 'Token not found';
|
||||
@ -402,9 +394,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final String formattedTime = [
|
||||
if (days > 0) '${days}d', // Append 'd' for days
|
||||
if (days > 0 || hours > 0)
|
||||
hours
|
||||
.toString()
|
||||
.padLeft(2, '0'), // Show hours if there are days or hours
|
||||
hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
|
||||
minutes.toString().padLeft(2, '0'),
|
||||
seconds.toString().padLeft(2, '0'),
|
||||
].join(':');
|
||||
@ -442,8 +432,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
emit(LoginInitial());
|
||||
}
|
||||
|
||||
static logout() {
|
||||
const storage = FlutterSecureStorage();
|
||||
static Future<void> logout(BuildContext context) async {
|
||||
final storage = FlutterSecureStorage();
|
||||
ProjectManager.clearProjectUUID();
|
||||
context.read<SpaceTreeBloc>().add(ClearAllData());
|
||||
storage.deleteAll();
|
||||
}
|
||||
}
|
||||
|
27
lib/pages/auth/model/project_model.dart
Normal file
27
lib/pages/auth/model/project_model.dart
Normal file
@ -0,0 +1,27 @@
|
||||
class Project {
|
||||
final String uuid;
|
||||
final String name;
|
||||
final String description;
|
||||
|
||||
const Project({
|
||||
required this.uuid,
|
||||
required this.name,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
factory Project.fromJson(Map<String, dynamic> json) {
|
||||
return Project(
|
||||
uuid: json['uuid'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'uuid': uuid,
|
||||
'name': name,
|
||||
'description': description,
|
||||
};
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import 'package:syncrow_web/pages/auth/model/project_model.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||
|
||||
class UserModel {
|
||||
@ -13,6 +14,7 @@ class UserModel {
|
||||
final bool? hasAcceptedWebAgreement;
|
||||
final DateTime? webAgreementAcceptedAt;
|
||||
final UserRole? role;
|
||||
final Project? project;
|
||||
|
||||
UserModel({
|
||||
required this.uuid,
|
||||
@ -26,6 +28,7 @@ class UserModel {
|
||||
required this.hasAcceptedWebAgreement,
|
||||
required this.webAgreementAcceptedAt,
|
||||
required this.role,
|
||||
required this.project,
|
||||
});
|
||||
|
||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||
@ -43,6 +46,8 @@ class UserModel {
|
||||
? DateTime.parse(json['webAgreementAcceptedAt'])
|
||||
: null,
|
||||
role: json['role'] != null ? UserRole.fromJson(json['role']) : null,
|
||||
project:
|
||||
json['project'] != null ? Project.fromJson(json['project']) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -64,6 +69,7 @@ class UserModel {
|
||||
phoneNumber: null,
|
||||
isEmailVerified: null,
|
||||
isAgreementAccepted: null,
|
||||
project: null
|
||||
);
|
||||
}
|
||||
|
||||
|
19
lib/pages/common/bloc/project_manager.dart
Normal file
19
lib/pages/common/bloc/project_manager.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
|
||||
class ProjectManager {
|
||||
static Future<String?> getProjectUUID() async {
|
||||
final projectUuid = await SharedPreferencesHelper.readStringFromSP(
|
||||
StringsManager.projectKey);
|
||||
return projectUuid.isNotEmpty ? projectUuid : null;
|
||||
}
|
||||
|
||||
static Future<void> setProjectUUID(String newUUID) async {
|
||||
await SharedPreferencesHelper.saveStringToSP(
|
||||
StringsManager.projectKey, newUUID);
|
||||
}
|
||||
|
||||
static Future<void> clearProjectUUID() async {
|
||||
await SharedPreferencesHelper.removeValueFromSP(StringsManager.projectKey);
|
||||
}
|
||||
}
|
@ -1,14 +1,19 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
|
||||
part 'device_managment_event.dart';
|
||||
part 'device_managment_state.dart';
|
||||
|
||||
class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
class DeviceManagementBloc
|
||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
int _selectedIndex = 0;
|
||||
List<AllDevicesModel> _devices = [];
|
||||
int _onlineCount = 0;
|
||||
@ -31,19 +36,25 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
on<UpdateSelection>(_onUpdateSelection);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevices(FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onFetchDevices(
|
||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
emit(DeviceManagementLoading());
|
||||
try {
|
||||
List<AllDevicesModel> devices = [];
|
||||
_devices.clear();
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||
devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
devices = await DevicesManagementApi()
|
||||
.fetchDevices('', '', projectUuid );
|
||||
} else {
|
||||
for (var community in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||
for (var space in spacesList) {
|
||||
devices.addAll(await DevicesManagementApi().fetchDevices(community, space));
|
||||
devices.addAll(await DevicesManagementApi().fetchDevices(
|
||||
community, space, projectUuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,7 +77,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
}
|
||||
}
|
||||
|
||||
void _onFilterDevices(FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
void _onFilterDevices(
|
||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
if (_devices.isNotEmpty) {
|
||||
_filteredDevices = List.from(_devices.where((device) {
|
||||
switch (event.filter) {
|
||||
@ -97,7 +109,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onResetFilters(
|
||||
ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
currentProductName = '';
|
||||
_selectedDevices.clear();
|
||||
_filteredDevices = List.from(_devices);
|
||||
@ -113,7 +126,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
));
|
||||
}
|
||||
|
||||
void _onResetSelectedDevices(ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onResetSelectedDevices(
|
||||
ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedDevices.clear();
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
@ -139,12 +153,14 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
}
|
||||
}
|
||||
|
||||
void _onSelectedFilterChanged(SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectedFilterChanged(
|
||||
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedIndex = event.selectedIndex;
|
||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||
}
|
||||
|
||||
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectDevice(
|
||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
final selectedUuid = event.selectedDevice.uuid;
|
||||
|
||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||
@ -155,7 +171,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
|
||||
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
||||
|
||||
bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
bool isControlButtonEnabled =
|
||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
emit(DeviceManagementLoaded(
|
||||
@ -164,7 +181,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
} else if (state is DeviceManagementFiltered) {
|
||||
@ -174,13 +192,15 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateSelection(UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
void _onUpdateSelection(
|
||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
List<AllDevicesModel> selectedDevices = [];
|
||||
List<AllDevicesModel> devicesToSelectFrom = [];
|
||||
|
||||
@ -223,7 +243,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
|
||||
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
|
||||
if (selectedDevices.length > 1) {
|
||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||
final productTypes =
|
||||
selectedDevices.map((device) => device.productType).toSet();
|
||||
return productTypes.length == 1;
|
||||
} else if (selectedDevices.length == 1) {
|
||||
return true;
|
||||
@ -234,8 +255,10 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
void _calculateDeviceCounts() {
|
||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||
_lowBatteryCount =
|
||||
_devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length;
|
||||
_lowBatteryCount = _devices
|
||||
.where((device) =>
|
||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
||||
.length;
|
||||
}
|
||||
|
||||
String _getFilterFromIndex(int index) {
|
||||
@ -251,7 +274,8 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
}
|
||||
}
|
||||
|
||||
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSearchDevices(
|
||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
if ((event.community == null || event.community!.isEmpty) &&
|
||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||
(event.productName == null || event.productName!.isEmpty)) {
|
||||
@ -280,22 +304,33 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
|
||||
final filteredDevices = devicesToSearch.where((device) {
|
||||
final matchesCommunity = event.community == null ||
|
||||
event.community!.isEmpty ||
|
||||
(device.community?.name?.toLowerCase().contains(event.community!.toLowerCase()) ??
|
||||
(device.community?.name
|
||||
?.toLowerCase()
|
||||
.contains(event.community!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesUnit = event.unitName == null ||
|
||||
event.unitName!.isEmpty ||
|
||||
(device.spaces != null &&
|
||||
device.spaces!.isNotEmpty &&
|
||||
device.spaces![0].spaceName!.toLowerCase().contains(event.unitName!.toLowerCase()));
|
||||
device.spaces![0].spaceName!
|
||||
.toLowerCase()
|
||||
.contains(event.unitName!.toLowerCase()));
|
||||
final matchesProductName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.name?.toLowerCase().contains(event.productName!.toLowerCase()) ?? false);
|
||||
(device.name
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesDeviceName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.categoryName?.toLowerCase().contains(event.productName!.toLowerCase()) ??
|
||||
(device.categoryName
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
|
||||
return matchesCommunity && matchesUnit && (matchesProductName || matchesDeviceName);
|
||||
return matchesCommunity &&
|
||||
matchesUnit &&
|
||||
(matchesProductName || matchesDeviceName);
|
||||
}).toList();
|
||||
|
||||
emit(DeviceManagementFiltered(
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
@ -42,6 +43,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||
},
|
||||
child: Text(
|
||||
'Devices',
|
||||
|
@ -2,16 +2,19 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/services/home_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
// final Graph graph = Graph()..isTree = true;
|
||||
@ -48,9 +51,13 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
|
||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
user = await HomeApi().fetchUserInfo(uuid);
|
||||
|
||||
if (user != null && user!.project != null) {
|
||||
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
||||
}
|
||||
add(FetchTermEvent());
|
||||
add(FetchPolicyEvent());
|
||||
|
||||
@ -81,12 +88,10 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future _confirmUserAgreement(
|
||||
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
Future _confirmUserAgreement(ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||
emit(PolicyAgreement());
|
||||
} catch (e) {
|
||||
@ -110,6 +115,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.accessIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
context.go(RoutesConst.accessManagementPage);
|
||||
},
|
||||
color: null,
|
||||
@ -119,6 +125,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.spaseManagementIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
context.go(RoutesConst.spacesManagementPage);
|
||||
},
|
||||
color: ColorsManager.primaryColor,
|
||||
@ -128,6 +135,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.devicesIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
BlocProvider.of<RoutineBloc>(context)
|
||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||
context.go(RoutesConst.deviceManagementPage);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@ -162,7 +164,7 @@ class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
AuthBloc.logout(context);
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
|
@ -219,6 +219,9 @@ class UserSpaceModel {
|
||||
final double x;
|
||||
final double y;
|
||||
final String icon;
|
||||
final String communityUuid;
|
||||
|
||||
//communityUuid
|
||||
|
||||
UserSpaceModel({
|
||||
required this.uuid,
|
||||
@ -231,6 +234,7 @@ class UserSpaceModel {
|
||||
required this.x,
|
||||
required this.y,
|
||||
required this.icon,
|
||||
required this.communityUuid,
|
||||
});
|
||||
|
||||
/// Create a [UserSpaceModel] from JSON data
|
||||
@ -246,7 +250,7 @@ class UserSpaceModel {
|
||||
x: (json['x'] as num).toDouble(),
|
||||
y: (json['y'] as num).toDouble(),
|
||||
icon: json['icon'] as String,
|
||||
);
|
||||
communityUuid: json['communityUuid'] as String);
|
||||
}
|
||||
|
||||
/// Convert the [UserSpaceModel] to JSON
|
||||
@ -262,6 +266,7 @@ class UserSpaceModel {
|
||||
'x': x,
|
||||
'y': y,
|
||||
'icon': icon,
|
||||
'communityUuid': communityUuid
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
|
||||
@ -7,11 +9,14 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialo
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||
import 'package:syncrow_web/services/user_permission.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
|
||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
UsersBloc() : super(UsersInitial()) {
|
||||
@ -61,8 +66,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
void isCompleteSpacesFun(
|
||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
|
||||
isCompleteSpaces = spaceBloc.state.selectedCommunities.isNotEmpty;
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
@ -74,7 +81,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
|
||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||
String communityUuid) async {
|
||||
return await CommunitySpaceManagementApi().getSpaceHierarchy(communityUuid);
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
return await CommunitySpaceManagementApi()
|
||||
.getSpaceHierarchy(communityUuid, projectUuid);
|
||||
}
|
||||
|
||||
List<TreeNode> updatedCommunities = [];
|
||||
@ -84,8 +94,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
List<CommunityModel> communities =
|
||||
await CommunitySpaceManagementApi().fetchCommunities();
|
||||
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
||||
communityIds = communities.map((community) => community.uuid).toList();
|
||||
updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
@ -328,10 +340,14 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
|
||||
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
// List<String> selectedIds =
|
||||
// getSelectedIds(updatedCommunities).where((id) => !communityIds.contains(id)).toList();
|
||||
|
||||
List<String> selectedSpacesId = getSelectedSpacesIds();
|
||||
// List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
|
||||
bool res = await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
@ -340,8 +356,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
);
|
||||
spaceUuids: selectedSpacesId,
|
||||
projectUuid: projectUuid);
|
||||
|
||||
if (res) {
|
||||
showCustomDialog(
|
||||
@ -370,12 +386,21 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getSelectedSpacesIds() {
|
||||
List<String> selectedSpacesId = [];
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
for (var community in spaceBloc.state.selectedCommunities) {
|
||||
selectedSpacesId
|
||||
.addAll(spaceBloc.state.selectedCommunityAndSpaces[community] ?? []);
|
||||
}
|
||||
return selectedSpacesId;
|
||||
}
|
||||
|
||||
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
bool res = await UserPermissionApi().editInviteUser(
|
||||
userId: event.userId,
|
||||
@ -384,8 +409,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
);
|
||||
spaceUuids: getSelectedSpacesIds(),
|
||||
projectUuid: projectUuid);
|
||||
if (res == true) {
|
||||
showCustomDialog(
|
||||
barrierDismissible: false,
|
||||
@ -490,8 +515,13 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
emit(UsersLoadingState());
|
||||
|
||||
try {
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
if (event.uuid?.isNotEmpty ?? false) {
|
||||
final res = await UserPermissionApi().fetchUserById(event.uuid);
|
||||
final res =
|
||||
await UserPermissionApi().fetchUserById(event.uuid, projectUuid);
|
||||
|
||||
if (res != null) {
|
||||
// Populate the text controllers
|
||||
@ -501,13 +531,20 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
phoneController.text = res.phoneNumber ?? '';
|
||||
jobTitleController.text = res.jobTitle ?? '';
|
||||
res.roleType;
|
||||
if (updatedCommunities.isNotEmpty) {
|
||||
// Create a list of UUIDs to mark
|
||||
final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
||||
// Print all IDs and mark nodes in updatedCommunities
|
||||
debugPrint('Printing and marking nodes in updatedCommunities:');
|
||||
_printAndMarkNodes(updatedCommunities, uuidsToMark);
|
||||
}
|
||||
res.spaces.map((space) {
|
||||
selectedIds.add(space.uuid);
|
||||
CommunityModel community = spaceBloc.state.communityList
|
||||
.firstWhere((item) => item.uuid == space.communityUuid);
|
||||
spaceBloc.add(OnSpaceSelected(community, space.uuid, []));
|
||||
}).toList();
|
||||
|
||||
// if (updatedCommunities.isNotEmpty) {
|
||||
// // Create a list of UUIDs to mark
|
||||
// final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
||||
// // Print all IDs and mark nodes in updatedCommunities
|
||||
// debugPrint('Printing and marking nodes in updatedCommunities:');
|
||||
// _printAndMarkNodes(updatedCommunities, uuidsToMark);
|
||||
// }
|
||||
final roleId = roles
|
||||
.firstWhere((element) =>
|
||||
element.type ==
|
||||
@ -600,4 +637,16 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
emailController.dispose();
|
||||
firstNameController.dispose();
|
||||
lastNameController.dispose();
|
||||
emailController.dispose();
|
||||
phoneController.dispose();
|
||||
jobTitleController.dispose();
|
||||
roleSearchController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) => UsersBloc()
|
||||
..add(const LoadCommunityAndSpacesEvent())
|
||||
// ..add(const LoadCommunityAndSpacesEvent())
|
||||
..add(const RoleEvent()),
|
||||
child: BlocConsumer<UsersBloc, UsersState>(
|
||||
listener: (context, state) {},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
@ -25,13 +26,12 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) => UsersBloc()
|
||||
..add(const LoadCommunityAndSpacesEvent())
|
||||
// ..add(const LoadCommunityAndSpacesEvent())
|
||||
..add(const RoleEvent())
|
||||
..add(GetUserByIdEvent(uuid: widget.userId)),
|
||||
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
||||
if (state is SpacesLoadedState) {
|
||||
BlocProvider.of<UsersBloc>(context)
|
||||
.add(GetUserByIdEvent(uuid: widget.userId));
|
||||
BlocProvider.of<UsersBloc>(context).add(GetUserByIdEvent(uuid: widget.userId));
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||
@ -39,8 +39,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: 900,
|
||||
child: Column(
|
||||
children: [
|
||||
@ -69,8 +68,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
children: [
|
||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||
_buildStep3Indicator(
|
||||
3, "Role & Permissions", _blocRole),
|
||||
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -118,15 +116,13 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
if (currentStep == 2) {
|
||||
_blocRole
|
||||
.add(CheckStepStatus(isEditUser: true));
|
||||
_blocRole.add(CheckStepStatus(isEditUser: true));
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole.add(const CheckSpacesStepStatus());
|
||||
}
|
||||
} else {
|
||||
_blocRole.add(EditInviteUsers(
|
||||
context: context,
|
||||
userId: widget.userId!));
|
||||
_blocRole
|
||||
.add(EditInviteUsers(context: context, userId: widget.userId!));
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -135,8 +131,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
style: TextStyle(
|
||||
color: (_blocRole.isCompleteSpaces == false ||
|
||||
_blocRole.isCompleteBasics == false ||
|
||||
_blocRole.isCompleteRolePermissions ==
|
||||
false) &&
|
||||
_blocRole.isCompleteRolePermissions == false) &&
|
||||
currentStep == 3
|
||||
? ColorsManager.grayColor
|
||||
: ColorsManager.secondaryColor),
|
||||
@ -209,12 +204,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -272,12 +263,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -334,12 +321,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -1,14 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class SpacesAccessView extends StatelessWidget {
|
||||
final String? userId;
|
||||
@ -27,10 +22,8 @@ class SpacesAccessView extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'Spaces access',
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
color: Colors.black),
|
||||
style: context.textTheme.bodyLarge
|
||||
?.copyWith(fontWeight: FontWeight.w700, fontSize: 20, color: Colors.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 35,
|
||||
@ -42,77 +35,78 @@ class SpacesAccessView extends StatelessWidget {
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(20),
|
||||
topLeft: Radius.circular(20)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.grayBorder)),
|
||||
child: TextFormField(
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
// controller: _blocRole.firstNameController,
|
||||
onChanged: (value) {
|
||||
_blocRole.add(SearchAnode(
|
||||
nodes: _blocRole.updatedCommunities,
|
||||
searchTerm: value));
|
||||
},
|
||||
decoration: textBoxDecoration(radios: 20)!
|
||||
.copyWith(
|
||||
fillColor: Colors.white,
|
||||
suffixIcon: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 16),
|
||||
child: SvgPicture.asset(
|
||||
Assets.textFieldSearch,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
hintStyle: context.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: Container(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: TreeView(userId: userId))))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: SpaceTreeView(onSelect: () {}))
|
||||
// Expanded(
|
||||
// child: SizedBox(
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// flex: 2,
|
||||
// child: Container(
|
||||
// decoration: const BoxDecoration(
|
||||
// color: ColorsManager.circleRolesBackground,
|
||||
// borderRadius: BorderRadius.only(
|
||||
// topRight: Radius.circular(20),
|
||||
// topLeft: Radius.circular(20)),
|
||||
// ),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Container(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: const BorderRadius.all(
|
||||
// Radius.circular(20)),
|
||||
// border: Border.all(
|
||||
// color: ColorsManager.grayBorder)),
|
||||
// child: TextFormField(
|
||||
// style:
|
||||
// const TextStyle(color: Colors.black),
|
||||
// // controller: _blocRole.firstNameController,
|
||||
// onChanged: (value) {
|
||||
// _blocRole.add(SearchAnode(
|
||||
// nodes: _blocRole.updatedCommunities,
|
||||
// searchTerm: value));
|
||||
// },
|
||||
// decoration: textBoxDecoration(radios: 20)!
|
||||
// .copyWith(
|
||||
// fillColor: Colors.white,
|
||||
// suffixIcon: Padding(
|
||||
// padding:
|
||||
// const EdgeInsets.only(right: 16),
|
||||
// child: SvgPicture.asset(
|
||||
// Assets.textFieldSearch,
|
||||
// width: 24,
|
||||
// height: 24,
|
||||
// ),
|
||||
// ),
|
||||
// hintStyle: context.textTheme.bodyMedium
|
||||
// ?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// flex: 7,
|
||||
// child: Container(
|
||||
// color: ColorsManager.circleRolesBackground,
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Container(
|
||||
// color: ColorsManager.whiteColors,
|
||||
// child: TreeView(userId: userId))))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -1,10 +1,13 @@
|
||||
import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
||||
import 'package:syncrow_web/services/user_permission.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
|
||||
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
UserTableBloc() : super(TableInitial()) {
|
||||
@ -46,10 +49,12 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
||||
emit(UsersLoadingState());
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
roleTypes.clear();
|
||||
jobTitle.clear();
|
||||
createdBy.clear();
|
||||
users = await UserPermissionApi().fetchUsers();
|
||||
users = await UserPermissionApi().fetchUsers(projectUuid);
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.createdDate);
|
||||
final dateB = _parseDateTime(b.createdDate);
|
||||
@ -96,9 +101,11 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
Future<void> _changeUserStatus(
|
||||
ChangeUserStatus event, Emitter<UserTableState> emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
emit(UsersLoadingState());
|
||||
bool res = await UserPermissionApi().changeUserStatusById(
|
||||
event.userId, event.newStatus == "disabled" ? false : true);
|
||||
bool res = await UserPermissionApi().changeUserStatusById(event.userId,
|
||||
event.newStatus == "disabled" ? false : true, projectUuid);
|
||||
if (res == true) {
|
||||
add(const GetUsers());
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/vi
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/de_activate_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/name_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/user_table.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
@ -25,8 +27,7 @@ class UsersPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
Widget actionButton(
|
||||
{bool isActive = false, required String title, Function()? onTap}) {
|
||||
Widget actionButton({bool isActive = false, required String title, Function()? onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
@ -59,8 +60,7 @@ class UsersPage extends StatelessWidget {
|
||||
: ColorsManager.disabledPink.withOpacity(0.5),
|
||||
),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -84,15 +84,12 @@ class UsersPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget changeIconStatus(
|
||||
{required String userId,
|
||||
required String status,
|
||||
required Function()? onTap}) {
|
||||
{required String userId, required String status, required Function()? onTap}) {
|
||||
return Center(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||
padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||
child: SvgPicture.asset(
|
||||
status == "invited"
|
||||
? Assets.invitedIcon
|
||||
@ -160,6 +157,7 @@ class UsersPage extends StatelessWidget {
|
||||
const SizedBox(width: 20),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
@ -198,14 +196,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
context.read<UserTableBloc>().add(const SortUsersByNameAsc());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
context.read<UserTableBloc>().add(const SortUsersByNameDesc());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -214,9 +208,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.jobTitle)
|
||||
item: _blocRole.selectedJobTitles.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
@ -256,9 +249,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.roleTypes)
|
||||
item: _blocRole.selectedRoles.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 4,
|
||||
@ -278,8 +270,7 @@ class UsersPage extends StatelessWidget {
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
context.read<UserTableBloc>().add(
|
||||
FilterUsersByRoleEvent(
|
||||
context.read<UserTableBloc>().add(FilterUsersByRoleEvent(
|
||||
selectedRoles: selectedItems,
|
||||
sortOrder: _blocRole.currentSortRole));
|
||||
},
|
||||
@ -296,14 +287,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -312,9 +299,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.createdBy)
|
||||
item: _blocRole.selectedCreatedBy.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 1,
|
||||
@ -352,9 +338,8 @@ class UsersPage extends StatelessWidget {
|
||||
item: _blocRole.selectedStatuses.contains(item),
|
||||
};
|
||||
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 0,
|
||||
@ -391,14 +376,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrderDate,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -425,23 +406,17 @@ class UsersPage extends StatelessWidget {
|
||||
Text(user.createdTime ?? ''),
|
||||
Text(user.invitedBy),
|
||||
status(
|
||||
status: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status,
|
||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||
),
|
||||
changeIconStatus(
|
||||
status: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status,
|
||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||
userId: user.uuid,
|
||||
onTap: user.status != "invited"
|
||||
? () {
|
||||
context.read<UserTableBloc>().add(
|
||||
ChangeUserStatus(
|
||||
context.read<UserTableBloc>().add(ChangeUserStatus(
|
||||
userId: user.uuid,
|
||||
newStatus: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status));
|
||||
newStatus:
|
||||
user.isEnabled == false ? 'disabled' : user.status));
|
||||
}
|
||||
: null,
|
||||
),
|
||||
@ -452,12 +427,12 @@ class UsersPage extends StatelessWidget {
|
||||
isActive: true,
|
||||
title: "Edit",
|
||||
onTap: () {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return EditUserDialog(
|
||||
userId: user.uuid);
|
||||
return EditUserDialog(userId: user.uuid);
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
@ -478,13 +453,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return DeleteUserDialog(
|
||||
onTapDelete: () async {
|
||||
return DeleteUserDialog(onTapDelete: () async {
|
||||
try {
|
||||
_blocRole.add(DeleteUserEvent(
|
||||
user.uuid, context));
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2));
|
||||
_blocRole.add(DeleteUserEvent(user.uuid, context));
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@ -514,20 +486,14 @@ class UsersPage extends StatelessWidget {
|
||||
visiblePagesCount: 4,
|
||||
buttonRadius: 10,
|
||||
selectedButtonColor: ColorsManager.secondaryColor,
|
||||
buttonUnSelectedBorderColor:
|
||||
ColorsManager.grayBorder,
|
||||
lastPageIcon:
|
||||
const Icon(Icons.keyboard_double_arrow_right),
|
||||
firstPageIcon:
|
||||
const Icon(Icons.keyboard_double_arrow_left),
|
||||
totalPages: (_blocRole.totalUsersCount.length /
|
||||
_blocRole.itemsPerPage)
|
||||
.ceil(),
|
||||
buttonUnSelectedBorderColor: ColorsManager.grayBorder,
|
||||
lastPageIcon: const Icon(Icons.keyboard_double_arrow_right),
|
||||
firstPageIcon: const Icon(Icons.keyboard_double_arrow_left),
|
||||
totalPages:
|
||||
(_blocRole.totalUsersCount.length / _blocRole.itemsPerPage).ceil(),
|
||||
currentPage: _blocRole.currentPage,
|
||||
onPageChanged: (int pageNumber) {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(ChangePage(pageNumber));
|
||||
context.read<UserTableBloc>().add(ChangePage(pageNumber));
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
||||
|
@ -3,6 +3,8 @@ import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
@ -10,17 +12,22 @@ import 'package:syncrow_web/pages/routines/models/delay/delay_fucntions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_details_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
part 'routine_event.dart';
|
||||
part 'routine_state.dart';
|
||||
|
||||
String spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
String communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
// String spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
// String communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
|
||||
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
RoutineBloc() : super(const RoutineState()) {
|
||||
@ -54,11 +61,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
TriggerSwitchTabsEvent event,
|
||||
Emitter<RoutineState> emit,
|
||||
) {
|
||||
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
emit(state.copyWith(
|
||||
routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
add(ResetRoutineState());
|
||||
if (event.isRoutineTab) {
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(const LoadScenes());
|
||||
add(const LoadAutomation());
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +88,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||
|
||||
// Find the index of the item in teh current itemsList
|
||||
int index =
|
||||
updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
int index = updatedIfItems.indexWhere(
|
||||
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
// Replace the map if the index is valid
|
||||
if (index != -1) {
|
||||
updatedIfItems[index] = event.item;
|
||||
@ -90,18 +98,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
|
||||
if (event.isTabToRun) {
|
||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
} else {
|
||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||
}
|
||||
}
|
||||
|
||||
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||
void _onAddToThenContainer(
|
||||
AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||
final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||
|
||||
// Find the index of the item in teh current itemsList
|
||||
int index =
|
||||
currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
int index = currentItems.indexWhere(
|
||||
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
// Replace the map if the index is valid
|
||||
if (index != -1) {
|
||||
currentItems[index] = event.item;
|
||||
@ -112,22 +123,26 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(thenItems: currentItems));
|
||||
}
|
||||
|
||||
void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||
void _onAddFunctionsToRoutine(
|
||||
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||
try {
|
||||
if (event.functions.isEmpty) return;
|
||||
|
||||
List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
|
||||
List<DeviceFunctionData> selectedFunction =
|
||||
List<DeviceFunctionData>.from(event.functions);
|
||||
|
||||
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||
List<DeviceFunctionData> currentFunctions =
|
||||
List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
||||
List<DeviceFunctionData>.from(
|
||||
currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
||||
|
||||
List<String> functionCode = [];
|
||||
for (int i = 0; i < selectedFunction.length; i++) {
|
||||
for (int j = 0; j < currentFunctions.length; j++) {
|
||||
if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) {
|
||||
if (selectedFunction[i].functionCode ==
|
||||
currentFunctions[j].functionCode) {
|
||||
currentFunctions[j] = selectedFunction[i];
|
||||
if (!functionCode.contains(currentFunctions[j].functionCode)) {
|
||||
functionCode.add(currentFunctions[j].functionCode);
|
||||
@ -137,13 +152,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
|
||||
for (int i = 0; i < functionCode.length; i++) {
|
||||
selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]);
|
||||
selectedFunction
|
||||
.removeWhere((code) => code.functionCode == functionCode[i]);
|
||||
}
|
||||
|
||||
currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)
|
||||
..addAll(selectedFunction);
|
||||
currentSelectedFunctions[event.uniqueCustomId] =
|
||||
List.from(currentFunctions)..addAll(selectedFunction);
|
||||
} else {
|
||||
currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
|
||||
currentSelectedFunctions[event.uniqueCustomId] =
|
||||
List.from(event.functions);
|
||||
}
|
||||
|
||||
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
||||
@ -152,18 +169,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onLoadScenes(
|
||||
LoadScenes event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
spaceId = event.spaceId;
|
||||
communityId = event.communityId;
|
||||
|
||||
List<ScenesModel> scenes = [];
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
if (communityId.isNotEmpty && spaceId.isNotEmpty) {
|
||||
scenes = await SceneApi.getScenes(event.spaceId, event.communityId);
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
scenes.addAll(
|
||||
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||
}
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
scenes: scenes,
|
||||
isLoading: false,
|
||||
@ -174,18 +197,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
loadScenesErrorMessage: 'Failed to load scenes',
|
||||
errorMessage: '',
|
||||
loadAutomationErrorMessage: '',
|
||||
scenes: []));
|
||||
scenes: scenes));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onLoadAutomation(
|
||||
LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
List<ScenesModel> automations = [];
|
||||
|
||||
try {
|
||||
spaceId = event.spaceId;
|
||||
List<ScenesModel> automations = [];
|
||||
if (spaceId.isNotEmpty) {
|
||||
automations = await SceneApi.getAutomation(event.spaceId);
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
automations.addAll(await SceneApi.getAutomation(spaceId));
|
||||
}
|
||||
}
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
@ -197,18 +226,20 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
automations: []));
|
||||
automations: automations));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onSearchRoutines(
|
||||
SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
emit(state.copyWith(isLoading: false, errorMessage: null));
|
||||
emit(state.copyWith(searchText: event.query));
|
||||
}
|
||||
|
||||
FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onAddSelectedIcon(
|
||||
AddSelectedIcon event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(selectedIcon: event.icon));
|
||||
}
|
||||
|
||||
@ -222,7 +253,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
return actions.last['deviceId'] == 'delay';
|
||||
}
|
||||
|
||||
Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onCreateScene(
|
||||
CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
// Check if first action is delay
|
||||
// if (_isFirstActionDelay(state.thenItems)) {
|
||||
@ -235,7 +267,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
@ -280,8 +313,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
});
|
||||
}).toList();
|
||||
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
|
||||
final createSceneModel = CreateSceneModel(
|
||||
spaceUuid: spaceId,
|
||||
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||
iconId: state.selectedIcon ?? '',
|
||||
showInDevice: true,
|
||||
sceneName: state.routineName ?? '',
|
||||
@ -292,8 +328,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createScene(createSceneModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(const LoadScenes());
|
||||
add(const LoadAutomation());
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -308,7 +344,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onCreateAutomation(
|
||||
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
@ -329,7 +366,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
CustomSnackBar.redSnackBar('Cannot have delay as the last action');
|
||||
@ -404,9 +442,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
);
|
||||
});
|
||||
}).toList();
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
|
||||
final createAutomationModel = CreateAutomationModel(
|
||||
spaceUuid: spaceId,
|
||||
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||
automationName: state.routineName ?? '',
|
||||
decisionExpr: state.selectedAutomationOperator,
|
||||
effectiveTime: EffectiveTime(
|
||||
@ -421,8 +461,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation());
|
||||
add(const LoadScenes());
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -439,17 +479,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onRemoveDragCard(
|
||||
RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||
if (event.isFromThen) {
|
||||
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
final selectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
thenItems.removeAt(event.index);
|
||||
selectedFunctions.remove(event.key);
|
||||
emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions));
|
||||
emit(state.copyWith(
|
||||
thenItems: thenItems, selectedFunctions: selectedFunctions));
|
||||
} else {
|
||||
final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
final selectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
ifItems.removeAt(event.index);
|
||||
selectedFunctions.remove(event.key);
|
||||
@ -460,7 +504,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
isAutomation: false,
|
||||
isTabToRun: false));
|
||||
} else {
|
||||
emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||
emit(state.copyWith(
|
||||
ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -472,18 +517,23 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
));
|
||||
}
|
||||
|
||||
FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onEffectiveTimeEvent(
|
||||
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(effectiveTime: event.effectiveTime));
|
||||
}
|
||||
|
||||
FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onSetRoutineName(
|
||||
SetRoutineName event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
routineName: event.name,
|
||||
));
|
||||
}
|
||||
|
||||
(List<Map<String, dynamic>>, List<Map<String, dynamic>>, Map<String, List<DeviceFunctionData>>)
|
||||
_createCardData(
|
||||
(
|
||||
List<Map<String, dynamic>>,
|
||||
List<Map<String, dynamic>>,
|
||||
Map<String, List<DeviceFunctionData>>
|
||||
) _createCardData(
|
||||
List<RoutineAction> actions,
|
||||
List<RoutineCondition>? conditions,
|
||||
Map<String, List<DeviceFunctionData>> currentFunctions,
|
||||
@ -516,7 +566,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
'deviceId': condition.entityId,
|
||||
'title': matchingDevice.name ?? condition.entityId,
|
||||
'productType': condition.entityType,
|
||||
'imagePath': matchingDevice.getDefaultIcon(condition.entityType),
|
||||
'imagePath':
|
||||
matchingDevice.getDefaultIcon(condition.entityType),
|
||||
};
|
||||
|
||||
final functions = matchingDevice.functions;
|
||||
@ -552,8 +603,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final cardData = {
|
||||
'entityId': action.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'),
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
: (matchingDevice.name ?? 'Device'),
|
||||
'productType': action.productType,
|
||||
'imagePath': matchingDevice.getDefaultIcon(action.productType),
|
||||
};
|
||||
@ -596,7 +650,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
return (thenItems, ifItems, currentFunctions);
|
||||
}
|
||||
|
||||
Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onGetSceneDetails(
|
||||
GetSceneDetails event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
isLoading: true,
|
||||
@ -644,8 +699,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
if (!deviceCards.containsKey(deviceId)) {
|
||||
deviceCards[deviceId] = {
|
||||
'entityId': action.entityId,
|
||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay'
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId':
|
||||
action.type == 'automation' || action.actionExecutor == 'delay'
|
||||
? const Uuid().v4()
|
||||
: action.entityId,
|
||||
'title': action.actionExecutor == 'delay'
|
||||
@ -682,7 +739,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
),
|
||||
);
|
||||
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||
} else if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
} else if (action.executorProperty != null &&
|
||||
action.actionExecutor != 'delay') {
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
@ -754,7 +812,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onResetRoutineState(
|
||||
ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
ifItems: [],
|
||||
thenItems: [],
|
||||
@ -778,17 +837,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
createRoutineView: false));
|
||||
}
|
||||
|
||||
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _deleteScene(
|
||||
DeleteScene event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
if (state.isTabToRun) {
|
||||
SceneApi.deleteScene(unitUuid: spaceId, sceneId: state.sceneId ?? '');
|
||||
await SceneApi.deleteScene(
|
||||
unitUuid: spaceBloc.state.selectedSpaces[0],
|
||||
sceneId: state.sceneId ?? '');
|
||||
} else {
|
||||
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? '');
|
||||
await SceneApi.deleteAutomation(
|
||||
unitUuid: spaceBloc.state.selectedSpaces[0],
|
||||
automationId: state.automationId ?? '');
|
||||
}
|
||||
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(const LoadScenes());
|
||||
add(const LoadAutomation());
|
||||
add(ResetRoutineState());
|
||||
emit(state.copyWith(isLoading: false, createRoutineView: false));
|
||||
} catch (e) {
|
||||
@ -813,10 +879,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
// }
|
||||
// }
|
||||
|
||||
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _fetchDevices(
|
||||
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
List<AllDevicesModel> devices = [];
|
||||
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
devices.addAll(await DevicesManagementApi()
|
||||
.fetchDevices(communityId, spaceId, projectUuid));
|
||||
}
|
||||
}
|
||||
|
||||
emit(state.copyWith(isLoading: false, devices: devices));
|
||||
} catch (e) {
|
||||
@ -824,7 +904,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onUpdateScene(
|
||||
UpdateScene event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
// Check if first action is delay
|
||||
// if (_isFirstActionDelay(state.thenItems)) {
|
||||
@ -838,7 +919,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
@ -891,11 +973,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
final result =
|
||||
await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(const LoadScenes());
|
||||
add(const LoadAutomation());
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -910,7 +993,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onUpdateAutomation(UpdateAutomation event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onUpdateAutomation(
|
||||
UpdateAutomation event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
@ -1005,8 +1089,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
});
|
||||
}).toList();
|
||||
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
|
||||
final createAutomationModel = CreateAutomationModel(
|
||||
spaceUuid: spaceId,
|
||||
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||
automationName: state.routineName ?? '',
|
||||
decisionExpr: state.selectedAutomationOperator,
|
||||
effectiveTime: EffectiveTime(
|
||||
@ -1018,13 +1105,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result =
|
||||
await SceneApi.updateAutomation(createAutomationModel, state.automationId ?? '');
|
||||
final result = await SceneApi.updateAutomation(
|
||||
createAutomationModel, state.automationId ?? '');
|
||||
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation());
|
||||
add(LoadScenes());
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -1052,7 +1139,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
thenItems: [],
|
||||
));
|
||||
|
||||
final automationDetails = await SceneApi.getAutomationDetails(event.automationId);
|
||||
final automationDetails =
|
||||
await SceneApi.getAutomationDetails(event.automationId);
|
||||
|
||||
final Map<String, Map<String, dynamic>> deviceIfCards = {};
|
||||
final Map<String, Map<String, dynamic>> deviceThenCards = {};
|
||||
@ -1120,13 +1208,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
),
|
||||
);
|
||||
|
||||
final deviceId =
|
||||
action.actionExecutor == 'delay' ? '${action.entityId}_delay' : action.entityId;
|
||||
final deviceId = action.actionExecutor == 'delay'
|
||||
? '${action.entityId}_delay'
|
||||
: action.entityId;
|
||||
|
||||
if (!deviceThenCards.containsKey(deviceId)) {
|
||||
deviceThenCards[deviceId] = {
|
||||
'entityId': action.entityId,
|
||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
@ -1157,7 +1247,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
|
||||
if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
if (action.executorProperty != null &&
|
||||
action.actionExecutor != 'delay') {
|
||||
final functions = matchingDevice.functions;
|
||||
final functionCode = action.executorProperty!.functionCode;
|
||||
for (var function in functions) {
|
||||
@ -1199,10 +1290,14 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
final ifItems = deviceIfCards.values.where((card) => card['type'] == 'condition').toList();
|
||||
final ifItems = deviceIfCards.values
|
||||
.where((card) => card['type'] == 'condition')
|
||||
.toList();
|
||||
final thenItems = deviceThenCards.values
|
||||
.where((card) =>
|
||||
card['type'] == 'action' || card['type'] == 'automation' || card['type'] == 'scene')
|
||||
card['type'] == 'action' ||
|
||||
card['type'] == 'automation' ||
|
||||
card['type'] == 'scene')
|
||||
.toList();
|
||||
|
||||
emit(state.copyWith(
|
||||
|
@ -27,22 +27,24 @@ class AddToThenContainer extends RoutineEvent {
|
||||
}
|
||||
|
||||
class LoadScenes extends RoutineEvent {
|
||||
final String spaceId;
|
||||
final String communityId;
|
||||
// final String spaceId;
|
||||
// final String communityId;
|
||||
// final BuildContext context;
|
||||
|
||||
const LoadScenes(this.spaceId, this.communityId);
|
||||
const LoadScenes();
|
||||
|
||||
@override
|
||||
List<Object> get props => [spaceId, communityId];
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadAutomation extends RoutineEvent {
|
||||
final String spaceId;
|
||||
// final String spaceId;
|
||||
// final BuildContext context;
|
||||
|
||||
const LoadAutomation(this.spaceId);
|
||||
const LoadAutomation();
|
||||
|
||||
@override
|
||||
List<Object> get props => [spaceId];
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class AddFunctionToRoutine extends RoutineEvent {
|
||||
|
@ -7,7 +7,6 @@ import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_vie
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class RoutinesView extends StatefulWidget {
|
||||
const RoutinesView({super.key});
|
||||
@ -20,7 +19,7 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
// context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
@override
|
||||
@ -32,9 +31,12 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SpaceTreeView(
|
||||
onSelect: () {},
|
||||
Expanded(child: SpaceTreeView(
|
||||
onSelect: () {
|
||||
context.read<RoutineBloc>()
|
||||
..add(const LoadScenes())
|
||||
..add(const LoadAutomation());
|
||||
},
|
||||
)),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
@ -59,8 +61,8 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
),
|
||||
RoutineViewCard(
|
||||
onTap: () {
|
||||
if (context.read<SpaceTreeBloc>().selectedCommunityId.isNotEmpty &&
|
||||
context.read<SpaceTreeBloc>().selectedSpaceId.isNotEmpty) {
|
||||
if (context.read<SpaceTreeBloc>().state.selectedCommunities.length == 1 &&
|
||||
context.read<SpaceTreeBloc>().state.selectedSpaces.length == 1) {
|
||||
context.read<RoutineBloc>().add(
|
||||
(ResetRoutineState()),
|
||||
);
|
||||
@ -68,7 +70,18 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
} else {
|
||||
CustomSnackBar.redSnackBar('Please select a space');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.read<SpaceTreeBloc>().state.selectedSpaces.isEmpty
|
||||
? 'Please select a space'
|
||||
: 'Please select only one space to proceed'),
|
||||
),
|
||||
);
|
||||
// CustomSnackBar.redSnackBar(
|
||||
// context.read<SpaceTreeBloc>().state.selectedSpaces.isEmpty
|
||||
// ? 'Please select a space'
|
||||
// : 'Please select only one space to proceed');
|
||||
}
|
||||
},
|
||||
icon: Icons.add,
|
||||
|
@ -20,10 +20,6 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(LoadScenes(context.read<SpaceTreeBloc>().selectedSpaceId,
|
||||
context.read<SpaceTreeBloc>().selectedCommunityId))
|
||||
..add(LoadAutomation(context.read<SpaceTreeBloc>().selectedSpaceId));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -4,9 +4,20 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
|
||||
class RoutineDevices extends StatelessWidget {
|
||||
class RoutineDevices extends StatefulWidget {
|
||||
const RoutineDevices({super.key});
|
||||
|
||||
@override
|
||||
State<RoutineDevices> createState() => _RoutineDevicesState();
|
||||
}
|
||||
|
||||
class _RoutineDevicesState extends State<RoutineDevices> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class ScenesAndAutomations extends StatefulWidget {
|
||||
@ -19,9 +18,8 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(LoadScenes(context.read<SpaceTreeBloc>().selectedSpaceId,
|
||||
context.read<SpaceTreeBloc>().selectedCommunityId))
|
||||
..add(LoadAutomation(context.read<SpaceTreeBloc>().selectedSpaceId));
|
||||
..add(const LoadScenes())
|
||||
..add(const LoadAutomation());
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
@ -6,9 +7,6 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model
|
||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||
|
||||
class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
|
||||
SpaceTreeBloc() : super(const SpaceTreeState()) {
|
||||
on<InitialEvent>(_fetchSpaces);
|
||||
on<OnCommunityExpanded>(_onCommunityExpanded);
|
||||
@ -16,17 +14,49 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
on<OnCommunitySelected>(_onCommunitySelected);
|
||||
on<OnSpaceSelected>(_onSpaceSelected);
|
||||
on<SearchQueryEvent>(_onSearch);
|
||||
on<ClearAllData>(_clearAllData);
|
||||
on<ClearCachedData>(_clearCachedData);
|
||||
on<OnCommunityAdded>(_onCommunityAdded);
|
||||
on<OnCommunityUpdated>(_onCommunityUpdate);
|
||||
}
|
||||
|
||||
void _onCommunityUpdate(
|
||||
OnCommunityUpdated event,
|
||||
Emitter<SpaceTreeState> emit,
|
||||
) async {
|
||||
emit(SpaceTreeLoadingState());
|
||||
|
||||
try {
|
||||
final updatedCommunity = event.updatedCommunity;
|
||||
final updatedCommunities =
|
||||
List<CommunityModel>.from(state.communityList);
|
||||
|
||||
final index = updatedCommunities
|
||||
.indexWhere((community) => community.uuid == updatedCommunity.uuid);
|
||||
|
||||
if (index != -1) {
|
||||
updatedCommunities[index] = updatedCommunity;
|
||||
emit(state.copyWith(communitiesList: updatedCommunities));
|
||||
} else {
|
||||
emit(SpaceTreeErrorState('Community not found in the list.'));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SpaceTreeErrorState('Error updating community: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
|
||||
emit(SpaceTreeLoadingState());
|
||||
try {
|
||||
List<CommunityModel> communities = await CommunitySpaceManagementApi().fetchCommunities();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
List<CommunityModel> communities =
|
||||
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
||||
|
||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
List<SpaceModel> spaces =
|
||||
await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid);
|
||||
List<SpaceModel> spaces = await CommunitySpaceManagementApi()
|
||||
.getSpaceHierarchy(community.uuid, projectUuid);
|
||||
|
||||
return CommunityModel(
|
||||
uuid: community.uuid,
|
||||
@ -41,15 +71,27 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: []));
|
||||
communitiesList: updatedCommunities,
|
||||
expandedCommunity: [],
|
||||
expandedSpaces: []));
|
||||
} catch (e) {
|
||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
_onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||
void _onCommunityAdded(
|
||||
OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
|
||||
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
||||
updatedCommunities.add(event.newCommunity);
|
||||
|
||||
emit(state.copyWith(communitiesList: updatedCommunities));
|
||||
}
|
||||
|
||||
_onCommunityExpanded(
|
||||
OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
|
||||
List<String> updatedExpandedCommunityList =
|
||||
List.from(state.expandedCommunities);
|
||||
|
||||
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
||||
updatedExpandedCommunityList.remove(event.communityId);
|
||||
@ -81,13 +123,19 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
}
|
||||
}
|
||||
|
||||
_onCommunitySelected(OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
||||
_onCommunitySelected(
|
||||
OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedSelectedCommunities =
|
||||
List.from(state.selectedCommunities.toSet().toList());
|
||||
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
List<String> updatedSelectedSpaces =
|
||||
List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks =
|
||||
List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces =
|
||||
Map.from(state.selectedCommunityAndSpaces);
|
||||
List<String> selectedSpacesInCommunity =
|
||||
communityAndSpaces[event.communityId] ?? [];
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
|
||||
@ -95,14 +143,16 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
// Select the community and all its children
|
||||
updatedSelectedCommunities.add(event.communityId);
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
selectedSpacesInCommunity.addAll(childrenIds);
|
||||
} else {
|
||||
// Unselect the community and all its children
|
||||
updatedSelectedCommunities.remove(event.communityId);
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
selectedSpacesInCommunity.removeWhere(childrenIds.contains);
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
|
||||
communityAndSpaces[event.communityId] = selectedSpacesInCommunity;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities,
|
||||
@ -118,9 +168,15 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
try {
|
||||
List<String> updatedSelectedCommunities =
|
||||
List.from(state.selectedCommunities.toSet().toList());
|
||||
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
List<String> updatedSelectedSpaces =
|
||||
List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks =
|
||||
List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces =
|
||||
Map.from(state.selectedCommunityAndSpaces);
|
||||
|
||||
List<String> selectedSpacesInCommunity =
|
||||
communityAndSpaces[event.communityModel.uuid] ?? [];
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
bool isChildSelected = false;
|
||||
@ -135,14 +191,19 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
!updatedSoldChecks.contains(event.spaceId)) {
|
||||
// First click: Select the space and all its children
|
||||
updatedSelectedSpaces.add(event.spaceId);
|
||||
updatedSelectedCommunities.add(event.communityId);
|
||||
updatedSelectedCommunities.add(event.communityModel.uuid);
|
||||
selectedSpacesInCommunity.add(event.spaceId);
|
||||
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
selectedSpacesInCommunity.addAll(childrenIds);
|
||||
}
|
||||
|
||||
List<String> spaces = _getThePathToChild(event.communityId, event.spaceId);
|
||||
List<String> spaces =
|
||||
_getThePathToChild(event.communityModel.uuid, event.spaceId);
|
||||
for (String space in spaces) {
|
||||
if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) {
|
||||
if (!updatedSelectedSpaces.contains(space) &&
|
||||
!updatedSoldChecks.contains(space)) {
|
||||
updatedSoldChecks.add(space);
|
||||
}
|
||||
}
|
||||
@ -150,31 +211,48 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
childrenIds.isNotEmpty &&
|
||||
isChildSelected) {
|
||||
// Second click: Unselect space but keep children
|
||||
selectedSpacesInCommunity.remove(event.spaceId);
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
updatedSoldChecks.add(event.spaceId);
|
||||
} else {
|
||||
// Third click: Unselect space and all its children
|
||||
selectedSpacesInCommunity.remove(event.spaceId);
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
selectedSpacesInCommunity.removeWhere(childrenIds.contains);
|
||||
}
|
||||
updatedSoldChecks.remove(event.spaceId);
|
||||
|
||||
List<String> parents = _getThePathToChild(event.communityId, event.spaceId);
|
||||
if (!_parentSelected(parents, updatedSelectedSpaces)) {
|
||||
List<String> parents =
|
||||
_getThePathToChild(event.communityModel.uuid, event.spaceId)
|
||||
.toSet()
|
||||
.toList();
|
||||
|
||||
if (updatedSelectedSpaces.isEmpty) {
|
||||
updatedSoldChecks.removeWhere(parents.contains);
|
||||
}
|
||||
if (!_anySpacesSelectedInCommunity(
|
||||
event.communityId, updatedSelectedSpaces, updatedSoldChecks)) {
|
||||
updatedSelectedCommunities.remove(event.communityId);
|
||||
updatedSelectedCommunities.remove(event.communityModel.uuid);
|
||||
} else {
|
||||
// Check if any parent has selected children
|
||||
for (String space in parents) {
|
||||
if (!_noChildrenSelected(
|
||||
event.communityModel, space, updatedSelectedSpaces, parents)) {
|
||||
updatedSoldChecks.remove(space);
|
||||
}
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
|
||||
if (!_anySpacesSelectedInCommunity(
|
||||
event.communityModel, updatedSelectedSpaces, updatedSoldChecks)) {
|
||||
updatedSelectedCommunities.remove(event.communityModel.uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityModel.uuid] = selectedSpacesInCommunity;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities,
|
||||
selectedCommunities: updatedSelectedCommunities.toSet().toList(),
|
||||
selectedSpaces: updatedSelectedSpaces,
|
||||
soldCheck: updatedSoldChecks,
|
||||
selectedCommunityAndSpaces: communityAndSpaces));
|
||||
@ -184,12 +262,24 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
}
|
||||
}
|
||||
|
||||
_parentSelected(List<String> parents, List<String> selectedSpaces) {
|
||||
for (String space in parents) {
|
||||
if (selectedSpaces.contains(space)) {
|
||||
_noChildrenSelected(CommunityModel community, String spaceId,
|
||||
List<String> selectedSpaces, List<String> parents) {
|
||||
if (selectedSpaces.contains(spaceId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<SpaceModel> children = _getAllChildSpaces(community.spaces);
|
||||
for (var child in children) {
|
||||
if (spaceId == child.uuid) {
|
||||
List<String> ids = _getAllChildIds(child.children);
|
||||
for (var id in ids) {
|
||||
if (selectedSpaces.contains(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -200,16 +290,55 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
|
||||
// Filter communities and expand only those that match the query
|
||||
filteredCommunity = communities.where((community) {
|
||||
final containsQueryInCommunity =
|
||||
community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
|
||||
final containsQueryInSpaces =
|
||||
community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
||||
final containsQueryInCommunity = community.name
|
||||
.toLowerCase()
|
||||
.contains(event.searchQuery.toLowerCase());
|
||||
final containsQueryInSpaces = community.spaces.any(
|
||||
(space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
||||
|
||||
return containsQueryInCommunity || containsQueryInSpaces;
|
||||
}).toList();
|
||||
|
||||
emit(state.copyWith(
|
||||
filteredCommunity: filteredCommunity, isSearching: event.searchQuery.isNotEmpty));
|
||||
filteredCommunity: filteredCommunity,
|
||||
isSearching: event.searchQuery.isNotEmpty,
|
||||
searchQuery: event.searchQuery));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_clearAllData(ClearAllData event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
communitiesList: [],
|
||||
filteredCommunity: [],
|
||||
isSearching: false,
|
||||
soldCheck: [],
|
||||
selectedSpaces: [],
|
||||
selectedCommunities: [],
|
||||
selectedCommunityAndSpaces: {},
|
||||
searchQuery: '',
|
||||
expandedSpaces: [],
|
||||
expandedCommunity: []));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_clearCachedData(ClearCachedData event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
communitiesList: state.communityList,
|
||||
filteredCommunity: [],
|
||||
isSearching: false,
|
||||
soldCheck: [],
|
||||
selectedSpaces: [],
|
||||
selectedCommunities: [],
|
||||
selectedCommunityAndSpaces: {},
|
||||
searchQuery: '',
|
||||
expandedSpaces: [],
|
||||
expandedCommunity: []));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
@ -218,8 +347,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
// Helper function to determine if any space or its children match the search query
|
||||
bool _containsQuery(SpaceModel space, String query) {
|
||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||
final matchesChildren =
|
||||
space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
||||
final matchesChildren = space.children.any((child) =>
|
||||
_containsQuery(child, query)); // Recursive check for children
|
||||
|
||||
return matchesSpace || matchesChildren;
|
||||
}
|
||||
@ -230,14 +359,21 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
ids.add(child.uuid!);
|
||||
ids.addAll(_getAllChildIds(child.children));
|
||||
}
|
||||
return ids;
|
||||
return ids.toSet().toList();
|
||||
}
|
||||
|
||||
bool _anySpacesSelectedInCommunity(
|
||||
String communityId, List<String> selectedSpaces, List<String> partialCheckedList) {
|
||||
List<SpaceModel> _getAllChildSpaces(List<SpaceModel> spaces) {
|
||||
List<SpaceModel> children = [];
|
||||
for (var child in spaces) {
|
||||
children.add(child);
|
||||
children.addAll(_getAllChildSpaces(child.children));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
bool _anySpacesSelectedInCommunity(CommunityModel community,
|
||||
List<String> selectedSpaces, List<String> partialCheckedList) {
|
||||
bool result = false;
|
||||
for (var community in state.communityList) {
|
||||
if (community.uuid == communityId) {
|
||||
List<String> ids = _getAllChildIds(community.spaces);
|
||||
for (var id in ids) {
|
||||
result = selectedSpaces.contains(id) || partialCheckedList.contains(id);
|
||||
@ -245,8 +381,6 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -267,7 +401,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
return ids;
|
||||
}
|
||||
|
||||
List<String> _getAllParentsIds(SpaceModel child, String spaceId, List<String> listIds) {
|
||||
List<String> _getAllParentsIds(
|
||||
SpaceModel child, String spaceId, List<String> listIds) {
|
||||
List<String> ids = listIds;
|
||||
|
||||
ids.add(child.uuid ?? '');
|
||||
@ -288,4 +423,9 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
ids.removeLast();
|
||||
return [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
|
||||
class SpaceTreeEvent extends Equatable {
|
||||
@ -49,14 +50,14 @@ class OnSpaceExpanded extends SpaceTreeEvent {
|
||||
}
|
||||
|
||||
class OnSpaceSelected extends SpaceTreeEvent {
|
||||
final String communityId;
|
||||
final String spaceId;
|
||||
final List<SpaceModel> children;
|
||||
final CommunityModel communityModel;
|
||||
|
||||
const OnSpaceSelected(this.communityId, this.spaceId, this.children);
|
||||
const OnSpaceSelected(this.communityModel, this.spaceId, this.children);
|
||||
|
||||
@override
|
||||
List<Object> get props => [communityId, spaceId, children];
|
||||
List<Object> get props => [communityModel, spaceId, children];
|
||||
}
|
||||
|
||||
class SearchQueryEvent extends SpaceTreeEvent {
|
||||
@ -67,3 +68,24 @@ class SearchQueryEvent extends SpaceTreeEvent {
|
||||
@override
|
||||
List<Object> get props => [searchQuery];
|
||||
}
|
||||
|
||||
class OnCommunityAdded extends SpaceTreeEvent {
|
||||
final CommunityModel newCommunity;
|
||||
const OnCommunityAdded(this.newCommunity);
|
||||
|
||||
@override
|
||||
List<Object> get props => [newCommunity];
|
||||
}
|
||||
|
||||
class OnCommunityUpdated extends SpaceTreeEvent {
|
||||
final CommunityModel updatedCommunity;
|
||||
const OnCommunityUpdated(this.updatedCommunity);
|
||||
|
||||
@override
|
||||
List<Object> get props => [updatedCommunity];
|
||||
}
|
||||
|
||||
|
||||
class ClearAllData extends SpaceTreeEvent {}
|
||||
|
||||
class ClearCachedData extends SpaceTreeEvent {}
|
||||
|
@ -11,6 +11,7 @@ class SpaceTreeState extends Equatable {
|
||||
final List<String> selectedSpaces;
|
||||
final List<String> soldCheck;
|
||||
final bool isSearching;
|
||||
final String searchQuery;
|
||||
|
||||
const SpaceTreeState(
|
||||
{this.communityList = const [],
|
||||
@ -21,7 +22,8 @@ class SpaceTreeState extends Equatable {
|
||||
this.selectedSpaces = const [],
|
||||
this.soldCheck = const [],
|
||||
this.isSearching = false,
|
||||
this.selectedCommunityAndSpaces = const {}});
|
||||
this.selectedCommunityAndSpaces = const {},
|
||||
this.searchQuery = ''});
|
||||
|
||||
SpaceTreeState copyWith(
|
||||
{List<CommunityModel>? communitiesList,
|
||||
@ -32,7 +34,8 @@ class SpaceTreeState extends Equatable {
|
||||
List<String>? selectedSpaces,
|
||||
List<String>? soldCheck,
|
||||
bool? isSearching,
|
||||
Map<String, List<String>>? selectedCommunityAndSpaces}) {
|
||||
Map<String, List<String>>? selectedCommunityAndSpaces,
|
||||
String? searchQuery}) {
|
||||
return SpaceTreeState(
|
||||
communityList: communitiesList ?? this.communityList,
|
||||
filteredCommunity: filteredCommunity ?? this.filteredCommunity,
|
||||
@ -42,7 +45,8 @@ class SpaceTreeState extends Equatable {
|
||||
selectedSpaces: selectedSpaces ?? this.selectedSpaces,
|
||||
soldCheck: soldCheck ?? this.soldCheck,
|
||||
isSearching: isSearching ?? this.isSearching,
|
||||
selectedCommunityAndSpaces: selectedCommunityAndSpaces ?? this.selectedCommunityAndSpaces);
|
||||
selectedCommunityAndSpaces: selectedCommunityAndSpaces ?? this.selectedCommunityAndSpaces,
|
||||
searchQuery: searchQuery ?? this.searchQuery);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -55,7 +59,8 @@ class SpaceTreeState extends Equatable {
|
||||
selectedSpaces,
|
||||
soldCheck,
|
||||
isSearching,
|
||||
selectedCommunityAndSpaces
|
||||
selectedCommunityAndSpaces,
|
||||
searchQuery
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
: Column(
|
||||
children: [
|
||||
CustomSearchBar(
|
||||
searchQuery: state.searchQuery,
|
||||
onSearchChanged: (query) {
|
||||
context.read<SpaceTreeBloc>().add(SearchQueryEvent(query));
|
||||
},
|
||||
@ -99,8 +100,8 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
state.expandedSpaces.contains(space.uuid),
|
||||
onItemSelected: () {
|
||||
context.read<SpaceTreeBloc>().add(
|
||||
OnSpaceSelected(community.uuid,
|
||||
space.uuid ?? '', space.children));
|
||||
OnSpaceSelected(community, space.uuid ?? '',
|
||||
space.children));
|
||||
widget.onSelect();
|
||||
},
|
||||
onExpansionChanged: () {
|
||||
@ -113,7 +114,7 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
state.soldCheck.contains(space.uuid),
|
||||
isSoldCheck: state.soldCheck.contains(space.uuid),
|
||||
children: _buildNestedSpaces(
|
||||
context, state, space, community.uuid),
|
||||
context, state, space, community),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
@ -196,7 +197,7 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
}
|
||||
|
||||
List<Widget> _buildNestedSpaces(
|
||||
BuildContext context, SpaceTreeState state, SpaceModel space, String communityId) {
|
||||
BuildContext context, SpaceTreeState state, SpaceModel space, CommunityModel community) {
|
||||
return space.children.map((child) {
|
||||
return CustomExpansionTileSpaceTree(
|
||||
isSelected:
|
||||
@ -207,13 +208,13 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
onItemSelected: () {
|
||||
context
|
||||
.read<SpaceTreeBloc>()
|
||||
.add(OnSpaceSelected(communityId, child.uuid ?? '', child.children));
|
||||
.add(OnSpaceSelected(community, child.uuid ?? '', child.children));
|
||||
widget.onSelect();
|
||||
},
|
||||
onExpansionChanged: () {
|
||||
context.read<SpaceTreeBloc>().add(OnSpaceExpanded(communityId, child.uuid ?? ''));
|
||||
context.read<SpaceTreeBloc>().add(OnSpaceExpanded(community.uuid, child.uuid ?? ''));
|
||||
},
|
||||
children: _buildNestedSpaces(context, state, child, communityId),
|
||||
children: _buildNestedSpaces(context, state, child, community),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
@ -13,7 +17,7 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_updat
|
||||
import 'package:syncrow_web/services/product_api.dart';
|
||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/action_enum.dart';
|
||||
import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action;
|
||||
|
||||
class SpaceManagementBloc
|
||||
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
||||
@ -22,11 +26,16 @@ class SpaceManagementBloc
|
||||
final SpaceModelManagementApi _spaceModelApi;
|
||||
|
||||
List<ProductModel>? _cachedProducts;
|
||||
List<SpaceTemplateModel>? _cachedSpaceModels;
|
||||
final SpaceTreeBloc _spaceTreeBloc;
|
||||
|
||||
SpaceManagementBloc(this._api, this._productApi, this._spaceModelApi)
|
||||
: super(SpaceManagementInitial()) {
|
||||
SpaceManagementBloc(
|
||||
this._api,
|
||||
this._productApi,
|
||||
this._spaceModelApi,
|
||||
this._spaceTreeBloc,
|
||||
) : super(SpaceManagementInitial()) {
|
||||
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||
on<UpdateSpacePositionEvent>(_onUpdateSpacePosition);
|
||||
on<CreateCommunityEvent>(_onCreateCommunity);
|
||||
on<SelectCommunityEvent>(_onSelectCommunity);
|
||||
on<DeleteCommunityEvent>(_onCommunityDelete);
|
||||
@ -37,6 +46,88 @@ class SpaceManagementBloc
|
||||
on<NewCommunityEvent>(_onNewCommunity);
|
||||
on<BlankStateEvent>(_onBlankState);
|
||||
on<SpaceModelLoadEvent>(_onLoadSpaceModel);
|
||||
on<UpdateSpaceModelCache>(_updateSpaceModelCache);
|
||||
on<DeleteSpaceModelFromCache>(_deleteSpaceModelFromCache);
|
||||
}
|
||||
|
||||
Future<void> _updateSpaceModelCache(
|
||||
UpdateSpaceModelCache event, Emitter<SpaceManagementState> emit) async {
|
||||
if (_cachedSpaceModels != null) {
|
||||
_cachedSpaceModels = _cachedSpaceModels!.map((model) {
|
||||
return model.uuid == event.updatedModel.uuid
|
||||
? event.updatedModel
|
||||
: model;
|
||||
}).toList();
|
||||
} else {
|
||||
_cachedSpaceModels = await fetchSpaceModels();
|
||||
}
|
||||
|
||||
emit(SpaceModelLoaded(
|
||||
communities: state is SpaceManagementLoaded
|
||||
? (state as SpaceManagementLoaded).communities
|
||||
: [],
|
||||
products: _cachedProducts ?? [],
|
||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||
));
|
||||
}
|
||||
|
||||
void _deleteSpaceModelFromCache(DeleteSpaceModelFromCache event,
|
||||
Emitter<SpaceManagementState> emit) async {
|
||||
if (_cachedSpaceModels != null) {
|
||||
_cachedSpaceModels = _cachedSpaceModels!
|
||||
.where((model) => model.uuid != event.deletedUuid)
|
||||
.toList();
|
||||
} else {
|
||||
_cachedSpaceModels = await fetchSpaceModels();
|
||||
}
|
||||
|
||||
emit(SpaceModelLoaded(
|
||||
communities: state is SpaceManagementLoaded
|
||||
? (state as SpaceManagementLoaded).communities
|
||||
: [],
|
||||
products: _cachedProducts ?? [],
|
||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||
));
|
||||
}
|
||||
|
||||
void updateCachedSpaceModels(List<SpaceTemplateModel> updatedModels) {
|
||||
_cachedSpaceModels = List.from(updatedModels);
|
||||
}
|
||||
|
||||
void addToCachedSpaceModels(SpaceTemplateModel newModel) {
|
||||
_cachedSpaceModels?.add(newModel);
|
||||
}
|
||||
|
||||
Future<List<SpaceTemplateModel>> fetchSpaceModels() async {
|
||||
try {
|
||||
if (_cachedSpaceModels != null) {
|
||||
return _cachedSpaceModels!;
|
||||
}
|
||||
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
List<SpaceTemplateModel> allSpaceModels = [];
|
||||
|
||||
bool hasNext = true;
|
||||
int page = 1;
|
||||
|
||||
while (hasNext) {
|
||||
final spaceModels = await _spaceModelApi.listSpaceModels(
|
||||
page: page, projectId: projectUuid);
|
||||
if (spaceModels.isNotEmpty) {
|
||||
allSpaceModels.addAll(spaceModels);
|
||||
page++;
|
||||
} else {
|
||||
hasNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
_cachedSpaceModels = allSpaceModels;
|
||||
|
||||
return allSpaceModels;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateCommunity(
|
||||
@ -45,9 +136,11 @@ class SpaceManagementBloc
|
||||
) async {
|
||||
final previousState = state;
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
emit(SpaceManagementLoading());
|
||||
final success =
|
||||
await _api.updateCommunity(event.communityUuid, event.name);
|
||||
final success = await _api.updateCommunity(
|
||||
event.communityUuid, event.name, projectUuid);
|
||||
if (success) {
|
||||
if (previousState is SpaceManagementLoaded) {
|
||||
final updatedCommunities =
|
||||
@ -55,11 +148,13 @@ class SpaceManagementBloc
|
||||
for (var community in updatedCommunities) {
|
||||
if (community.uuid == event.communityUuid) {
|
||||
community.name = event.name;
|
||||
_spaceTreeBloc.add(OnCommunityAdded(community));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var prevSpaceModels = await fetchSpaceModels(previousState);
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
emit(SpaceManagementLoaded(
|
||||
communities: updatedCommunities,
|
||||
@ -76,42 +171,6 @@ class SpaceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<SpaceTemplateModel>> fetchSpaceModels(
|
||||
SpaceManagementState previousState) async {
|
||||
try {
|
||||
List<SpaceTemplateModel> allSpaces = [];
|
||||
List<SpaceTemplateModel> prevSpaceModels = [];
|
||||
|
||||
if (previousState is SpaceManagementLoaded ||
|
||||
previousState is BlankState) {
|
||||
prevSpaceModels = List<SpaceTemplateModel>.from(
|
||||
(previousState as dynamic).spaceModels ?? [],
|
||||
);
|
||||
allSpaces.addAll(prevSpaceModels);
|
||||
}
|
||||
|
||||
if (prevSpaceModels.isEmpty) {
|
||||
bool hasNext = true;
|
||||
int page = 1;
|
||||
|
||||
while (hasNext) {
|
||||
final spaces = await _spaceModelApi.listSpaceModels(page: page);
|
||||
if (spaces.isNotEmpty) {
|
||||
allSpaces.addAll(spaces);
|
||||
page++;
|
||||
} else {
|
||||
hasNext = false;
|
||||
}
|
||||
}
|
||||
prevSpaceModels = await _spaceModelApi.listSpaceModels(page: 1);
|
||||
}
|
||||
|
||||
return allSpaces;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
void _onloadProducts() async {
|
||||
if (_cachedProducts == null) {
|
||||
final products = await _productApi.fetchProducts();
|
||||
@ -132,7 +191,9 @@ class SpaceManagementBloc
|
||||
|
||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||
String communityUuid) async {
|
||||
return await _api.getSpaceHierarchy(communityUuid);
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
|
||||
}
|
||||
|
||||
Future<void> _onNewCommunity(
|
||||
@ -147,7 +208,7 @@ class SpaceManagementBloc
|
||||
return;
|
||||
}
|
||||
|
||||
var prevSpaceModels = await fetchSpaceModels(previousState);
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
emit(BlankState(
|
||||
communities: event.communities,
|
||||
@ -163,7 +224,11 @@ class SpaceManagementBloc
|
||||
BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
|
||||
try {
|
||||
final previousState = state;
|
||||
var prevSpaceModels = await fetchSpaceModels(previousState);
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
||||
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
if (previousState is SpaceManagementLoaded ||
|
||||
previousState is BlankState) {
|
||||
@ -176,41 +241,8 @@ class SpaceManagementBloc
|
||||
return;
|
||||
}
|
||||
|
||||
final communities = await _api.fetchCommunities();
|
||||
final updatedCommunities =
|
||||
await Future.wait(communities.map((community) async {
|
||||
final spaces = await _fetchSpacesForCommunity(community.uuid);
|
||||
|
||||
return CommunityModel(
|
||||
uuid: community.uuid,
|
||||
createdAt: community.createdAt,
|
||||
updatedAt: community.updatedAt,
|
||||
name: community.name,
|
||||
description: community.description,
|
||||
spaces: spaces,
|
||||
region: community.region,
|
||||
);
|
||||
}));
|
||||
|
||||
emit(BlankState(
|
||||
spaceModels: prevSpaceModels,
|
||||
communities: updatedCommunities,
|
||||
products: _cachedProducts ?? [],
|
||||
));
|
||||
} catch (error) {
|
||||
emit(SpaceManagementError('Error loading communities: $error'));
|
||||
}
|
||||
}
|
||||
|
||||
void _onLoadCommunityAndSpaces(
|
||||
LoadCommunityAndSpacesEvent event,
|
||||
Emitter<SpaceManagementState> emit,
|
||||
) async {
|
||||
var prevState = state;
|
||||
emit(SpaceManagementLoading());
|
||||
try {
|
||||
_onloadProducts();
|
||||
List<CommunityModel> communities = await _api.fetchCommunities();
|
||||
if (communities.isEmpty) {
|
||||
communities = await _api.fetchCommunities(projectUuid);
|
||||
|
||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
@ -222,20 +254,62 @@ class SpaceManagementBloc
|
||||
updatedAt: community.updatedAt,
|
||||
name: community.name,
|
||||
description: community.description,
|
||||
spaces: spaces, // New spaces list
|
||||
spaces: spaces,
|
||||
region: community.region,
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
|
||||
final prevSpaceModels = await fetchSpaceModels(prevState);
|
||||
emit(SpaceManagementLoaded(
|
||||
communities: updatedCommunities,
|
||||
products: _cachedProducts ?? [],
|
||||
spaceModels: prevSpaceModels));
|
||||
} catch (e) {
|
||||
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
||||
communities = updatedCommunities;
|
||||
}
|
||||
|
||||
emit(BlankState(
|
||||
spaceModels: prevSpaceModels,
|
||||
communities: communities,
|
||||
products: _cachedProducts ?? [],
|
||||
));
|
||||
} catch (error) {
|
||||
emit(SpaceManagementError('Error loading communities: $error'));
|
||||
}
|
||||
}
|
||||
|
||||
void _onLoadCommunityAndSpaces(
|
||||
LoadCommunityAndSpacesEvent event,
|
||||
Emitter<SpaceManagementState> emit,
|
||||
) async {
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
_onloadProducts();
|
||||
|
||||
// Wait until `communityList` is loaded
|
||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
||||
|
||||
// Fetch space models after communities are available
|
||||
final prevSpaceModels = await fetchSpaceModels();
|
||||
emit(SpaceManagementLoaded(
|
||||
communities: communities,
|
||||
products: _cachedProducts ?? [],
|
||||
spaceModels: prevSpaceModels,
|
||||
));
|
||||
}
|
||||
|
||||
Future<List<CommunityModel>> _waitForCommunityList(
|
||||
SpaceTreeBloc spaceBloc) async {
|
||||
// Check if communityList is already populated
|
||||
if (spaceBloc.state.communityList.isNotEmpty) {
|
||||
return spaceBloc.state.communityList;
|
||||
}
|
||||
|
||||
final completer = Completer<List<CommunityModel>>();
|
||||
final subscription = spaceBloc.stream.listen((state) {
|
||||
if (state.communityList.isNotEmpty) {
|
||||
completer.complete(state.communityList);
|
||||
}
|
||||
});
|
||||
|
||||
// Return the list once available, then cancel the listener
|
||||
final communities = await completer.future;
|
||||
await subscription.cancel();
|
||||
return communities;
|
||||
}
|
||||
|
||||
void _onCommunityDelete(
|
||||
@ -244,10 +318,12 @@ class SpaceManagementBloc
|
||||
) async {
|
||||
try {
|
||||
emit(SpaceManagementLoading());
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final success = await _api.deleteCommunity(event.communityUuid);
|
||||
final success =
|
||||
await _api.deleteCommunity(event.communityUuid, projectUuid);
|
||||
if (success) {
|
||||
add(LoadCommunityAndSpacesEvent());
|
||||
// add(LoadCommunityAndSpacesEvent());
|
||||
} else {
|
||||
emit(const SpaceManagementError('Failed to delete the community.'));
|
||||
}
|
||||
@ -257,11 +333,6 @@ class SpaceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateSpacePosition(
|
||||
UpdateSpacePositionEvent event,
|
||||
Emitter<SpaceManagementState> emit,
|
||||
) {}
|
||||
|
||||
void _onCreateCommunity(
|
||||
CreateCommunityEvent event,
|
||||
Emitter<SpaceManagementState> emit,
|
||||
@ -270,9 +341,11 @@ class SpaceManagementBloc
|
||||
emit(SpaceManagementLoading());
|
||||
|
||||
try {
|
||||
CommunityModel? newCommunity =
|
||||
await _api.createCommunity(event.name, event.description);
|
||||
var prevSpaceModels = await fetchSpaceModels(previousState);
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
CommunityModel? newCommunity = await _api.createCommunity(
|
||||
event.name, event.description, projectUuid);
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
if (newCommunity != null) {
|
||||
if (previousState is SpaceManagementLoaded ||
|
||||
@ -281,6 +354,8 @@ class SpaceManagementBloc
|
||||
(previousState as dynamic).communities,
|
||||
);
|
||||
final updatedCommunities = prevCommunities..add(newCommunity);
|
||||
_spaceTreeBloc.add(OnCommunityAdded(newCommunity));
|
||||
|
||||
emit(SpaceManagementLoaded(
|
||||
spaceModels: prevSpaceModels,
|
||||
communities: updatedCommunities,
|
||||
@ -375,8 +450,6 @@ class SpaceManagementBloc
|
||||
event.communityUuid,
|
||||
emit,
|
||||
);
|
||||
} else {
|
||||
add(LoadCommunityAndSpacesEvent());
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SpaceManagementError('Error saving spaces: $e'));
|
||||
@ -393,13 +466,15 @@ class SpaceManagementBloc
|
||||
String communityUuid,
|
||||
Emitter<SpaceManagementState> emit,
|
||||
) async {
|
||||
var prevSpaceModels = await fetchSpaceModels(previousState);
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
final communities = List<CommunityModel>.from(previousState.communities);
|
||||
|
||||
for (var community in communities) {
|
||||
if (community.uuid == communityUuid) {
|
||||
community.spaces = allSpaces;
|
||||
_spaceTreeBloc.add(OnCommunityUpdated(community));
|
||||
|
||||
emit(SpaceManagementLoaded(
|
||||
communities: communities,
|
||||
products: _cachedProducts ?? [],
|
||||
@ -414,6 +489,7 @@ class SpaceManagementBloc
|
||||
Future<List<SpaceModel>> saveSpacesHierarchically(
|
||||
List<SpaceModel> spaces, String communityUuid) async {
|
||||
final orderedSpaces = flattenHierarchy(spaces);
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final parentsToDelete = orderedSpaces.where((space) =>
|
||||
space.status == SpaceStatus.deleted &&
|
||||
@ -422,7 +498,7 @@ class SpaceManagementBloc
|
||||
for (var parent in parentsToDelete) {
|
||||
try {
|
||||
if (parent.uuid != null) {
|
||||
await _api.deleteSpace(communityUuid, parent.uuid!);
|
||||
await _api.deleteSpace(communityUuid, parent.uuid!, projectUuid);
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
@ -435,7 +511,8 @@ class SpaceManagementBloc
|
||||
if (space.uuid != null && space.uuid!.isNotEmpty) {
|
||||
List<TagModelUpdate> tagUpdates = [];
|
||||
|
||||
final prevSpace = await _api.getSpace(communityUuid, space.uuid!);
|
||||
final prevSpace =
|
||||
await _api.getSpace(communityUuid, space.uuid!, projectUuid);
|
||||
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
||||
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
||||
final List<SubspaceModel>? newSubspaces = space.subspaces;
|
||||
@ -449,13 +526,15 @@ class SpaceManagementBloc
|
||||
.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
||||
if (!existsInNew) {
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.delete, uuid: prevSubspace.uuid));
|
||||
action: custom_action.Action.delete,
|
||||
uuid: prevSubspace.uuid));
|
||||
}
|
||||
}
|
||||
} else if (prevSubspaces != null && newSubspaces == null) {
|
||||
for (var prevSubspace in prevSubspaces) {
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.delete, uuid: prevSubspace.uuid));
|
||||
action: custom_action.Action.delete,
|
||||
uuid: prevSubspace.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,14 +547,14 @@ class SpaceManagementBloc
|
||||
if (newSubspace.tags != null) {
|
||||
for (var tag in newSubspace.tags!) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
action: custom_action.Action.add,
|
||||
uuid: tag.uuid == '' ? null : tag.uuid,
|
||||
tag: tag.tag,
|
||||
productUuid: tag.product?.uuid));
|
||||
}
|
||||
}
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.add,
|
||||
action: custom_action.Action.add,
|
||||
subspaceName: newSubspace.subspaceName,
|
||||
tags: tagUpdates));
|
||||
}
|
||||
@ -494,7 +573,7 @@ class SpaceManagementBloc
|
||||
final List<TagModelUpdate> tagSubspaceUpdates =
|
||||
processTagUpdates(prevSubspace.tags, newSubspace.tags);
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.update,
|
||||
action: custom_action.Action.update,
|
||||
uuid: newSubspace.uuid,
|
||||
subspaceName: newSubspace.subspaceName,
|
||||
tags: tagSubspaceUpdates));
|
||||
@ -514,7 +593,7 @@ class SpaceManagementBloc
|
||||
subspaces: subspaceUpdates,
|
||||
tags: tagUpdates,
|
||||
direction: space.incomingConnection?.direction,
|
||||
);
|
||||
projectId: projectUuid);
|
||||
} else {
|
||||
// Call create if the space does not have a UUID
|
||||
final List<CreateTagBodyModel> tagBodyModels = space.tags != null
|
||||
@ -543,7 +622,7 @@ class SpaceManagementBloc
|
||||
spaceModelUuid: space.spaceModel?.uuid,
|
||||
tags: tagBodyModels,
|
||||
subspaces: createSubspaceBodyModels,
|
||||
);
|
||||
projectId: projectUuid);
|
||||
space.uuid = response?.uuid;
|
||||
}
|
||||
} catch (e) {
|
||||
@ -581,10 +660,17 @@ class SpaceManagementBloc
|
||||
void _onLoadSpaceModel(
|
||||
SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
||||
emit(SpaceManagementLoading());
|
||||
|
||||
try {
|
||||
var prevState = state;
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
List<CommunityModel> communities = spaceBloc.state.communityList;
|
||||
|
||||
List<CommunityModel> communities = await _api.fetchCommunities();
|
||||
var prevSpaceModels = await fetchSpaceModels();
|
||||
|
||||
if (communities.isEmpty) {
|
||||
communities = await _api.fetchCommunities(projectUuid);
|
||||
|
||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
@ -596,18 +682,20 @@ class SpaceManagementBloc
|
||||
updatedAt: community.updatedAt,
|
||||
name: community.name,
|
||||
description: community.description,
|
||||
spaces: spaces, // New spaces list
|
||||
spaces: spaces,
|
||||
region: community.region,
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
|
||||
var prevSpaceModels = await fetchSpaceModels(prevState);
|
||||
communities = updatedCommunities;
|
||||
}
|
||||
|
||||
emit(SpaceModelLoaded(
|
||||
communities: updatedCommunities,
|
||||
communities: communities,
|
||||
products: _cachedProducts ?? [],
|
||||
spaceModels: prevSpaceModels));
|
||||
spaceModels: prevSpaceModels,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
||||
}
|
||||
@ -623,7 +711,7 @@ class SpaceManagementBloc
|
||||
if (prevTags == null && newTags != null) {
|
||||
for (var newTag in newTags) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
action: custom_action.Action.add,
|
||||
tag: newTag.tag,
|
||||
uuid: newTag.uuid,
|
||||
productUuid: newTag.product?.uuid,
|
||||
@ -639,14 +727,14 @@ class SpaceManagementBloc
|
||||
final existsInNew =
|
||||
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
||||
if (!existsInNew) {
|
||||
tagUpdates
|
||||
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||
}
|
||||
}
|
||||
} else if (prevTags != null && newTags == null) {
|
||||
for (var prevTag in prevTags) {
|
||||
tagUpdates
|
||||
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
@ -659,7 +747,7 @@ class SpaceManagementBloc
|
||||
if ((newTag.uuid == null || !prevTagUuids.contains(newTag.uuid)) &&
|
||||
!processedTags.contains(newTag.tag)) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
action: custom_action.Action.add,
|
||||
tag: newTag.tag,
|
||||
uuid: newTag.uuid == '' ? null : newTag.uuid,
|
||||
productUuid: newTag.product?.uuid));
|
||||
@ -676,7 +764,7 @@ class SpaceManagementBloc
|
||||
final newTag = newTagMap[prevTag.uuid];
|
||||
if (newTag != null) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.update,
|
||||
action: custom_action.Action.update,
|
||||
uuid: newTag.uuid,
|
||||
tag: newTag.tag,
|
||||
));
|
||||
|
@ -1,16 +1,23 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; // Import for Offset
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; // Import for Offset
|
||||
|
||||
abstract class SpaceManagementEvent extends Equatable {
|
||||
const SpaceManagementEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class LoadCommunityAndSpacesEvent extends SpaceManagementEvent {}
|
||||
class LoadCommunityAndSpacesEvent extends SpaceManagementEvent {
|
||||
final BuildContext context;
|
||||
|
||||
const LoadCommunityAndSpacesEvent(this.context);
|
||||
@override
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class DeleteCommunityEvent extends SpaceManagementEvent {
|
||||
final String communityUuid;
|
||||
@ -74,14 +81,12 @@ class UpdateSpacePositionEvent extends SpaceManagementEvent {
|
||||
class CreateCommunityEvent extends SpaceManagementEvent {
|
||||
final String name;
|
||||
final String description;
|
||||
final BuildContext context;
|
||||
|
||||
const CreateCommunityEvent({
|
||||
required this.name,
|
||||
required this.description,
|
||||
});
|
||||
const CreateCommunityEvent(this.name, this.description, this.context);
|
||||
|
||||
@override
|
||||
List<Object> get props => [name, description];
|
||||
List<Object?> get props => [name, description, context];
|
||||
}
|
||||
|
||||
class UpdateCommunityEvent extends SpaceManagementEvent {
|
||||
@ -141,7 +146,28 @@ class LoadSpaceHierarchyEvent extends SpaceManagementEvent {
|
||||
List<Object> get props => [communityId];
|
||||
}
|
||||
|
||||
class BlankStateEvent extends SpaceManagementEvent {
|
||||
final BuildContext context;
|
||||
|
||||
class BlankStateEvent extends SpaceManagementEvent {}
|
||||
const BlankStateEvent(this.context);
|
||||
@override
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class SpaceModelLoadEvent extends SpaceManagementEvent {}
|
||||
class SpaceModelLoadEvent extends SpaceManagementEvent {
|
||||
final BuildContext context;
|
||||
|
||||
const SpaceModelLoadEvent(this.context);
|
||||
@override
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class UpdateSpaceModelCache extends SpaceManagementEvent {
|
||||
final SpaceTemplateModel updatedModel;
|
||||
UpdateSpaceModelCache(this.updatedModel);
|
||||
}
|
||||
|
||||
class DeleteSpaceModelFromCache extends SpaceManagementEvent {
|
||||
final String deletedUuid;
|
||||
DeleteSpaceModelFromCache(this.deletedUuid);
|
||||
}
|
@ -30,10 +30,6 @@ class SpaceManagementLoaded extends SpaceManagementState {
|
||||
this.spaceModels});
|
||||
}
|
||||
|
||||
class SpaceModelManagenetLoaded extends SpaceManagementState {
|
||||
SpaceModelManagenetLoaded();
|
||||
}
|
||||
|
||||
class BlankState extends SpaceManagementState {
|
||||
final List<CommunityModel> communities;
|
||||
final List<ProductModel> products;
|
||||
@ -75,3 +71,4 @@ class SpaceModelLoaded extends SpaceManagementState {
|
||||
@override
|
||||
List<Object> get props => [communities, products, spaceModels];
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||
@ -29,11 +32,15 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (_) => SpaceManagementBloc(_api, _productApi, _spaceModelApi)
|
||||
..add(LoadCommunityAndSpacesEvent()),
|
||||
create: (context) => SpaceManagementBloc(
|
||||
_api,
|
||||
_productApi,
|
||||
_spaceModelApi,
|
||||
BlocProvider.of<SpaceTreeBloc>(context),
|
||||
)..add(LoadCommunityAndSpacesEvent(this.context)),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (_) => CenterBodyBloc(),
|
||||
create: (context) => CenterBodyBloc(),
|
||||
),
|
||||
],
|
||||
child: WebScaffold(
|
||||
@ -57,6 +64,7 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
shouldNavigateToSpaceModelPage: false,
|
||||
);
|
||||
} else if (state is SpaceManagementLoaded) {
|
||||
|
||||
return LoadedSpaceView(
|
||||
communities: state.communities,
|
||||
selectedCommunity: state.selectedCommunity,
|
||||
|
@ -73,17 +73,14 @@ class _BlankCommunityWidgetState extends State<BlankCommunityWidget> {
|
||||
context: parentContext,
|
||||
builder: (context) => CreateCommunityDialog(
|
||||
isEditMode: false,
|
||||
existingCommunityNames: widget.communities.map((community) => community.name).toList(),
|
||||
existingCommunityNames:
|
||||
widget.communities.map((community) => community.name).toList(),
|
||||
onCreateCommunity: (String communityName, String description) {
|
||||
parentContext.read<SpaceManagementBloc>().add(
|
||||
CreateCommunityEvent(
|
||||
name: communityName,
|
||||
description: description,
|
||||
),
|
||||
CreateCommunityEvent(communityName, description, context),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,9 @@ class CommunityTile extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomExpansionTile(
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: CustomExpansionTile(
|
||||
title: title,
|
||||
initiallyExpanded: isExpanded,
|
||||
isSelected: isSelected,
|
||||
@ -30,6 +32,6 @@ class CommunityTile extends StatelessWidget {
|
||||
},
|
||||
onItemSelected: onItemSelected,
|
||||
children: children ?? [],
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
@ -39,6 +40,7 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_spaceModels = List.from(widget.spaceModels ?? []);
|
||||
}
|
||||
|
||||
@ -46,6 +48,7 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
||||
@override
|
||||
void didUpdateWidget(covariant LoadedSpaceView oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
||||
if (widget.spaceModels != oldWidget.spaceModels) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
@ -74,16 +77,13 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SidebarWidget(
|
||||
communities: widget.communities,
|
||||
selectedSpaceUuid: widget.selectedSpace?.uuid ??
|
||||
widget.selectedCommunity?.uuid ??
|
||||
'',
|
||||
),
|
||||
widget.shouldNavigateToSpaceModelPage
|
||||
? Expanded(
|
||||
? _spaceModels.isNotEmpty
|
||||
? Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 300, child: SpaceTreeView(onSelect: () {})),
|
||||
Expanded(
|
||||
child: BlocProvider(
|
||||
create: (context) => SpaceModelBloc(
|
||||
api: SpaceModelManagementApi(),
|
||||
@ -94,8 +94,19 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
||||
onSpaceModelsUpdated: _onSpaceModelsUpdated,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: CommunityStructureArea(
|
||||
: const Center(child: CircularProgressIndicator())
|
||||
: Row(
|
||||
children: [
|
||||
SidebarWidget(
|
||||
communities: widget.communities,
|
||||
selectedSpaceUuid: widget.selectedSpace?.uuid ??
|
||||
widget.selectedCommunity?.uuid ??
|
||||
'',
|
||||
),
|
||||
CommunityStructureArea(
|
||||
selectedCommunity: widget.selectedCommunity,
|
||||
selectedSpace: widget.selectedSpace,
|
||||
spaces: widget.selectedCommunity?.spaces ?? [],
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
||||
@ -18,6 +19,8 @@ class CreateSpaceModelBloc
|
||||
CreateSpaceModelBloc(this._api) : super(CreateSpaceModelInitial()) {
|
||||
on<CreateSpaceTemplate>((event, emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
late SpaceTemplateModel spaceTemplate = event.spaceTemplate;
|
||||
|
||||
final tagBodyModels =
|
||||
@ -40,7 +43,8 @@ class CreateSpaceModelBloc
|
||||
tags: tagBodyModels,
|
||||
subspaceModels: subspaceTemplateBodyModels);
|
||||
|
||||
final newSpaceTemplate = await _api.createSpaceModel(spaceModelBody);
|
||||
final newSpaceTemplate =
|
||||
await _api.createSpaceModel(spaceModelBody, projectUuid);
|
||||
spaceTemplate.uuid = newSpaceTemplate?.uuid ?? '';
|
||||
|
||||
if (newSpaceTemplate != null) {
|
||||
@ -201,9 +205,11 @@ class CreateSpaceModelBloc
|
||||
|
||||
on<ModifySpaceTemplate>((event, emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
if (event.spaceTemplate.uuid != null) {
|
||||
final prevSpaceModel =
|
||||
await _api.getSpaceModel(event.spaceTemplate.uuid ?? '');
|
||||
final prevSpaceModel = await _api.getSpaceModel(
|
||||
event.spaceTemplate.uuid ?? '', projectUuid);
|
||||
|
||||
final newSpaceModel = event.updatedSpaceTemplate;
|
||||
String? spaceModelName;
|
||||
@ -287,7 +293,7 @@ class CreateSpaceModelBloc
|
||||
subspaceModels: subspaceUpdates);
|
||||
|
||||
final res = await _api.updateSpaceModel(
|
||||
spaceModelBody, prevSpaceModel?.uuid ?? '');
|
||||
spaceModelBody, prevSpaceModel?.uuid ?? '', projectUuid);
|
||||
|
||||
if (res != null) {
|
||||
emit(CreateSpaceModelLoaded(newSpaceModel));
|
||||
|
@ -1,4 +1,7 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||
@ -11,17 +14,23 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
required this.api,
|
||||
required List<SpaceTemplateModel> initialSpaceModels,
|
||||
}) : super(SpaceModelLoaded(spaceModels: initialSpaceModels)) {
|
||||
log('Initial Space Models in: ${initialSpaceModels.map((e) => e.toJson()).toList()}');
|
||||
|
||||
on<CreateSpaceModel>(_onCreateSpaceModel);
|
||||
on<UpdateSpaceModel>(_onUpdateSpaceModel);
|
||||
on<DeleteSpaceModel>(_onDeleteSpaceModel);
|
||||
}
|
||||
|
||||
Future<void> _onCreateSpaceModel(
|
||||
CreateSpaceModel event, Emitter<SpaceModelState> emit) async {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is SpaceModelLoaded) {
|
||||
try {
|
||||
final newSpaceModel =
|
||||
await api.getSpaceModel(event.newSpaceModel.uuid ?? '');
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final newSpaceModel = await api.getSpaceModel(
|
||||
event.newSpaceModel.uuid ?? '', projectUuid);
|
||||
|
||||
if (newSpaceModel != null) {
|
||||
final updatedSpaceModels =
|
||||
@ -40,8 +49,10 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
final currentState = state;
|
||||
if (currentState is SpaceModelLoaded) {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final newSpaceModel =
|
||||
await api.getSpaceModel(event.spaceModelUuid ?? '');
|
||||
await api.getSpaceModel(event.spaceModelUuid, projectUuid);
|
||||
if (newSpaceModel != null) {
|
||||
final updatedSpaceModels = currentState.spaceModels.map((model) {
|
||||
return model.uuid == event.spaceModelUuid ? newSpaceModel : model;
|
||||
@ -53,4 +64,28 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onDeleteSpaceModel(
|
||||
DeleteSpaceModel event, Emitter<SpaceModelState> emit) async {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is SpaceModelLoaded) {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final deletedSuccessfully =
|
||||
await api.deleteSpaceModel(event.spaceModelUuid, projectUuid);
|
||||
|
||||
if (deletedSuccessfully) {
|
||||
final updatedSpaceModels = currentState.spaceModels
|
||||
.where((model) => model.uuid != event.spaceModelUuid)
|
||||
.toList();
|
||||
|
||||
emit(SpaceModelLoaded(spaceModels: updatedSpaceModels));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SpaceModelError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,3 +34,12 @@ class UpdateSpaceModel extends SpaceModelEvent {
|
||||
@override
|
||||
List<Object?> get props => [spaceModelUuid];
|
||||
}
|
||||
|
||||
class DeleteSpaceModel extends SpaceModelEvent {
|
||||
final String spaceModelUuid;
|
||||
|
||||
DeleteSpaceModel({required this.spaceModelUuid});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [spaceModelUuid];
|
||||
}
|
||||
|
@ -90,7 +90,11 @@ class SpaceModelPage extends StatelessWidget {
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
child: SpaceModelCardWidget(model: model),
|
||||
child: SpaceModelCardWidget(
|
||||
model: model,
|
||||
pageContext: context,
|
||||
topActionsDisabled: false,
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
|
@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
||||
@ -50,7 +52,9 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
||||
width: screenWidth * 0.3,
|
||||
child: BlocProvider(
|
||||
create: (_) {
|
||||
final bloc = CreateSpaceModelBloc(_spaceModelApi);
|
||||
final bloc = CreateSpaceModelBloc(
|
||||
_spaceModelApi,
|
||||
);
|
||||
if (spaceModel != null) {
|
||||
bloc.add(UpdateSpaceTemplate(spaceModel!, otherSpaceModels));
|
||||
} else {
|
||||
@ -194,6 +198,12 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
||||
.add(CreateSpaceModel(
|
||||
newSpaceModel:
|
||||
newModel));
|
||||
pageContext!
|
||||
.read<
|
||||
SpaceManagementBloc>()
|
||||
.add(
|
||||
UpdateSpaceModelCache(
|
||||
newModel));
|
||||
}
|
||||
Navigator.of(context)
|
||||
.pop(); // Close the dialog
|
||||
@ -239,6 +249,11 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
||||
spaceModelUuid:
|
||||
newModel.uuid ??
|
||||
''));
|
||||
pageContext!
|
||||
.read<
|
||||
SpaceManagementBloc>()
|
||||
.add(UpdateSpaceModelCache(
|
||||
newModel));
|
||||
}
|
||||
Navigator.of(context)
|
||||
.pop();
|
||||
|
@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeleteSpaceModelDialog extends StatelessWidget {
|
||||
final VoidCallback onConfirmDelete;
|
||||
|
||||
const DeleteSpaceModelDialog({Key? key, required this.onConfirmDelete})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return AlertDialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
title: Center(
|
||||
child: Text(
|
||||
"Delete Space Model",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge
|
||||
?.copyWith(color: ColorsManager.blackColor),
|
||||
),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: screenWidth * 0.4,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Are you sure you want to delete?",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"The existing sub-spaces, devices, and routines will remain associated with the spaces, but the connection will be removed.",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: ColorsManager.lightGrayColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: CancelButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close dialog
|
||||
},
|
||||
label: "Cancel",
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close dialog
|
||||
onConfirmDelete(); // Execute delete action
|
||||
},
|
||||
backgroundColor: ColorsManager.semiTransparentRed,
|
||||
borderRadius: 10,
|
||||
foregroundColor: ColorsManager.whiteColors,
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -1,13 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
|
||||
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/delete_space_model_dialog.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class SpaceModelCardWidget extends StatelessWidget {
|
||||
final SpaceTemplateModel model;
|
||||
final BuildContext? pageContext;
|
||||
final bool topActionsDisabled;
|
||||
|
||||
const SpaceModelCardWidget({Key? key, required this.model}) : super(key: key);
|
||||
const SpaceModelCardWidget({
|
||||
Key? key,
|
||||
required this.model,
|
||||
this.pageContext,
|
||||
this.topActionsDisabled = true,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -51,15 +68,51 @@ class SpaceModelCardWidget extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
model.modelName,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
style:
|
||||
Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (!topActionsDisabled)
|
||||
GestureDetector(
|
||||
onTap: () => _showDeleteDialog(context),
|
||||
child: Container(
|
||||
width: 36, // Adjust size as needed
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.deleteSpaceModel, // Your actual SVG path
|
||||
width: 20,
|
||||
height: 20,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
Colors.grey, BlendMode.srcIn),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!showOnlyName) ...[
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
@ -117,4 +170,26 @@ class SpaceModelCardWidget extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeleteDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return DeleteSpaceModelDialog(
|
||||
onConfirmDelete: () {
|
||||
if (pageContext != null) {
|
||||
pageContext!.read<SpaceModelBloc>().add(
|
||||
DeleteSpaceModel(spaceModelUuid: model.uuid ?? ''),
|
||||
);
|
||||
|
||||
pageContext!.read<SpaceManagementBloc>().add(
|
||||
DeleteSpaceModelFromCache(model.uuid ?? ''),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,11 @@ class CenterBodyWidget extends StatelessWidget {
|
||||
context.read<CenterBodyBloc>().add(CommunityStructureSelectedEvent());
|
||||
}
|
||||
if (state is CommunityStructureState) {
|
||||
context.read<SpaceManagementBloc>().add(BlankStateEvent());
|
||||
context.read<SpaceManagementBloc>().add(BlankStateEvent(context));
|
||||
}
|
||||
|
||||
if (state is SpaceModelState) {
|
||||
context.read<SpaceManagementBloc>().add(SpaceModelLoadEvent());
|
||||
context.read<SpaceManagementBloc>().add(SpaceModelLoadEvent(context));
|
||||
}
|
||||
|
||||
return Container(
|
||||
|
@ -3,6 +3,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
|
||||
@ -13,9 +14,14 @@ import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart';
|
||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
||||
class VisitorPasswordBloc
|
||||
extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
||||
|
||||
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
|
||||
on<SelectUsageFrequency>(selectUsageFrequency);
|
||||
on<FetchDevice>(_onFetchDevice);
|
||||
@ -38,7 +44,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
final TextEditingController deviceNameController = TextEditingController();
|
||||
final TextEditingController deviceIdController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController virtualAddressController = TextEditingController();
|
||||
final TextEditingController virtualAddressController =
|
||||
TextEditingController();
|
||||
List<String> selectedDevices = [];
|
||||
|
||||
List<DeviceModel> data = [];
|
||||
@ -64,12 +71,14 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
String startTimeAccess = 'Start Time';
|
||||
String endTimeAccess = 'End Time';
|
||||
PasswordStatus? passwordStatus;
|
||||
selectAccessType(SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
||||
selectAccessType(
|
||||
SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
||||
accessTypeSelected = event.type;
|
||||
emit(PasswordTypeSelected(event.type));
|
||||
}
|
||||
|
||||
selectUsageFrequency(SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
||||
selectUsageFrequency(
|
||||
SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
||||
usageFrequencySelected = event.usageType;
|
||||
emit(UsageFrequencySelected(event.usageType));
|
||||
}
|
||||
@ -116,10 +125,12 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
timePicked.minute,
|
||||
);
|
||||
|
||||
final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
final selectedTimestamp =
|
||||
selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
|
||||
if (event.isStart) {
|
||||
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
if (expirationTimeTimeStamp != null &&
|
||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Effective Time cannot be later than Expiration Time.',
|
||||
);
|
||||
@ -128,7 +139,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
startTimeAccess = selectedDateTime.toString().split('.').first;
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Expiration Time cannot be earlier than Effective Time.',
|
||||
);
|
||||
@ -143,7 +155,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
}
|
||||
|
||||
bool toggleRepeat(ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
bool toggleRepeat(
|
||||
ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
emit(LoadingInitialState());
|
||||
repeat = !repeat;
|
||||
emit(IsRepeatState(repeat: repeat));
|
||||
@ -175,10 +188,13 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
emit(ChangeTimeState());
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevice(FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> _onFetchDevice(
|
||||
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(DeviceLoaded());
|
||||
data = await AccessMangApi().fetchDevices();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
data = await AccessMangApi().fetchDevices(projectUuid);
|
||||
emit(TableLoaded(data));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
@ -186,8 +202,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
|
||||
//online password
|
||||
Future<void> postOnlineOneTimePassword(
|
||||
OnlineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> postOnlineOneTimePassword(OnlineOneTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
generate7DigitNumber();
|
||||
@ -211,7 +227,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
|
||||
Future<void> postOnlineMultipleTimePassword(
|
||||
OnlineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
OnlineMultipleTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
|
||||
@ -221,7 +238,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
if (repeat)
|
||||
Schedule(
|
||||
effectiveTime: getTimeFromDateTimeString(effectiveTime),
|
||||
invalidTime: getTimeFromDateTimeString(expirationTime).toString(),
|
||||
invalidTime:
|
||||
getTimeFromDateTimeString(expirationTime).toString(),
|
||||
workingDay: selectedDays,
|
||||
),
|
||||
],
|
||||
@ -244,13 +262,15 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
|
||||
//offline password
|
||||
Future<void> postOfflineOneTimePassword(
|
||||
OfflineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> postOfflineOneTimePassword(OfflineOneTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
await generate7DigitNumber();
|
||||
var res = await AccessMangApi().postOffLineOneTime(
|
||||
email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName);
|
||||
email: event.email,
|
||||
devicesUuid: selectedDevices,
|
||||
passwordName: event.passwordName);
|
||||
if (res['statusCode'] == 201) {
|
||||
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||
emit(SuccessState());
|
||||
@ -264,7 +284,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
|
||||
Future<void> postOfflineMultipleTimePassword(
|
||||
OfflineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
OfflineMultipleTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
await generate7DigitNumber();
|
||||
@ -287,7 +308,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
}
|
||||
}
|
||||
|
||||
void selectDevice(SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
void selectDevice(
|
||||
SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
if (selectedDeviceIds.contains(event.deviceId)) {
|
||||
selectedDeviceIds.remove(event.deviceId);
|
||||
} else {
|
||||
@ -329,7 +351,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
add(UpdateFilteredDevicesEvent(filteredData));
|
||||
}
|
||||
|
||||
Stream<VisitorPasswordState> mapEventToState(VisitorPasswordEvent event) async* {
|
||||
Stream<VisitorPasswordState> mapEventToState(
|
||||
VisitorPasswordEvent event) async* {
|
||||
if (event is FetchDevice) {
|
||||
} else if (event is UpdateFilteredDevicesEvent) {
|
||||
yield TableLoaded(event.filteredData);
|
||||
@ -378,16 +401,20 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
|
||||
).millisecondsSinceEpoch ~/
|
||||
1000; // Divide by 1000 to remove milliseconds
|
||||
if (event.isEffective) {
|
||||
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
accessPeriodValidate = "Effective Time cannot be later than Expiration Time.";
|
||||
if (expirationTimeTimeStamp != null &&
|
||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
accessPeriodValidate =
|
||||
"Effective Time cannot be later than Expiration Time.";
|
||||
} else {
|
||||
accessPeriodValidate = '';
|
||||
effectiveTime = selectedDateTime.toString().split('.').first;
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
accessPeriodValidate = 'Expiration Time cannot be earlier than Effective Time.';
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
accessPeriodValidate =
|
||||
'Expiration Time cannot be earlier than Effective Time.';
|
||||
} else {
|
||||
accessPeriodValidate = '';
|
||||
expirationTime = selectedDateTime.toString().split('.').first;
|
||||
|
@ -23,6 +23,7 @@ class DeviceModel {
|
||||
dynamic timeZone;
|
||||
dynamic updateTime;
|
||||
dynamic uuid;
|
||||
dynamic spaceName;
|
||||
|
||||
DeviceModel({
|
||||
required this.productUuid,
|
||||
@ -45,6 +46,7 @@ class DeviceModel {
|
||||
required this.timeZone,
|
||||
required this.updateTime,
|
||||
required this.uuid,
|
||||
required this.spaceName,
|
||||
});
|
||||
|
||||
// Deserialize from JSON
|
||||
@ -53,7 +55,8 @@ class DeviceModel {
|
||||
DeviceType type = devicesTypesMap[json['productType']] ?? DeviceType.Other;
|
||||
if (type == DeviceType.LightBulb) {
|
||||
tempIcon = Assets.lightBulb;
|
||||
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||
} else if (type == DeviceType.CeilingSensor ||
|
||||
type == DeviceType.WallSensor) {
|
||||
tempIcon = Assets.sensors;
|
||||
} else if (type == DeviceType.AC) {
|
||||
tempIcon = Assets.ac;
|
||||
@ -102,6 +105,7 @@ class DeviceModel {
|
||||
timeZone: json['timeZone'],
|
||||
updateTime: json['updateTime'],
|
||||
uuid: json['uuid'],
|
||||
spaceName: json['spaceName'],
|
||||
);
|
||||
}
|
||||
|
||||
@ -128,6 +132,7 @@ class DeviceModel {
|
||||
'timeZone': timeZone,
|
||||
'updateTime': updateTime,
|
||||
'uuid': uuid,
|
||||
'spaceName': spaceName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/common/access_device_table.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||
@ -19,7 +20,8 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
return BlocProvider(
|
||||
create: (context) => VisitorPasswordBloc()..add(FetchDevice()),
|
||||
create: (context) =>
|
||||
VisitorPasswordBloc()..add(FetchDevice()),
|
||||
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
||||
builder: (BuildContext context, VisitorPasswordState state) {
|
||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||
@ -35,10 +37,10 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
backgroundColor: Colors.white,
|
||||
title: Text(
|
||||
'Add Accessible Device',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
|
||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 24,
|
||||
color: Colors.black),
|
||||
),
|
||||
content: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.7,
|
||||
@ -68,7 +70,10 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
'Only online accessible devices can be added',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.grayColor),
|
||||
@ -152,7 +157,8 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
visitorBloc.deviceNameController.clear();
|
||||
visitorBloc.deviceIdController.clear();
|
||||
visitorBloc.unitNameController.clear();
|
||||
visitorBloc.add(FetchDevice()); // Reset to original list
|
||||
visitorBloc.add(
|
||||
FetchDevice()); // Reset to original list
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -172,7 +178,8 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
selectAll: (p0) {
|
||||
visitorBloc.selectedDeviceIds.clear();
|
||||
for (var item in state.data) {
|
||||
visitorBloc.add(SelectDeviceEvent(item.uuid));
|
||||
visitorBloc
|
||||
.add(SelectDeviceEvent(item.uuid));
|
||||
}
|
||||
},
|
||||
onRowSelected: (index, isSelected, row) {
|
||||
@ -193,7 +200,7 @@ class AddDeviceDialog extends StatelessWidget {
|
||||
item.name.toString(),
|
||||
item.uuid.toString(),
|
||||
item.productType.toString(),
|
||||
'',
|
||||
item.spaceName.toString(),
|
||||
item.online.value.toString(),
|
||||
];
|
||||
}).toList(),
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/date_time_widget.dart';
|
||||
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
|
||||
|
@ -6,10 +6,10 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
|
||||
class AccessMangApi {
|
||||
Future<List<PasswordModel>> fetchVisitorPassword() async {
|
||||
Future<List<PasswordModel>> fetchVisitorPassword(String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.visitorPassword,
|
||||
path: ApiEndpoints.visitorPassword.replaceAll('{projectId}', projectId),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
List<dynamic> jsonData = json;
|
||||
@ -25,10 +25,10 @@ class AccessMangApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchDevices() async {
|
||||
Future fetchDevices(String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.getDevices,
|
||||
path: ApiEndpoints.getDevices.replaceAll('{projectId}', projectId),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
List<dynamic> jsonData = json;
|
||||
@ -86,7 +86,8 @@ class AccessMangApi {
|
||||
"invalidTime": invalidTime,
|
||||
};
|
||||
if (scheduleList != null) {
|
||||
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
body["scheduleList"] =
|
||||
scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
||||
@ -105,7 +106,11 @@ class AccessMangApi {
|
||||
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
body: jsonEncode({"email": email, "passwordName": passwordName, "devicesUuid": devicesUuid}),
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"passwordName": passwordName,
|
||||
"devicesUuid": devicesUuid
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
|
@ -12,15 +12,15 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
|
||||
class DevicesManagementApi {
|
||||
Future<List<AllDevicesModel>> fetchDevices(String communityId, String spaceId) async {
|
||||
Future<List<AllDevicesModel>> fetchDevices(String communityId, String spaceId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: communityId.isNotEmpty && spaceId.isNotEmpty
|
||||
? ApiEndpoints.getSpaceDevices
|
||||
.replaceAll('{spaceUuid}', spaceId)
|
||||
.replaceAll('{communityUuid}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId)
|
||||
: ApiEndpoints.getAllDevices,
|
||||
.replaceAll('{projectId}', projectId)
|
||||
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
List<dynamic> jsonData =
|
||||
|
@ -12,7 +12,8 @@ class SceneApi {
|
||||
static final HTTPService _httpService = HTTPService();
|
||||
|
||||
// //create scene
|
||||
static Future<Map<String, dynamic>> createScene(CreateSceneModel createSceneModel) async {
|
||||
static Future<Map<String, dynamic>> createScene(
|
||||
CreateSceneModel createSceneModel) async {
|
||||
try {
|
||||
debugPrint('create scene model: ${createSceneModel.toMap()}');
|
||||
final response = await _httpService.post(
|
||||
@ -69,14 +70,15 @@ class SceneApi {
|
||||
|
||||
//get scenes by community id and space id
|
||||
|
||||
static Future<List<ScenesModel>> getScenes(String spaceId, String communityId,
|
||||
static Future<List<ScenesModel>> getScenes(
|
||||
String spaceId, String communityId, String projectId,
|
||||
{showInDevice = false}) async {
|
||||
try {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getUnitScenes
|
||||
.replaceAll('{spaceUuid}', spaceId)
|
||||
.replaceAll('{communityUuid}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
queryParameters: {'showInHomePage': showInDevice},
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) {
|
||||
@ -100,7 +102,8 @@ class SceneApi {
|
||||
static Future<List<ScenesModel>> getAutomation(String spaceId) async {
|
||||
try {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getSpaceAutomation.replaceAll('{spaceUuid}', spaceId),
|
||||
path:
|
||||
ApiEndpoints.getSpaceAutomation.replaceAll('{spaceUuid}', spaceId),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) {
|
||||
List<ScenesModel> scenes = [];
|
||||
@ -130,10 +133,12 @@ class SceneApi {
|
||||
// }
|
||||
|
||||
//automation details
|
||||
static Future<RoutineDetailsModel> getAutomationDetails(String automationId) async {
|
||||
static Future<RoutineDetailsModel> getAutomationDetails(
|
||||
String automationId) async {
|
||||
try {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getAutomationDetails.replaceAll('{automationId}', automationId),
|
||||
path: ApiEndpoints.getAutomationDetails
|
||||
.replaceAll('{automationId}', automationId),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) => RoutineDetailsModel.fromMap(json),
|
||||
);
|
||||
@ -148,7 +153,8 @@ class SceneApi {
|
||||
try {
|
||||
final response = await _httpService.put(
|
||||
path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId),
|
||||
body: createSceneModel.toJson(sceneId.isNotEmpty == true ? sceneId : null),
|
||||
body: createSceneModel
|
||||
.toJson(sceneId.isNotEmpty == true ? sceneId : null),
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
@ -160,11 +166,14 @@ class SceneApi {
|
||||
}
|
||||
|
||||
//update automation
|
||||
static updateAutomation(CreateAutomationModel createAutomationModel, String automationId) async {
|
||||
static updateAutomation(
|
||||
CreateAutomationModel createAutomationModel, String automationId) async {
|
||||
try {
|
||||
final response = await _httpService.put(
|
||||
path: ApiEndpoints.updateAutomation.replaceAll('{automationId}', automationId),
|
||||
body: createAutomationModel.toJson(automationId.isNotEmpty == true ? automationId : null),
|
||||
path: ApiEndpoints.updateAutomation
|
||||
.replaceAll('{automationId}', automationId),
|
||||
body: createAutomationModel
|
||||
.toJson(automationId.isNotEmpty == true ? automationId : null),
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
@ -181,7 +190,8 @@ class SceneApi {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) => RoutineDetailsModel.fromMap(json['data']),
|
||||
expectedResponseModel: (json) =>
|
||||
RoutineDetailsModel.fromMap(json['data']),
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
@ -190,7 +200,8 @@ class SceneApi {
|
||||
}
|
||||
|
||||
//delete Scene
|
||||
static Future<bool> deleteScene({required String unitUuid, required String sceneId}) async {
|
||||
static Future<bool> deleteScene(
|
||||
{required String unitUuid, required String sceneId}) async {
|
||||
try {
|
||||
final response = await _httpService.delete(
|
||||
path: ApiEndpoints.deleteScene
|
||||
|
@ -13,7 +13,8 @@ import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
|
||||
class CommunitySpaceManagementApi {
|
||||
// Community Management APIs
|
||||
Future<List<CommunityModel>> fetchCommunities({int page = 1}) async {
|
||||
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
||||
{int page = 1}) async {
|
||||
try {
|
||||
List<CommunityModel> allCommunities = [];
|
||||
bool hasNext = true;
|
||||
@ -21,7 +22,7 @@ class CommunitySpaceManagementApi {
|
||||
while (hasNext) {
|
||||
await HTTPService().get(
|
||||
path: ApiEndpoints.getCommunityList
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
queryParameters: {'page': page},
|
||||
expectedResponseModel: (json) {
|
||||
try {
|
||||
@ -65,11 +66,10 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
|
||||
Future<CommunityModel?> createCommunity(
|
||||
String name, String description) async {
|
||||
String name, String description, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.createCommunity
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
|
||||
body: {
|
||||
'name': name,
|
||||
'description': description,
|
||||
@ -85,12 +85,13 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> updateCommunity(String communityId, String name) async {
|
||||
Future<bool> updateCommunity(
|
||||
String communityId, String name, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().put(
|
||||
path: ApiEndpoints.updateCommunity
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
body: {
|
||||
'name': name,
|
||||
},
|
||||
@ -105,12 +106,12 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> deleteCommunity(String communityId) async {
|
||||
Future<bool> deleteCommunity(String communityId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().delete(
|
||||
path: ApiEndpoints.deleteCommunity
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
@ -122,12 +123,13 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<SpacesResponse> fetchSpaces(String communityId) async {
|
||||
Future<SpacesResponse> fetchSpaces(
|
||||
String communityId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.listSpaces
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
expectedResponseModel: (json) {
|
||||
return SpacesResponse.fromJson(json);
|
||||
},
|
||||
@ -148,13 +150,14 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<SpaceModel?> getSpace(String communityId, String spaceId) async {
|
||||
Future<SpaceModel?> getSpace(
|
||||
String communityId, String spaceId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.getSpace
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{spaceId}', spaceId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
expectedResponseModel: (json) {
|
||||
return SpaceModel.fromJson(json['data']);
|
||||
},
|
||||
@ -176,7 +179,8 @@ class CommunitySpaceManagementApi {
|
||||
String? spaceModelUuid,
|
||||
String? icon,
|
||||
List<CreateTagBodyModel>? tags,
|
||||
List<CreateSubspaceModel>? subspaces}) async {
|
||||
List<CreateSubspaceModel>? subspaces,
|
||||
required String projectId}) async {
|
||||
try {
|
||||
final body = {
|
||||
'spaceName': name,
|
||||
@ -199,7 +203,7 @@ class CommunitySpaceManagementApi {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.createSpace
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
body: body,
|
||||
expectedResponseModel: (json) {
|
||||
return SpaceModel.fromJson(json['data']);
|
||||
@ -212,8 +216,8 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> updateSpace({
|
||||
required String communityId,
|
||||
Future<bool> updateSpace(
|
||||
{required String communityId,
|
||||
required spaceId,
|
||||
required String name,
|
||||
String? parentId,
|
||||
@ -223,7 +227,7 @@ class CommunitySpaceManagementApi {
|
||||
required Offset position,
|
||||
List<TagModelUpdate>? tags,
|
||||
List<UpdateSubspaceTemplateModel>? subspaces,
|
||||
}) async {
|
||||
required String projectId}) async {
|
||||
try {
|
||||
final body = {
|
||||
'spaceName': name,
|
||||
@ -243,7 +247,7 @@ class CommunitySpaceManagementApi {
|
||||
path: ApiEndpoints.updateSpace
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{spaceId}', spaceId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
body: body,
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
@ -256,13 +260,14 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> deleteSpace(String communityId, String spaceId) async {
|
||||
Future<bool> deleteSpace(
|
||||
String communityId, String spaceId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().delete(
|
||||
path: ApiEndpoints.deleteSpace
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{spaceId}', spaceId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
@ -274,12 +279,13 @@ class CommunitySpaceManagementApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<SpaceModel>> getSpaceHierarchy(String communityId) async {
|
||||
Future<List<SpaceModel>> getSpaceHierarchy(
|
||||
String communityId, String projectId) async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.getSpaceHierarchy
|
||||
.replaceAll('{communityId}', communityId)
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
.replaceAll('{projectId}', projectId),
|
||||
expectedResponseModel: (json) {
|
||||
final spaceModels = (json['data'] as List)
|
||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
||||
|
@ -5,10 +5,10 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
|
||||
class SpaceModelManagementApi {
|
||||
Future<List<SpaceTemplateModel>> listSpaceModels({int page = 1}) async {
|
||||
Future<List<SpaceTemplateModel>> listSpaceModels(
|
||||
{required String projectId, int page = 1}) async {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.listSpaceModels
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
path: ApiEndpoints.listSpaceModels.replaceAll('{projectId}', projectId),
|
||||
queryParameters: {'page': page},
|
||||
expectedResponseModel: (json) {
|
||||
List<dynamic> jsonData = json['data'];
|
||||
@ -21,10 +21,9 @@ class SpaceModelManagementApi {
|
||||
}
|
||||
|
||||
Future<SpaceTemplateModel?> createSpaceModel(
|
||||
CreateSpaceTemplateBodyModel spaceModel) async {
|
||||
CreateSpaceTemplateBodyModel spaceModel, String projectId) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.createSpaceModel
|
||||
.replaceAll('{projectId}', TempConst.projectId),
|
||||
path: ApiEndpoints.createSpaceModel.replaceAll('{projectId}', projectId),
|
||||
showServerMessage: true,
|
||||
body: spaceModel.toJson(),
|
||||
expectedResponseModel: (json) {
|
||||
@ -34,12 +33,12 @@ class SpaceModelManagementApi {
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
Future<String?> updateSpaceModel(
|
||||
CreateSpaceTemplateBodyModel spaceModel, String spaceModelUuid) async {
|
||||
Future<String?> updateSpaceModel(CreateSpaceTemplateBodyModel spaceModel,
|
||||
String spaceModelUuid, String projectId) async {
|
||||
final response = await HTTPService().put(
|
||||
path: ApiEndpoints.updateSpaceModel
|
||||
.replaceAll('{projectId}', TempConst.projectId).replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||
.replaceAll('{projectId}', projectId)
|
||||
.replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||
body: spaceModel.toJson(),
|
||||
expectedResponseModel: (json) {
|
||||
return json['message'];
|
||||
@ -48,10 +47,11 @@ class SpaceModelManagementApi {
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<SpaceTemplateModel?> getSpaceModel(String spaceModelUuid) async {
|
||||
Future<SpaceTemplateModel?> getSpaceModel(
|
||||
String spaceModelUuid, String projectId) async {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.getSpaceModel
|
||||
.replaceAll('{projectId}', TempConst.projectId)
|
||||
.replaceAll('{projectId}', projectId)
|
||||
.replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
@ -60,4 +60,17 @@ class SpaceModelManagementApi {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<bool> deleteSpaceModel(String spaceModelUuid, String projectId) async {
|
||||
final response = await HTTPService().delete(
|
||||
path: ApiEndpoints.getSpaceModel
|
||||
.replaceAll('{projectId}', projectId)
|
||||
.replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
class UserPermissionApi {
|
||||
static final HTTPService _httpService = HTTPService();
|
||||
|
||||
Future<List<RolesUserModel>> fetchUsers() async {
|
||||
Future<List<RolesUserModel>> fetchUsers(String projectId) async {
|
||||
try {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getUsers,
|
||||
path: ApiEndpoints.getUsers.replaceAll('{projectId}', projectId),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
debugPrint('fetchUsers Response: $json');
|
||||
@ -34,8 +34,9 @@ class UserPermissionApi {
|
||||
path: ApiEndpoints.roleTypes,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
final List<RoleTypeModel> fetchedRoles =
|
||||
(json['data'] as List).map((item) => RoleTypeModel.fromJson(item)).toList();
|
||||
final List<RoleTypeModel> fetchedRoles = (json['data'] as List)
|
||||
.map((item) => RoleTypeModel.fromJson(item))
|
||||
.toList();
|
||||
return fetchedRoles;
|
||||
},
|
||||
);
|
||||
@ -47,7 +48,9 @@ class UserPermissionApi {
|
||||
path: ApiEndpoints.permission.replaceAll("roleUuid", roleUuid),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return (json as List).map((data) => PermissionOption.fromJson(data)).toList();
|
||||
return (json as List)
|
||||
.map((data) => PermissionOption.fromJson(data))
|
||||
.toList();
|
||||
},
|
||||
);
|
||||
return response ?? [];
|
||||
@ -61,6 +64,7 @@ class UserPermissionApi {
|
||||
String? phoneNumber,
|
||||
String? roleUuid,
|
||||
List<String>? spaceUuids,
|
||||
required String projectUuid,
|
||||
}) async {
|
||||
try {
|
||||
final body = <String, dynamic>{
|
||||
@ -70,7 +74,7 @@ class UserPermissionApi {
|
||||
"jobTitle": jobTitle != '' ? jobTitle : null,
|
||||
"phoneNumber": phoneNumber != '' ? phoneNumber : null,
|
||||
"roleUuid": roleUuid,
|
||||
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c",
|
||||
"projectUuid": projectUuid,
|
||||
"spaceUuids": spaceUuids,
|
||||
};
|
||||
final response = await _httpService.post(
|
||||
@ -121,9 +125,11 @@ class UserPermissionApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<EditUserModel?> fetchUserById(userUuid) async {
|
||||
Future<EditUserModel?> fetchUserById(userUuid, String projectId) async {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.getUserById.replaceAll("{userUuid}", userUuid),
|
||||
path: ApiEndpoints.getUserById
|
||||
.replaceAll("{userUuid}", userUuid)
|
||||
.replaceAll("{projectId}", projectId),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
EditUserModel res = EditUserModel.fromJson(json['data']);
|
||||
@ -141,6 +147,7 @@ class UserPermissionApi {
|
||||
String? phoneNumber,
|
||||
String? roleUuid,
|
||||
List<String>? spaceUuids,
|
||||
required String projectUuid,
|
||||
}) async {
|
||||
try {
|
||||
final body = <String, dynamic>{
|
||||
@ -149,7 +156,7 @@ class UserPermissionApi {
|
||||
"jobTitle": jobTitle != '' ? jobTitle : " ",
|
||||
"phoneNumber": phoneNumber != '' ? phoneNumber : " ",
|
||||
"roleUuid": roleUuid,
|
||||
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c",
|
||||
"projectUuid": projectUuid,
|
||||
"spaceUuids": spaceUuids,
|
||||
};
|
||||
final response = await _httpService.put(
|
||||
@ -186,15 +193,16 @@ class UserPermissionApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> changeUserStatusById(userUuid, status) async {
|
||||
Future<bool> changeUserStatusById(userUuid, status, String projectUuid) async {
|
||||
try {
|
||||
Map<String, dynamic> bodya = {
|
||||
"disable": status,
|
||||
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c"
|
||||
"projectUuid": projectUuid
|
||||
};
|
||||
|
||||
final response = await _httpService.put(
|
||||
path: ApiEndpoints.changeUserStatus.replaceAll("{invitedUserUuid}", userUuid),
|
||||
path: ApiEndpoints.changeUserStatus
|
||||
.replaceAll("{invitedUserUuid}", userUuid),
|
||||
body: bodya,
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'];
|
||||
|
@ -71,4 +71,5 @@ abstract class ColorsManager {
|
||||
static const Color lightGrayBorderColor = Color(0xB2D5D5D5);
|
||||
//background: #F8F8F8;
|
||||
static const Color vividBlue = Color(0xFF023DFE);
|
||||
static const Color semiTransparentRed = Color(0x99FF0000);
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ abstract class ApiEndpoints {
|
||||
static const String sendOtp = '/authentication/user/send-otp';
|
||||
static const String verifyOtp = '/authentication/user/verify-otp';
|
||||
static const String getRegion = '/region';
|
||||
static const String visitorPassword = '/visitor-password';
|
||||
static const String getDevices = '/visitor-password/devices';
|
||||
static const String visitorPassword = '/projects/{projectId}/visitor-password';
|
||||
static const String getDevices = '/projects/{projectId}/visitor-password/devices';
|
||||
|
||||
static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time';
|
||||
static const String sendOnlineMultipleTime =
|
||||
@ -25,7 +25,7 @@ abstract class ApiEndpoints {
|
||||
|
||||
////// Devices Management ////////////////
|
||||
|
||||
static const String getAllDevices = '/device';
|
||||
static const String getAllDevices = '/projects/{projectId}/devices';
|
||||
static const String getSpaceDevices =
|
||||
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
||||
static const String getDeviceStatus = '/device/{uuid}/functions/status';
|
||||
@ -95,8 +95,8 @@ abstract class ApiEndpoints {
|
||||
static const String inviteUser = '/invite-user';
|
||||
|
||||
static const String checkEmail = '/invite-user/check-email';
|
||||
static const String getUsers = '/projects/${projectUuid}/user';
|
||||
static const String getUserById = '/projects/${projectUuid}/user/{userUuid}';
|
||||
static const String getUsers = '/projects/{projectId}/user';
|
||||
static const String getUserById = '/projects/{projectId}/user/{userUuid}';
|
||||
static const String editUser = '/invite-user/{inviteUserUuid}';
|
||||
static const String deleteUser = '/invite-user/{inviteUserUuid}';
|
||||
static const String changeUserStatus = '/invite-user/{invitedUserUuid}/disable';
|
||||
|
@ -258,6 +258,7 @@ class Assets {
|
||||
static const String doorSensor = 'assets/icons/door_sensor.svg';
|
||||
|
||||
static const String delete = 'assets/icons/delete.svg';
|
||||
static const String deleteSpaceModel = 'assets/icons/delete_space_model.svg';
|
||||
static const String edit = 'assets/icons/edit.svg';
|
||||
static const String editSpace = 'assets/icons/edit_space.svg';
|
||||
//assets/icons/routine/tab_to_run.svg
|
||||
|
@ -40,4 +40,5 @@ class StringsManager {
|
||||
static const String firstLaunch = "firstLaunch";
|
||||
static const String deleteScene = 'Delete Scene';
|
||||
static const String deleteAutomation = 'Delete Automation';
|
||||
static const String projectKey = 'selected_project_uuid';
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
@ -218,7 +220,7 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
AuthBloc.logout(context);
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: SizedBox(
|
||||
|
Reference in New Issue
Block a user