Compare commits

..

23 Commits

Author SHA1 Message Date
9f75ce817e added space model delete to bloc and api 2025-02-25 21:31:40 +04:00
aa23daa0b4 added DeleteSpaceModelDialog into SpaceModelCardWidget for delete 2025-02-25 21:31:25 +04:00
61f0c3ad2b DeleteSpaceModelDialog into a separate widget 2025-02-25 21:30:27 +04:00
27fef7ddaa Pulled latest changes 2025-02-20 12:55:07 +03:00
010176cc25 Added clear data and cached events in space tree 2025-02-20 12:53:59 +03:00
d08a1d1037 Merge pull request #100 from SyncrowIOT/bugfix/fix-get-all-device-endpoint
fixed device endpoint
2025-02-20 13:33:55 +04:00
e634154fb3 fixed device endpoint 2025-02-20 13:31:31 +04:00
c0f59aba61 Merge pull request #98 from SyncrowIOT:SP-1186-FE-Cursor-Resets-After-Each-Character-When-Creating-a-Tag
fixed text theme of tag list
2025-02-20 11:48:36 +04:00
7ee7681e09 fixed theme 2025-02-20 11:47:58 +04:00
57c5f4752c fixed theme 2025-02-20 11:36:08 +04:00
ad4f2ae382 Merge pull request #96 from SyncrowIOT/SP-1186-FE-Cursor-Resets-After-Each-Character-When-Creating-a-Tag
fixed cursor issue
2025-02-20 11:29:03 +04:00
eafb811d2e fixed cursor issue 2025-02-20 11:26:30 +04:00
2d0dcc41df Merge pull request #93 from SyncrowIOT/bugfix/fix-get-user-endpoint
change endpoint
2025-02-19 17:54:19 +04:00
d89e3fac8e change endpoint 2025-02-19 17:53:20 +04:00
25acd67351 Bug fixes in the side tree 2025-02-19 02:13:14 +03:00
0c2a092f4d Added side tree to space model 2025-02-18 12:31:43 +03:00
b968b5a6eb Merge pull request #92 from SyncrowIOT/bugfix/change-project-cubit
Bugfix/change-project-cubit
2025-02-18 13:22:12 +04:00
05edc7641a removed project cubit from all classes 2025-02-18 12:56:51 +04:00
b8204f1015 changed project class to use shared preference 2025-02-18 12:56:25 +04:00
d87fec796b Merge pull request #91 from SyncrowIOT/add_space_name
spaceName
2025-02-17 12:56:47 +03:00
b00b0c82dc spaceName 2025-02-17 12:36:04 +03:00
0aa029a2fc Removed static space id and community id in the routine 2025-02-17 03:32:40 +03:00
dec3a25639 Merge pull request #90 from SyncrowIOT/feat/use-project-uuid-instead-of-hardcode
Feat/use project UUID instead of hardcode
2025-02-17 01:11:53 +03:00
51 changed files with 849 additions and 498 deletions

View 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

View File

@ -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,13 +48,16 @@ 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();
_isOpen = false;
if (_isOpen && _overlayEntry != null) {
_overlayEntry!.remove();
_overlayEntry = null;
_isOpen = false;
}
}
OverlayEntry _createOverlayEntry() {
@ -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,40 +80,44 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
elevation: 4.0,
child: Container(
color: ColorsManager.whiteColors,
constraints: const BoxConstraints(
maxHeight: 200.0,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: _filteredItems.length,
itemBuilder: (context, index) {
final item = _filteredItems[index];
return Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ColorsManager.lightGrayBorderColor,
width: 1.0,
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(
bottom: BorderSide(
color: ColorsManager.lightGrayBorderColor,
width: 1.0,
),
),
),
),
),
child: ListTile(
title: Text(item,
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(
color: ColorsManager.textPrimaryColor)),
onTap: () {
_controller.text = item;
widget.onSelected(item);
setState(() {
_filteredItems
.remove(item); // Remove selected item
});
_closeDropdown();
},
),
child: ListTile(
title: Text(item,
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(
color: ColorsManager
.textPrimaryColor)),
onTap: () {
_controller.text = item;
widget.onSelected(item);
setState(() {
_filteredItems
.remove(item); // Remove selected item
});
_closeDropdown();
},
),
);
},
);
},
),
@ -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),
),
],
),
),

View File

@ -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,

View File

@ -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();
}
}

View File

