diff --git a/assets/icons/add_button_Icon.svg b/assets/icons/add_button_Icon.svg
new file mode 100644
index 00000000..f9b8eae7
--- /dev/null
+++ b/assets/icons/add_button_Icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/back_button_icon.svg b/assets/icons/back_button_icon.svg
new file mode 100644
index 00000000..5cc7b637
--- /dev/null
+++ b/assets/icons/back_button_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/clock_icon.svg b/assets/icons/clock_icon.svg
new file mode 100644
index 00000000..296aa862
--- /dev/null
+++ b/assets/icons/clock_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/no_data_table.svg b/assets/icons/no_data_table.svg
new file mode 100644
index 00000000..c97946a2
--- /dev/null
+++ b/assets/icons/no_data_table.svg
@@ -0,0 +1,24 @@
+
diff --git a/assets/icons/search_icon.svg b/assets/icons/search_icon.svg
new file mode 100644
index 00000000..009efd91
--- /dev/null
+++ b/assets/icons/search_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/x_delete.svg b/assets/icons/x_delete.svg
new file mode 100644
index 00000000..637f2e72
--- /dev/null
+++ b/assets/icons/x_delete.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/4_sceen_switch.svg b/assets/images/4_sceen_switch.svg
new file mode 100644
index 00000000..3765e137
--- /dev/null
+++ b/assets/images/4_sceen_switch.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/images/6_sceen_switch.svg b/assets/images/6_sceen_switch.svg
new file mode 100644
index 00000000..fef2291b
--- /dev/null
+++ b/assets/images/6_sceen_switch.svg
@@ -0,0 +1,12 @@
+
diff --git a/lib/main.dart b/lib/main.dart
index a50d2615..071c7433 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,22 +1,9 @@
import 'package:firebase_core/firebase_core.dart';
-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:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart';
-import 'package:syncrow_web/pages/auth/bloc/auth_bloc.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/create_routine_bloc/create_routine_bloc.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/visitor_password/bloc/visitor_password_bloc.dart';
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';
+import 'package:syncrow_web/syncrow_app.dart';
Future main() async {
try {
@@ -33,59 +20,5 @@ Future main() async {
);
initialSetup();
} catch (_) {}
- runApp(MyApp());
-}
-
-class MyApp extends StatelessWidget {
- MyApp({super.key});
-
- final GoRouter _router = GoRouter(
- initialLocation: RoutesConst.auth,
- routes: AppRoutes.getRoutes(),
- redirect: (context, state) async {
- final checkToken = await AuthBloc.getTokenAndValidate();
- final loggedIn = checkToken == 'Success';
- final goingToLogin = state.uri.toString() == RoutesConst.auth;
-
- if (!loggedIn && !goingToLogin) return RoutesConst.auth;
- if (loggedIn && goingToLogin) return RoutesConst.home;
-
- return null;
- },
- );
-
- @override
- Widget build(BuildContext context) {
- return MultiBlocProvider(
- providers: [
- BlocProvider(
- create: (context) => CreateRoutineBloc(),
- ),
- BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
- BlocProvider(
- create: (context) => VisitorPasswordBloc(),
- ),
- BlocProvider(
- create: (context) => RoutineBloc(),
- ),
- BlocProvider(
- create: (context) => SpaceTreeBloc(),
- ),
- ],
- child: MaterialApp.router(
- debugShowCheckedModeBanner: false,
- scrollBehavior: const MaterialScrollBehavior().copyWith(
- dragDevices: {
- PointerDeviceKind.mouse,
- PointerDeviceKind.touch,
- PointerDeviceKind.stylus,
- PointerDeviceKind.unknown,
- },
- ),
- key: NavigationService.navigatorKey,
- // scaffoldMessengerKey: NavigationService.snackbarKey,
- theme: myTheme,
- routerConfig: _router,
- ));
- }
+ runApp(const SyncrowApp());
}
diff --git a/lib/main_dev.dart b/lib/main_dev.dart
index 284e2f30..49df196f 100644
--- a/lib/main_dev.dart
+++ b/lib/main_dev.dart
@@ -1,22 +1,9 @@
import 'package:firebase_core/firebase_core.dart';
-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:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart';
-import 'package:syncrow_web/pages/auth/bloc/auth_bloc.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/create_routine_bloc/create_routine_bloc.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/visitor_password/bloc/visitor_password_bloc.dart';
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';
+import 'package:syncrow_web/syncrow_app.dart';
Future main() async {
try {
@@ -33,59 +20,5 @@ Future main() async {
);
initialSetup();
} catch (_) {}
- runApp(MyApp());
-}
-
-class MyApp extends StatelessWidget {
- MyApp({super.key});
-
- final GoRouter _router = GoRouter(
- initialLocation: RoutesConst.auth,
- routes: AppRoutes.getRoutes(),
- redirect: (context, state) async {
- final checkToken = await AuthBloc.getTokenAndValidate();
- final loggedIn = checkToken == 'Success';
- final goingToLogin = state.uri.toString() == RoutesConst.auth;
-
- if (!loggedIn && !goingToLogin) return RoutesConst.auth;
- if (loggedIn && goingToLogin) return RoutesConst.home;
-
- return null;
- },
- );
-
- @override
- Widget build(BuildContext context) {
- return MultiBlocProvider(
- providers: [
- BlocProvider(
- create: (context) => CreateRoutineBloc(),
- ),
- BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
- BlocProvider(
- create: (context) => VisitorPasswordBloc(),
- ),
- BlocProvider(
- create: (context) => RoutineBloc(),
- ),
- BlocProvider(
- create: (context) => SpaceTreeBloc(),
- ),
- ],
- child: MaterialApp.router(
- debugShowCheckedModeBanner: false,
- scrollBehavior: const MaterialScrollBehavior().copyWith(
- dragDevices: {
- PointerDeviceKind.mouse,
- PointerDeviceKind.touch,
- PointerDeviceKind.stylus,
- PointerDeviceKind.unknown,
- },
- ),
- key: NavigationService.navigatorKey,
- // scaffoldMessengerKey: NavigationService.snackbarKey,
- theme: myTheme,
- routerConfig: _router,
- ));
- }
+ runApp(const SyncrowApp());
}
diff --git a/lib/main_staging.dart b/lib/main_staging.dart
index 6389c53a..6e0de3e1 100644
--- a/lib/main_staging.dart
+++ b/lib/main_staging.dart
@@ -1,26 +1,16 @@
import 'package:firebase_core/firebase_core.dart';
-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:go_router/go_router.dart';
import 'package:syncrow_web/firebase_options.dart';
-import 'package:syncrow_web/pages/auth/bloc/auth_bloc.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/create_routine_bloc/create_routine_bloc.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/visitor_password/bloc/visitor_password_bloc.dart';
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';
+import 'package:syncrow_web/syncrow_app.dart';
Future main() async {
try {
- const environment = String.fromEnvironment('FLAVOR', defaultValue: 'staging');
+ const environment = String.fromEnvironment(
+ 'FLAVOR',
+ defaultValue: 'staging',
+ );
await dotenv.load(fileName: '.env.$environment');
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
@@ -30,59 +20,5 @@ Future main() async {
);
initialSetup();
} catch (_) {}
- runApp(MyApp());
-}
-
-class MyApp extends StatelessWidget {
- MyApp({super.key});
-
- final GoRouter _router = GoRouter(
- initialLocation: RoutesConst.auth,
- routes: AppRoutes.getRoutes(),
- redirect: (context, state) async {
- final checkToken = await AuthBloc.getTokenAndValidate();
- final loggedIn = checkToken == 'Success';
- final goingToLogin = state.uri.toString() == RoutesConst.auth;
-
- if (!loggedIn && !goingToLogin) return RoutesConst.auth;
- if (loggedIn && goingToLogin) return RoutesConst.home;
-
- return null;
- },
- );
-
- @override
- Widget build(BuildContext context) {
- return MultiBlocProvider(
- providers: [
- BlocProvider(
- create: (context) => CreateRoutineBloc(),
- ),
- BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
- BlocProvider(
- create: (context) => VisitorPasswordBloc(),
- ),
- BlocProvider(
- create: (context) => RoutineBloc(),
- ),
- BlocProvider(
- create: (context) => SpaceTreeBloc(),
- ),
- ],
- child: MaterialApp.router(
- debugShowCheckedModeBanner: false,
- scrollBehavior: const MaterialScrollBehavior().copyWith(
- dragDevices: {
- PointerDeviceKind.mouse,
- PointerDeviceKind.touch,
- PointerDeviceKind.stylus,
- PointerDeviceKind.unknown,
- },
- ),
- key: NavigationService.navigatorKey,
- // scaffoldMessengerKey: NavigationService.snackbarKey,
- theme: myTheme,
- routerConfig: _router,
- ));
- }
+ runApp(const SyncrowApp());
}
diff --git a/lib/pages/access_management/booking_system/data/services/memory_bookable_space_service.dart b/lib/pages/access_management/booking_system/data/services/memory_bookable_space_service.dart
new file mode 100644
index 00000000..034480ec
--- /dev/null
+++ b/lib/pages/access_management/booking_system/data/services/memory_bookable_space_service.dart
@@ -0,0 +1,63 @@
+import 'package:syncrow_web/pages/access_management/booking_system/data/services/remote_calendar_service.dart';
+import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart';
+import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart';
+import 'package:syncrow_web/pages/access_management/booking_system/domain/services/calendar_system_service.dart';
+
+class MemoryCalendarService implements CalendarSystemService {
+ final Map _eventsCache = {};
+
+ @override
+ Future getCalendarEvents({
+ required LoadEventsParam params,
+ }) async {
+ final key = params.generateKey();
+
+ return _eventsCache[key]!;
+ }
+
+ void setEvents(
+ LoadEventsParam param,
+ CalendarEventsResponse events,
+ ) {
+ final key = param.generateKey();
+ _eventsCache[key] = events;
+ }
+
+ void addEvent(LoadEventsParam param, CalendarEventsResponse event) {
+ final key = param.generateKey();
+
+ _eventsCache[key] = event;
+ }
+
+ void clear() {
+ _eventsCache.clear();
+ }
+}
+
+class MemoryCalendarServiceWithRemoteFallback implements CalendarSystemService {
+ final MemoryCalendarService memoryService;
+ final RemoteCalendarService remoteService;
+
+ MemoryCalendarServiceWithRemoteFallback({
+ required this.memoryService,
+ required this.remoteService,
+ });
+
+ @override
+ Future getCalendarEvents({
+ required LoadEventsParam params,
+ }) async {
+ final key = params.generateKey();
+ final doesExistInMemory = memoryService._eventsCache.containsKey(key);
+
+ if (doesExistInMemory) {
+ return memoryService.getCalendarEvents(params: params);
+ } else {
+ final remoteResult =
+ await remoteService.getCalendarEvents(params: params);
+ memoryService.setEvents(params, remoteResult);
+
+ return remoteResult;
+ }
+ }
+}
diff --git a/lib/pages/access_management/booking_system/data/services/remote_bookable_spaces_service.dart b/lib/pages/access_management/booking_system/data/services/remote_bookable_spaces_service.dart
index 3c2610db..5ed71116 100644
--- a/lib/pages/access_management/booking_system/data/services/remote_bookable_spaces_service.dart
+++ b/lib/pages/access_management/booking_system/data/services/remote_bookable_spaces_service.dart
@@ -18,7 +18,7 @@ class RemoteBookableSpacesService implements BookableSystemService {
}) async {
try {
final response = await _httpService.get(
- path: ApiEndpoints.getBookableSpaces,
+ path: ApiEndpoints.bookableSpaces,
queryParameters: {
'page': param.page,
'size': param.size,
diff --git a/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart
index aa3307d3..55a5b0b8 100644
--- a/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart
+++ b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart
@@ -1,4 +1,5 @@
import 'package:dio/dio.dart';
+import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart';
import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart';
import 'package:syncrow_web/pages/access_management/booking_system/domain/services/calendar_system_service.dart';
import 'package:syncrow_web/services/api/api_exception.dart';
@@ -13,147 +14,21 @@ class RemoteCalendarService implements CalendarSystemService {
@override
Future getCalendarEvents({
- required String spaceId,
+ required LoadEventsParam params,
}) async {
+ final month = params.startDate.month.toString().padLeft(2, '0');
+ final year = params.startDate.year.toString();
+
try {
- final response = await _httpService.get(
- path: ApiEndpoints.getCalendarEvents,
- queryParameters: {
- 'spaceId': spaceId,
- },
+ return await _httpService.get(
+ path: ApiEndpoints.getBookings
+ .replaceAll('{mm}', month)
+ .replaceAll('{yyyy}', year)
+ .replaceAll('{space}', params.id),
expectedResponseModel: (json) {
- return CalendarEventsResponse.fromJson(
- json as Map,
- );
+ return CalendarEventsResponse.fromJson(json as Map);
},
);
-
- return CalendarEventsResponse.fromJson(response as Map);
- } on DioException catch (e) {
- final responseData = e.response?.data;
- if (responseData is Map) {
- final errorMessage = responseData['error']?['message'] as String? ??
- responseData['message'] as String? ??
- _defaultErrorMessage;
- throw APIException(errorMessage);
- }
- throw APIException(_defaultErrorMessage);
- } catch (e) {
- throw APIException('$_defaultErrorMessage: ${e.toString()}');
- }
- }
-}
-
-class FakeRemoteCalendarService implements CalendarSystemService {
- const FakeRemoteCalendarService(this._httpService, {this.useDummy = false});
-
- final HTTPService _httpService;
- final bool useDummy;
- static const _defaultErrorMessage = 'Failed to load Calendar';
-
- @override
- Future getCalendarEvents({
- required String spaceId,
- }) async {
- if (useDummy) {
- final dummyJson = {
- 'statusCode': 200,
- 'message': 'Successfully fetched all bookings',
- 'data': [
- {
- 'uuid': 'd4553fa6-a0c9-4f42-81c9-99a13a57bf80',
- 'date': '2025-07-11T10:22:00.626Z',
- 'startTime': '09:00:00',
- 'endTime': '12:00:00',
- 'cost': 10,
- 'user': {
- 'uuid': '784394ff-3197-4c39-9f07-48dc44920b1e',
- 'firstName': 'salsabeel',
- 'lastName': 'abuzaid',
- 'email': 'test@test.com',
- 'companyName': null
- },
- 'space': {
- 'uuid': '000f4d81-43e4-4ad7-865c-0f8b04b7081e',
- 'spaceName': '2(1)'
- }
- },
- {
- 'uuid': 'e9b27af0-b963-4d98-9657-454c4ba78561',
- 'date': '2025-07-11T10:22:00.626Z',
- 'startTime': '12:00:00',
- 'endTime': '13:00:00',
- 'cost': 10,
- 'user': {
- 'uuid': '784394ff-3197-4c39-9f07-48dc44920b1e',
- 'firstName': 'salsabeel',
- 'lastName': 'abuzaid',
- 'email': 'test@test.com',
- 'companyName': null
- },
- 'space': {
- 'uuid': '000f4d81-43e4-4ad7-865c-0f8b04b7081e',
- 'spaceName': '2(1)'
- }
- },
- {
- 'uuid': 'e9b27af0-b963-4d98-9657-454c4ba78561',
- 'date': '2025-07-13T10:22:00.626Z',
- 'startTime': '15:30:00',
- 'endTime': '19:00:00',
- 'cost': 20,
- 'user': {
- 'uuid': '784394ff-3197-4c39-9f07-48dc44920b1e',
- 'firstName': 'salsabeel',
- 'lastName': 'abuzaid',
- 'email': 'test@test.com',
- 'companyName': null
- },
- 'space': {
- 'uuid': '000f4d81-43e4-4ad7-865c-0f8b04b7081e',
- 'spaceName': '2(1)'
- }
- }
- ],
- 'success': true
- };
- final response = CalendarEventsResponse.fromJson(dummyJson);
-
- // Filter events by spaceId
- final filteredData = response.data.where((event) {
- return event.space.uuid == spaceId;
- }).toList();
- print('Filtering events for spaceId: $spaceId');
- print('Found ${filteredData.length} matching events');
- return filteredData.isNotEmpty
- ? CalendarEventsResponse(
- statusCode: response.statusCode,
- message: response.message,
- data: filteredData,
- success: response.success,
- )
- : CalendarEventsResponse(
- statusCode: 404,
- message: 'No events found for spaceId: $spaceId',
- data: [],
- success: false,
- );
- }
-
- try {
- final response = await _httpService.get(
- path: ApiEndpoints.getCalendarEvents,
- queryParameters: {
- 'spaceId': spaceId,
- },
- expectedResponseModel: (json) {
- return CalendarEventsResponse.fromJson(
- json as Map,
- );
- },
- );
-
- return CalendarEventsResponse.fromJson(response as Map);
} on DioException catch (e) {
final responseData = e.response?.data;
if (responseData is Map) {
diff --git a/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart b/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart
new file mode 100644
index 00000000..542dd5dc
--- /dev/null
+++ b/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart
@@ -0,0 +1,34 @@
+import 'package:equatable/equatable.dart';
+
+class LoadEventsParam extends Equatable {
+ final DateTime startDate;
+ final DateTime endDate;
+ final String id;
+
+ const LoadEventsParam({
+ required this.startDate,
+ required this.endDate,
+ required this.id,
+ });
+
+ @override
+ List