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/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_calendar_service.dart b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart
new file mode 100644
index 00000000..55a5b0b8
--- /dev/null
+++ b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart
@@ -0,0 +1,45 @@
+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';
+import 'package:syncrow_web/services/api/http_service.dart';
+import 'package:syncrow_web/utils/constants/api_const.dart';
+
+class RemoteCalendarService implements CalendarSystemService {
+ const RemoteCalendarService(this._httpService);
+
+ final HTTPService _httpService;
+ static const _defaultErrorMessage = 'Failed to load Calendar';
+
+ @override
+ Future getCalendarEvents({
+ required LoadEventsParam params,
+ }) async {
+ final month = params.startDate.month.toString().padLeft(2, '0');
+ final year = params.startDate.year.toString();
+
+ try {
+ 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);
+ },
+ );
+ } 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()}');
+ }
+ }
+}
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