@ -2,10 +2,8 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.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_cubit.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
@ -15,25 +13,22 @@ 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 {
try {
const environment =
String.fromEnvironment('FLAVOR', defaultValue: 'development');
const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development');
await dotenv.load(fileName: '.env.$environment');
WidgetsFlutterBinding.ensureInitialized();
initialSetup();
} catch (_) {}
final storage = FlutterSecureStorage();
final projectCubit = ProjectCubit(storage);
runApp(MyApp(projectCubit: projectCubit));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final ProjectCubit projectCubit;
MyApp({super.key, required this.projectCubit});
MyApp({super.key});
final GoRouter _router = GoRouter(
initialLocation: RoutesConst.auth,
@ -54,17 +49,15 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (context) => projectCubit),
BlocProvider(
create: (context) => HomeBloc(projectCubit)..add(const FetchUserInfo())),
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
BlocProvider<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(projectCubit),
create: (context) => VisitorPasswordBloc(),
),
BlocProvider<RoutineBloc>(
create: (context) => RoutineBloc(projectCubit),
create: (context) => RoutineBloc(),
),
BlocProvider<SpaceTreeBloc>(
create: (context) => SpaceTreeBloc(projectCubit)..add(InitialEvent()),
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
),
],
child: MaterialApp.router(
@ -77,6 +70,8 @@ class MyApp extends StatelessWidget {
PointerDeviceKind.unknown,
},
),
key: NavigationService.navigatorKey,
// scaffoldMessengerKey: NavigationService.snackbarKey,
theme: myTheme,
routerConfig: _router,
));

View File

@ -3,18 +3,18 @@ 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_cubit.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';
import 'package:syncrow_web/utils/constants/app_enum.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 AccessBloc extends Bloc<AccessEvent, AccessState> {
final ProjectCubit projectCubit;
AccessBloc(this.projectCubit) : super((AccessInitial())) {
AccessBloc() : super((AccessInitial())) {
on<FetchTableData>(_onFetchTableData);
on<SelectTime>(selectTime);
on<FilterDataEvent>(_filterData);
@ -34,10 +34,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> _onFetchTableData(
FetchTableData event, Emitter<AccessState> emit) async {
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
emit(AccessLoaded());
data = await AccessMangApi()
.fetchVisitorPassword(projectUuid ?? TempConst.projectId);
data = await AccessMangApi().fetchVisitorPassword(projectUuid);
filteredData = data;
updateTabsCount();
emit(TableLoaded(data));

View File

@ -3,7 +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_cubit.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';
@ -28,7 +28,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
final isLargeScreen = isLargeScreenSize(context);
final isSmallScreen = isSmallScreenSize(context);
final isHalfMediumScreen = isHafMediumScreenSize(context);
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
final padding =
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
return WebScaffold(
enableMenuSidebar: false,
@ -40,7 +41,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
),
rightBody: const NavigateHomeGridView(),
scaffoldBody: BlocProvider(
create: (BuildContext context) => AccessBloc(context.read<ProjectCubit>())..add(FetchTableData()),
create: (BuildContext context) =>
AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
@ -94,11 +96,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
return [
item.passwordName,
item.passwordType.value,
accessBloc.timestampToDate(item.effectiveTime),
accessBloc.timestampToDate(item.invalidTime),
accessBloc
.timestampToDate(item.effectiveTime),
accessBloc
.timestampToDate(item.invalidTime),
item.deviceName.toString(),
item.authorizerEmail.toString(),
accessBloc.timestampToDate(item.invalidTime),
accessBloc
.timestampToDate(item.invalidTime),
item.passwordStatus.value,
];
}).toList(),
@ -109,7 +114,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
})));
}
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
Wrap _buildVisitorAdminPasswords(
BuildContext context, AccessBloc accessBloc) {
return Wrap(
spacing: 10,
runSpacing: 10,
@ -135,7 +141,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
borderRadius: 8,
child: Text(
'Create Visitor Password ',
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
style: context.textTheme.titleSmall!
.copyWith(color: Colors.white, fontSize: 12),
)),
),
// Container(
@ -173,8 +180,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
description: '',
onSubmitted: (value) {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
emailAuthorizer:
accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@ -192,8 +201,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
description: '',
onSubmitted: (value) {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
emailAuthorizer:
accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@ -222,7 +233,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
onSearch: () {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@ -250,8 +262,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
description: '',
onSubmitted: (value) {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
emailAuthorizer:
accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@ -275,7 +289,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
onSearch: () {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));

View File

@ -9,10 +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_cubit.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> {
@ -32,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>();
@ -50,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(
@ -88,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));
}
});
}
@ -99,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(
@ -116,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());
}
@ -131,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 /////////////////////////////////////
@ -183,15 +179,13 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
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,13 +432,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(LoginInitial());
}
static Future<void> logout(
BuildContext context, ProjectCubit projectCubit) async {
static Future<void> logout(BuildContext context) async {
final storage = FlutterSecureStorage();
await storage.delete(key: ProjectCubit.projectKey);
projectCubit.clearProjectUUID();
ProjectManager.clearProjectUUID();
context.read<SpaceTreeBloc>().add(ClearAllData());
storage.deleteAll();
}
}

View File

@ -1,19 +0,0 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class ProjectCubit extends Cubit<String?> {
final FlutterSecureStorage storage;
static const String projectKey = "selected_project_uuid";
ProjectCubit(this.storage) : super(null);
Future<void> setProjectUUID(String newUUID) async {
await storage.write(key: projectKey, value: newUUID);
emit(newUUID);
}
Future<void> clearProjectUUID() async {
await storage.delete(key: projectKey);
emit(null);
}
}

View 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);
}
}

View File

@ -1,11 +1,13 @@
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_cubit.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';
@ -22,9 +24,8 @@ class DeviceManagementBloc
String currentProductName = '';
String? currentCommunity;
String? currentUnitName;
final ProjectCubit projectCubit;
DeviceManagementBloc(this.projectCubit) : super(DeviceManagementInitial()) {
DeviceManagementBloc() : super(DeviceManagementInitial()) {
on<FetchDevices>(_onFetchDevices);
on<FilterDevices>(_onFilterDevices);
on<SelectedFilterChanged>(_onSelectedFilterChanged);
@ -42,18 +43,18 @@ class DeviceManagementBloc
List<AllDevicesModel> devices = [];
_devices.clear();
var spaceBloc = event.context.read<SpaceTreeBloc>();
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
if (spaceBloc.state.selectedCommunities.isEmpty) {
devices = await DevicesManagementApi()
.fetchDevices('', '', projectUuid ?? TempConst.projectId);
.fetchDevices('', '', projectUuid );
} else {
for (var community in spaceBloc.state.selectedCommunities) {
List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
for (var space in spacesList) {
devices.addAll(await DevicesManagementApi().fetchDevices(
community, space, projectUuid ?? TempConst.projectId));
community, space, projectUuid));
}
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
@ -20,7 +20,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => DeviceManagementBloc(context.read<ProjectCubit>())..add(FetchDevices(context)),
create: (context) =>
DeviceManagementBloc()..add(FetchDevices(context)),
),
],
child: WebScaffold(
@ -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',

View File

@ -2,17 +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_cubit.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;
@ -22,9 +24,8 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
UserModel? user;
String terms = '';
String policy = '';
final ProjectCubit projectCubit;
HomeBloc(this.projectCubit) : super((HomeInitial())) {
HomeBloc() : super((HomeInitial())) {
// on<CreateNewNode>(_createNode);
on<FetchUserInfo>(_fetchUserInfo);
on<FetchTermEvent>(_fetchTerms);
@ -50,12 +51,12 @@ 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) {
projectCubit.setProjectUUID(user!.project!.uuid);
await ProjectManager.setProjectUUID(user!.project!.uuid);
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
}
add(FetchTermEvent());
add(FetchPolicyEvent());
@ -91,12 +92,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) {
@ -120,6 +119,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,
@ -129,6 +129,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,
@ -138,6 +139,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);

View File

@ -3,7 +3,7 @@ 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_cubit.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';
@ -164,8 +164,7 @@ class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
children: [
InkWell(
onTap: () {
final projectCubit = BlocProvider.of<ProjectCubit>(context);
AuthBloc.logout(context, projectCubit);
AuthBloc.logout(context);
context.go(RoutesConst.auth);
},
child: const Text("Cancel"),

View File

@ -1,6 +1,6 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
@ -13,12 +13,12 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model
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/constants/strings_manager.dart';
import 'package:syncrow_web/utils/constants/temp_const.dart';
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
class UsersBloc extends Bloc<UsersEvent, UsersState> {
final ProjectCubit projectCubit;
UsersBloc(this.projectCubit) : super(UsersInitial()) {
UsersBloc() : super(UsersInitial()) {
on<CheckStepStatus>(isCompleteBasicsFun);
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
on<SearchAnode>(searchTreeNode);
@ -78,10 +78,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
Future<List<SpaceModel>> _fetchSpacesForCommunity(
String communityUuid) async {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
return await CommunitySpaceManagementApi()
.getSpaceHierarchy(communityUuid, projectUuid ?? TempConst.projectId);
.getSpaceHierarchy(communityUuid, projectUuid);
}
List<TreeNode> updatedCommunities = [];
@ -91,9 +91,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
try {
emit(UsersLoadingState());
final projectUuid = projectCubit.state;
List<CommunityModel> communities = await CommunitySpaceManagementApi()
.fetchCommunities(projectUuid ?? TempConst.projectId);
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
List<CommunityModel> communities =
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
communityIds = communities.map((community) => community.uuid).toList();
updatedCommunities = await Future.wait(
communities.map((community) async {
@ -336,7 +337,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
emit(UsersLoadingState());
List<String> selectedIds = getSelectedIds(updatedCommunities)
@ -351,7 +352,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
phoneNumber: phoneController.text,
roleUuid: roleSelected,
spaceUuids: selectedIds,
projectUuid: projectUuid ?? TempConst.projectId);
projectUuid: projectUuid);
if (res) {
showCustomDialog(
@ -386,7 +387,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
List<String> selectedIds = getSelectedIds(updatedCommunities)
.where((id) => !communityIds.contains(id))
.toList();
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
bool res = await UserPermissionApi().editInviteUser(
userId: event.userId,
@ -396,7 +397,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
phoneNumber: phoneController.text,
roleUuid: roleSelected,
spaceUuids: selectedIds,
projectUuid: projectUuid ?? TempConst.projectId);
projectUuid: projectUuid);
if (res == true) {
showCustomDialog(
barrierDismissible: false,
@ -501,11 +502,11 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
emit(UsersLoadingState());
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
if (event.uuid?.isNotEmpty ?? false) {
final res = await UserPermissionApi()
.fetchUserById(event.uuid, projectUuid ?? TempConst.projectId);
final res =
await UserPermissionApi().fetchUserById(event.uuid, projectUuid);
if (res != null) {
// Populate the text controllers

View File

@ -1,7 +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_cubit.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';
@ -24,7 +24,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => UsersBloc(context.read<ProjectCubit>())
create: (BuildContext context) => UsersBloc()
..add(const LoadCommunityAndSpacesEvent())
..add(const RoleEvent()),
child: BlocConsumer<UsersBloc, UsersState>(

View File

@ -1,7 +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_cubit.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';
@ -22,7 +22,7 @@ class TreeView extends StatelessWidget {
final _blocRole = BlocProvider.of<UsersBloc>(context);
debugPrint('TreeView constructed with userId = $userId');
return BlocProvider(
create: (_) => UsersBloc(context.read<ProjectCubit>()),
create: (_) => UsersBloc(),
// ..add(const LoadCommunityAndSpacesEvent()),
child: BlocConsumer<UsersBloc, UsersState>(
listener: (context, state) {

View File

@ -1,7 +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_cubit.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,7 +25,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => UsersBloc(context.read<ProjectCubit>())
create: (BuildContext context) => UsersBloc()
..add(const LoadCommunityAndSpacesEvent())
..add(const RoleEvent())
..add(GetUserByIdEvent(uuid: widget.userId)),

View File

@ -1,17 +1,16 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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/temp_const.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> {
final ProjectCubit _projectCubit;
UserTableBloc(this._projectCubit) : super(TableInitial()) {
UserTableBloc() : super(TableInitial()) {
on<GetUsers>(_getUsers);
on<ChangeUserStatus>(_changeUserStatus);
on<SortUsersByNameAsc>(_toggleSortUsersByNameAsc);
@ -50,13 +49,12 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
emit(UsersLoadingState());
try {
final projectUuid = _projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
roleTypes.clear();
jobTitle.clear();
createdBy.clear();
users = await UserPermissionApi()
.fetchUsers(projectUuid ?? TempConst.projectId);
users = await UserPermissionApi().fetchUsers(projectUuid);
users.sort((a, b) {
final dateA = _parseDateTime(a.createdDate);
final dateB = _parseDateTime(b.createdDate);
@ -103,13 +101,11 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
Future<void> _changeUserStatus(
ChangeUserStatus event, Emitter<UserTableState> emit) async {
try {
final projectUuid = _projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
emit(UsersLoadingState());
bool res = await UserPermissionApi().changeUserStatusById(
event.userId,
event.newStatus == "disabled" ? false : true,
projectUuid ?? TempConst.projectId);
bool res = await UserPermissionApi().changeUserStatusById(event.userId,
event.newStatus == "disabled" ? false : true, projectUuid);
if (res == true) {
add(const GetUsers());
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
@ -77,7 +77,7 @@ class RolesAndPermissionPage extends StatelessWidget {
],
),
scaffoldBody: BlocProvider<UserTableBloc>(
create: (context) => UserTableBloc(context.read<ProjectCubit>())..add(const GetUsers()),
create: (context) => UserTableBloc()..add(const GetUsers()),
child: UsersPage(),
)
// _blocRole.tapSelect == false

View File

@ -3,7 +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_cubit.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';
@ -11,23 +12,25 @@ 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> {
final ProjectCubit projectCubit;
RoutineBloc(this.projectCubit) : super(const RoutineState()) {
RoutineBloc() : super(const RoutineState()) {
on<AddToIfContainer>(_onAddToIfContainer);
on<AddToThenContainer>(_onAddToThenContainer);
on<LoadScenes>(_onLoadScenes);
@ -62,8 +65,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
routineTab: event.isRoutineTab, createRoutineView: false));
add(ResetRoutineState());
if (event.isRoutineTab) {
add(LoadScenes(spaceId, communityId));
add(LoadAutomation(spaceId));
add(const LoadScenes());
add(const LoadAutomation());
}
}
@ -169,18 +172,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
Future<void> _onLoadScenes(
LoadScenes event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
List<ScenesModel> scenes = [];
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
spaceId = event.spaceId;
communityId = event.communityId;
List<ScenesModel> scenes = [];
if (communityId.isNotEmpty && spaceId.isNotEmpty) {
scenes = await SceneApi.getScenes(event.spaceId, event.communityId, projectUuid ?? TempConst.projectId);
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,
@ -191,19 +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 {
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,
@ -215,7 +226,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
loadAutomationErrorMessage: 'Failed to load automations',
errorMessage: '',
loadScenesErrorMessage: '',
automations: []));
automations: automations));
}
}
@ -302,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 ?? '',
@ -314,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,
@ -428,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(
@ -445,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,
@ -821,18 +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) {
@ -861,9 +883,20 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true));
try {
final projectUuid = projectCubit.state;
final devices = await DevicesManagementApi()
.fetchDevices('', '', projectUuid ?? TempConst.projectId);
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) {
@ -944,8 +977,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
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,
@ -1056,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(
@ -1074,8 +1110,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
if (result['success']) {
add(ResetRoutineState());
add(LoadAutomation(spaceId));
add(LoadScenes(spaceId, communityId));
add(LoadAutomation());
add(LoadScenes());
} else {
emit(state.copyWith(
isLoading: false,

View File

@ -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 {

View File

@ -20,7 +20,7 @@ class _RoutinesViewState extends State<RoutinesView> {
@override
void initState() {
super.initState();
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
// context.read<RoutineBloc>().add(FetchDevicesInRoutine());
}
@override
@ -32,9 +32,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 +62,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 +71,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,

View File

@ -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

View File

@ -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>(

View File

@ -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

View File

@ -1,39 +1,35 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
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/utils/constants/temp_const.dart';
class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
final ProjectCubit projectCubit;
SpaceTreeBloc(this.projectCubit) : super(const SpaceTreeState()) {
SpaceTreeBloc() : super(const SpaceTreeState()) {
on<InitialEvent>(_fetchSpaces);
on<OnCommunityExpanded>(_onCommunityExpanded);
on<OnSpaceExpanded>(_onSpaceExpanded);
on<OnCommunitySelected>(_onCommunitySelected);
on<OnSpaceSelected>(_onSpaceSelected);
on<SearchQueryEvent>(_onSearch);
on<ClearAllData>(_clearAllData);
on<ClearCachedData>(_clearCachedData);
}
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
emit(SpaceTreeLoadingState());
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
List<CommunityModel> communities = await CommunitySpaceManagementApi()
.fetchCommunities(projectUuid ?? TempConst.projectId);
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, projectUuid ?? TempConst.projectId);
List<SpaceModel> spaces =
await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid);
return CommunityModel(
uuid: community.uuid,
@ -48,19 +44,15 @@ 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 {
_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);
@ -92,17 +84,13 @@ 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> childrenIds = _getAllChildIds(event.children);
@ -133,12 +121,9 @@ 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> childrenIds = _getAllChildIds(event.children);
bool isChildSelected = false;
@ -153,16 +138,14 @@ 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);
if (childrenIds.isNotEmpty) {
updatedSelectedSpaces.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);
}
}
@ -182,20 +165,30 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
updatedSoldChecks.remove(event.spaceId);
List<String> parents =
_getThePathToChild(event.communityId, event.spaceId);
if (!_parentSelected(parents, updatedSelectedSpaces)) {
_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);
}
}
if (!_anySpacesSelectedInCommunity(
event.communityModel, updatedSelectedSpaces, updatedSoldChecks)) {
updatedSelectedCommunities.remove(event.communityModel.uuid);
}
}
}
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
communityAndSpaces[event.communityModel.uuid] = updatedSelectedSpaces;
emit(state.copyWith(
selectedCommunities: updatedSelectedCommunities,
selectedCommunities: updatedSelectedCommunities.toSet().toList(),
selectedSpaces: updatedSelectedSpaces,
soldCheck: updatedSoldChecks,
selectedCommunityAndSpaces: communityAndSpaces));
@ -205,12 +198,24 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
}
}
_parentSelected(List<String> parents, List<String> selectedSpaces) {
for (String space in parents) {
if (selectedSpaces.contains(space)) {
return true;
_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;
}
@ -221,18 +226,54 @@ 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));
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'));
}
@ -241,8 +282,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;
}
@ -253,22 +294,26 @@ 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);
if (result) {
return result;
}
}
List<String> ids = _getAllChildIds(community.spaces);
for (var id in ids) {
result = selectedSpaces.contains(id) || partialCheckedList.contains(id);
if (result) {
return result;
}
}
return result;
@ -291,8 +336,7 @@ 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 ?? '');
@ -313,4 +357,9 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
ids.removeLast();
return [];
}
@override
Future<void> close() async {
super.close();
}
}

View File

@ -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,7 @@ class SearchQueryEvent extends SpaceTreeEvent {
@override
List<Object> get props => [searchQuery];
}
class ClearAllData extends SpaceTreeEvent {}
class ClearCachedData extends SpaceTreeEvent {}

View File

@ -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
];
}

View File

@ -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();
}

View File

@ -1,5 +1,8 @@
import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.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';
@ -15,19 +18,19 @@ 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/strings_manager.dart';
import 'package:syncrow_web/utils/constants/temp_const.dart';
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
class SpaceManagementBloc
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
final CommunitySpaceManagementApi _api;
final ProductApi _productApi;
final SpaceModelManagementApi _spaceModelApi;
final ProjectCubit projectCubit;
List<ProductModel>? _cachedProducts;
SpaceManagementBloc(
this._api, this._productApi, this._spaceModelApi, this.projectCubit)
SpaceManagementBloc(this._api, this._productApi, this._spaceModelApi)
: super(SpaceManagementInitial()) {
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
on<UpdateSpacePositionEvent>(_onUpdateSpacePosition);
@ -43,17 +46,23 @@ class SpaceManagementBloc
on<SpaceModelLoadEvent>(_onLoadSpaceModel);
}
void _logEvent(String eventName) {
log('Event Triggered: $eventName');
}
void _onUpdateCommunity(
UpdateCommunityEvent event,
Emitter<SpaceManagementState> emit,
) async {
_logEvent('UpdateCommunityEvent');
final previousState = state;
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
emit(SpaceManagementLoading());
final success = await _api.updateCommunity(
event.communityUuid, event.name, projectUuid ?? TempConst.projectId);
event.communityUuid, event.name, projectUuid);
if (success) {
if (previousState is SpaceManagementLoaded) {
final updatedCommunities =
@ -85,7 +94,7 @@ class SpaceManagementBloc
Future<List<SpaceTemplateModel>> fetchSpaceModels(
SpaceManagementState previousState) async {
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
List<SpaceTemplateModel> allSpaces = [];
List<SpaceTemplateModel> prevSpaceModels = [];
@ -104,7 +113,7 @@ class SpaceManagementBloc
while (hasNext) {
final spaces = await _spaceModelApi.listSpaceModels(
page: page, projectId: projectUuid ?? TempConst.projectId);
page: page, projectId: projectUuid);
if (spaces.isNotEmpty) {
allSpaces.addAll(spaces);
page++;
@ -113,7 +122,7 @@ class SpaceManagementBloc
}
}
prevSpaceModels = await _spaceModelApi.listSpaceModels(
page: 1, projectId: projectUuid ?? TempConst.projectId);
page: 1, projectId: projectUuid);
}
return allSpaces;
@ -142,10 +151,9 @@ class SpaceManagementBloc
Future<List<SpaceModel>> _fetchSpacesForCommunity(
String communityUuid) async {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
return await _api.getSpaceHierarchy(
communityUuid, projectUuid ?? TempConst.projectId);
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
}
Future<void> _onNewCommunity(
@ -176,7 +184,7 @@ class SpaceManagementBloc
BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
try {
final previousState = state;
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
var prevSpaceModels = await fetchSpaceModels(previousState);
@ -191,8 +199,7 @@ class SpaceManagementBloc
return;
}
final communities =
await _api.fetchCommunities(projectUuid ?? TempConst.projectId);
final communities = await _api.fetchCommunities(projectUuid);
final updatedCommunities =
await Future.wait(communities.map((community) async {
final spaces = await _fetchSpacesForCommunity(community.uuid);
@ -222,14 +229,16 @@ class SpaceManagementBloc
LoadCommunityAndSpacesEvent event,
Emitter<SpaceManagementState> emit,
) async {
_logEvent('LoadCommunityAndSpacesEvent');
var prevState = state;
emit(SpaceManagementLoading());
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
_onloadProducts();
List<CommunityModel> communities =
await _api.fetchCommunities(projectUuid ?? TempConst.projectId);
await _api.fetchCommunities(projectUuid);
List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async {
@ -263,10 +272,10 @@ class SpaceManagementBloc
) async {
try {
emit(SpaceManagementLoading());
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
final success = await _api.deleteCommunity(
event.communityUuid, projectUuid ?? TempConst.projectId);
final success =
await _api.deleteCommunity(event.communityUuid, projectUuid);
if (success) {
add(LoadCommunityAndSpacesEvent());
} else {
@ -291,9 +300,10 @@ class SpaceManagementBloc
emit(SpaceManagementLoading());
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
CommunityModel? newCommunity = await _api.createCommunity(
event.name, event.description, projectUuid ?? TempConst.projectId);
event.name, event.description, projectUuid);
var prevSpaceModels = await fetchSpaceModels(previousState);
if (newCommunity != null) {
@ -436,7 +446,7 @@ class SpaceManagementBloc
Future<List<SpaceModel>> saveSpacesHierarchically(
List<SpaceModel> spaces, String communityUuid) async {
final orderedSpaces = flattenHierarchy(spaces);
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
final parentsToDelete = orderedSpaces.where((space) =>
space.status == SpaceStatus.deleted &&
@ -445,8 +455,7 @@ class SpaceManagementBloc
for (var parent in parentsToDelete) {
try {
if (parent.uuid != null) {
await _api.deleteSpace(
communityUuid, parent.uuid!, projectUuid ?? TempConst.projectId);
await _api.deleteSpace(communityUuid, parent.uuid!, projectUuid);
}
} catch (e) {
rethrow;
@ -459,8 +468,8 @@ class SpaceManagementBloc
if (space.uuid != null && space.uuid!.isNotEmpty) {
List<TagModelUpdate> tagUpdates = [];
final prevSpace = await _api.getSpace(
communityUuid, space.uuid!, projectUuid ?? TempConst.projectId);
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;
@ -539,7 +548,7 @@ class SpaceManagementBloc
subspaces: subspaceUpdates,
tags: tagUpdates,
direction: space.incomingConnection?.direction,
projectId: projectUuid ?? TempConst.projectId);
projectId: projectUuid);
} else {
// Call create if the space does not have a UUID
final List<CreateTagBodyModel> tagBodyModels = space.tags != null
@ -568,7 +577,7 @@ class SpaceManagementBloc
spaceModelUuid: space.spaceModel?.uuid,
tags: tagBodyModels,
subspaces: createSubspaceBodyModels,
projectId: projectUuid ?? TempConst.projectId);
projectId: projectUuid);
space.uuid = response?.uuid;
}
} catch (e) {
@ -608,10 +617,10 @@ class SpaceManagementBloc
emit(SpaceManagementLoading());
try {
var prevState = state;
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
List<CommunityModel> communities =
await _api.fetchCommunities(projectUuid ?? TempConst.projectId);
await _api.fetchCommunities(projectUuid);
List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async {

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.dart';
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.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';
@ -33,7 +32,6 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
_api,
_productApi,
_spaceModelApi,
context.read<ProjectCubit>(),
)..add(LoadCommunityAndSpacesEvent()),
),
BlocProvider(

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
@ -75,20 +75,14 @@ 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(
widget.shouldNavigateToSpaceModelPage
? Row(
children: [
SizedBox(width: 300, child: SpaceTreeView(onSelect: () {})),
Expanded(
child: BlocProvider(
create: (context) => SpaceModelBloc(
api: SpaceModelManagementApi(),
projectCubit: context.read<ProjectCubit>(),
initialSpaceModels: _spaceModels,
),
child: SpaceModelPage(
@ -96,8 +90,17 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
onSpaceModelsUpdated: _onSpaceModelsUpdated,
),
),
)
: CommunityStructureArea(
),
],
)
: Row(
children: [
SidebarWidget(
communities: widget.communities,
selectedSpaceUuid:
widget.selectedSpace?.uuid ?? widget.selectedCommunity?.uuid ?? '',
),
CommunityStructureArea(
selectedCommunity: widget.selectedCommunity,
selectedSpace: widget.selectedSpace,
spaces: widget.selectedCommunity?.spaces ?? [],
@ -105,8 +108,8 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
communities: widget.communities,
spaceModels: _spaceModels,
),
],
),
],
),
const GradientCanvasBorderWidget(),
],
);

View File

@ -1,5 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
@ -9,20 +9,21 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.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/strings_manager.dart';
import 'package:syncrow_web/utils/constants/temp_const.dart';
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
class CreateSpaceModelBloc
extends Bloc<CreateSpaceModelEvent, CreateSpaceModelState> {
SpaceTemplateModel? _space;
final SpaceModelManagementApi _api;
final ProjectCubit _projectCubit;
CreateSpaceModelBloc(this._api, this._projectCubit)
: super(CreateSpaceModelInitial()) {
CreateSpaceModelBloc(this._api) : super(CreateSpaceModelInitial()) {
on<CreateSpaceTemplate>((event, emit) async {
try {
final projectUuid = _projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
late SpaceTemplateModel spaceTemplate = event.spaceTemplate;
final tagBodyModels =
@ -45,8 +46,8 @@ class CreateSpaceModelBloc
tags: tagBodyModels,
subspaceModels: subspaceTemplateBodyModels);
final newSpaceTemplate = await _api.createSpaceModel(
spaceModelBody, projectUuid ?? TempConst.projectId);
final newSpaceTemplate =
await _api.createSpaceModel(spaceModelBody, projectUuid);
spaceTemplate.uuid = newSpaceTemplate?.uuid ?? '';
if (newSpaceTemplate != null) {
@ -207,12 +208,11 @@ class CreateSpaceModelBloc
on<ModifySpaceTemplate>((event, emit) async {
try {
final projectUuid = _projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
if (event.spaceTemplate.uuid != null) {
final prevSpaceModel = await _api.getSpaceModel(
event.spaceTemplate.uuid ?? '',
projectUuid ?? TempConst.projectId);
event.spaceTemplate.uuid ?? '', projectUuid);
final newSpaceModel = event.updatedSpaceTemplate;
String? spaceModelName;
@ -295,8 +295,8 @@ class CreateSpaceModelBloc
tags: tagUpdates,
subspaceModels: subspaceUpdates);
final res = await _api.updateSpaceModel(spaceModelBody,
prevSpaceModel?.uuid ?? '', projectUuid ?? TempConst.projectId);
final res = await _api.updateSpaceModel(
spaceModelBody, prevSpaceModel?.uuid ?? '', projectUuid);
if (res != null) {
emit(CreateSpaceModelLoaded(newSpaceModel));

View File

@ -1,22 +1,20 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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';
import 'package:syncrow_web/services/space_model_mang_api.dart';
import 'package:syncrow_web/utils/constants/temp_const.dart';
class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
final SpaceModelManagementApi api;
final ProjectCubit projectCubit;
SpaceModelBloc({
required this.api,
required this.projectCubit,
required List<SpaceTemplateModel> initialSpaceModels,
}) : super(SpaceModelLoaded(spaceModels: initialSpaceModels)) {
on<CreateSpaceModel>(_onCreateSpaceModel);
on<UpdateSpaceModel>(_onUpdateSpaceModel);
on<DeleteSpaceModel>(_onDeleteSpaceModel);
}
Future<void> _onCreateSpaceModel(
@ -25,9 +23,10 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
if (currentState is SpaceModelLoaded) {
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
final newSpaceModel = await api.getSpaceModel(
event.newSpaceModel.uuid ?? '', projectUuid ?? TempConst.projectId);
event.newSpaceModel.uuid ?? '', projectUuid);
if (newSpaceModel != null) {
final updatedSpaceModels =
@ -46,10 +45,10 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
final currentState = state;
if (currentState is SpaceModelLoaded) {
try {
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
final newSpaceModel = await api.getSpaceModel(
event.spaceModelUuid ?? '', projectUuid ?? TempConst.projectId);
final newSpaceModel =
await api.getSpaceModel(event.spaceModelUuid, projectUuid);
if (newSpaceModel != null) {
final updatedSpaceModels = currentState.spaceModels.map((model) {
return model.uuid == event.spaceModelUuid ? newSpaceModel : model;
@ -61,4 +60,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()));
}
}
}
}

View File

@ -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];
}

View File

@ -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,
),
));
},
),

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_cubit.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/model/product_model.dart';
@ -53,7 +52,6 @@ class CreateSpaceModelDialog extends StatelessWidget {
create: (_) {
final bloc = CreateSpaceModelBloc(
_spaceModelApi,
context.read<ProjectCubit>(),
);
if (spaceModel != null) {
bloc.add(UpdateSpaceTemplate(spaceModel!, otherSpaceModels));

View File

@ -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'),
),
),
],
),
],
);
}
}

View File

@ -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/common/buttons/cancel_button.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.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) {
@ -34,7 +51,7 @@ class SpaceModelCardWidget extends StatelessWidget {
return LayoutBuilder(
builder: (context, constraints) {
bool showOnlyName = constraints.maxWidth < 250;
return Container(
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
@ -51,14 +68,50 @@ class SpaceModelCardWidget extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
model.modelName,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
Row(
children: [
Expanded(
child: Text(
model.modelName,
style:
Theme.of(context).textTheme.headlineMedium?.copyWith(
color: Colors.black,
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
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),
@ -117,4 +170,22 @@ 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 ?? ''),
);
}
},
);
},
);
}
}

View File

@ -3,7 +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_cubit.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';
@ -14,14 +14,15 @@ 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> {
final ProjectCubit projectCubit;
VisitorPasswordBloc(this.projectCubit) : super(VisitorPasswordInitial()) {
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
on<SelectUsageFrequency>(selectUsageFrequency);
on<FetchDevice>(_onFetchDevice);
on<SelectPasswordType>(selectAccessType);
@ -191,10 +192,9 @@ class VisitorPasswordBloc
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
try {
emit(DeviceLoaded());
final projectUuid = projectCubit.state;
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
data = await AccessMangApi()
.fetchDevices(projectUuid ?? TempConst.projectId);
data = await AccessMangApi().fetchDevices(projectUuid);
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));

View File

@ -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
};
}
}

View File

@ -2,7 +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_cubit.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';
@ -20,7 +20,8 @@ class AddDeviceDialog extends StatelessWidget {
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return BlocProvider(
create: (context) => VisitorPasswordBloc(context.read<ProjectCubit>())..add(FetchDevice()),
create: (context) =>
VisitorPasswordBloc()..add(FetchDevice()),
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
@ -36,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,
@ -69,10 +70,13 @@ class AddDeviceDialog extends StatelessWidget {
),
Text(
'Only online accessible devices can be added',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 12,
color: ColorsManager.grayColor),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 12,
color: ColorsManager.grayColor),
),
],
)),
@ -153,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
},
),
),
@ -173,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) {
@ -194,7 +200,7 @@ class AddDeviceDialog extends StatelessWidget {
item.name.toString(),
item.uuid.toString(),
item.productType.toString(),
'',
item.spaceName.toString(),
item.online.value.toString(),
];
}).toList(),

View File

@ -2,7 +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_cubit.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';
@ -23,7 +23,7 @@ class VisitorPasswordDialog extends StatelessWidget {
Size size = MediaQuery.of(context).size;
var text = Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13);
return BlocProvider(
create: (context) => VisitorPasswordBloc(context.read<ProjectCubit>()),
create: (context) => VisitorPasswordBloc(),
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
listener: (context, state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);

View File

@ -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;
}
}

View File

@ -14,7 +14,7 @@ class UserPermissionApi {
Future<List<RolesUserModel>> fetchUsers(String projectId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getUsers.replaceAll('{projectUuid}', projectId),
path: ApiEndpoints.getUsers.replaceAll('{projectId}', projectId),
showServerMessage: true,
expectedResponseModel: (json) {
debugPrint('fetchUsers Response: $json');

View File

@ -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);
}

View File

@ -25,7 +25,7 @@ abstract class ApiEndpoints {
////// Devices Management ////////////////
static const String getAllDevices = '/projects/{projectId}/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';

View File

@ -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

View File

@ -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';
}

View File

@ -4,7 +4,7 @@ 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_cubit.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';
@ -220,10 +220,7 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
),
GestureDetector(
onTap: () {
final projectCubit =
BlocProvider.of<ProjectCubit>(context);
AuthBloc.logout(context, projectCubit);
AuthBloc.logout(context);
context.go(RoutesConst.auth);
},
child: SizedBox(