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/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/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/presentation/view/widgets/icon_text_button.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/icon_text_button.dart
index c7c660c1..9844e3d8 100644
--- a/lib/pages/access_management/booking_system/presentation/view/widgets/icon_text_button.dart
+++ b/lib/pages/access_management/booking_system/presentation/view/widgets/icon_text_button.dart
@@ -4,6 +4,7 @@ import 'package:syncrow_web/utils/color_manager.dart';
class SvgTextButton extends StatelessWidget {
final String svgAsset;
+ final EdgeInsets? padding;
final String label;
final VoidCallback onPressed;
final Color backgroundColor;
@@ -12,16 +13,20 @@ class SvgTextButton extends StatelessWidget {
final double borderRadius;
final List boxShadow;
final double svgSize;
-
+ final double? fontSize;
+ final FontWeight? fontWeight;
const SvgTextButton({
super.key,
required this.svgAsset,
+ this.fontSize,
+ this.fontWeight,
required this.label,
required this.onPressed,
this.backgroundColor = ColorsManager.circleRolesBackground,
this.svgColor = const Color(0xFF496EFF),
this.labelColor = Colors.black,
this.borderRadius = 10.0,
+ this.padding,
this.boxShadow = const [
BoxShadow(
color: ColorsManager.lightGrayColor,
@@ -40,7 +45,8 @@ class SvgTextButton extends StatelessWidget {
borderRadius: BorderRadius.circular(borderRadius),
onTap: onPressed,
child: Container(
- padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
+ padding: padding ??
+ const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(borderRadius),
diff --git a/lib/pages/access_management/booking_system/view/booking_page.dart b/lib/pages/access_management/booking_system/view/booking_page.dart
new file mode 100644
index 00000000..49d10b50
--- /dev/null
+++ b/lib/pages/access_management/booking_system/view/booking_page.dart
@@ -0,0 +1,57 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/icon_text_button.dart';
+
+import 'package:syncrow_web/utils/constants/assets.dart';
+
+class BookingPage extends StatelessWidget {
+ final PageController pageController;
+ const BookingPage({
+ super.key,
+ required this.pageController,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ Expanded(
+ child: Container(
+ color: Colors.blueGrey[100],
+ child: const Center(
+ child: Text(
+ 'Side bar',
+ style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
+ ),
+ ),
+ )),
+ Expanded(
+ flex: 4,
+ child: Padding(
+ padding: const EdgeInsets.all(20.0),
+ child: SizedBox(
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ SvgTextButton(
+ svgAsset: Assets.homeIcon,
+ label: 'Manage Bookable Spaces',
+ onPressed: () {
+ pageController.jumpToPage(2);
+ }),
+ const SizedBox(width: 20),
+ SvgTextButton(
+ svgAsset: Assets.groupIcon,
+ label: 'Manage Users',
+ onPressed: () {})
+ ],
+ )
+ ],
+ ),
+ ),
+ ))
+ ],
+ );
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/data/non_bookable_spaces_decorator.dart b/lib/pages/access_management/manage_bookable_spaces/data/non_bookable_spaces_decorator.dart
new file mode 100644
index 00000000..af24439f
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/data/non_bookable_spaces_decorator.dart
@@ -0,0 +1,32 @@
+import 'dart:async';
+
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/non_bookable_spaces_service.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.dart';
+
+class NonBookableSpacesDebouncerDecoratorService
+ implements NonBookableSpacesService {
+ final NonBookableSpacesService _delegate;
+ Timer? _debounce;
+
+ NonBookableSpacesDebouncerDecoratorService(this._delegate);
+
+ @override
+ Future> load(
+ NonBookableSpacesParams params) {
+ final completer = Completer>();
+
+ _debounce?.cancel();
+ _debounce = Timer(const Duration(milliseconds: 500), () async {
+ try {
+ final result = await _delegate.load(params);
+ completer.complete(result);
+ } catch (e) {
+ completer.completeError(e);
+ }
+ });
+
+ return completer.future;
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/data/remote_bookable_spaces_service.dart b/lib/pages/access_management/manage_bookable_spaces/data/remote_bookable_spaces_service.dart
new file mode 100644
index 00000000..ceebf262
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/data/remote_bookable_spaces_service.dart
@@ -0,0 +1,47 @@
+import 'package:dio/dio.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/bookable_spaces_service.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.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 RemoteBookableSpacesService implements BookableSpacesService {
+ final HTTPService _httpService;
+ RemoteBookableSpacesService(this._httpService);
+ static const _defaultErrorMessage = 'Failed to load Bookable Spaces';
+ @override
+ Future> load(
+ BookableSpacesParam param) async {
+ try {
+ final response = await _httpService.get(
+ path: ApiEndpoints.bookableSpaces,
+ queryParameters: {
+ 'configured': true,
+ 'page': param.currentPage,
+ },
+ expectedResponseModel: (json) {
+ final result = json as Map;
+ return PaginatedDataModel.fromJson(
+ result,
+ BookableSpacemodel.fromJsonList,
+ );
+ },
+ );
+ return response;
+ } on DioException catch (e) {
+ final message = e.response?.data as Map?;
+ final error = message?['error'] as Map?;
+ final errorMessage = error?['error'] as String? ?? '';
+ final formattedErrorMessage = [
+ _defaultErrorMessage,
+ errorMessage,
+ ].join(': ');
+ throw APIException(formattedErrorMessage);
+ } catch (e) {
+ final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
+ throw APIException(formattedErrorMessage);
+ }
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/data/remote_non_bookable_spaces.dart b/lib/pages/access_management/manage_bookable_spaces/data/remote_non_bookable_spaces.dart
new file mode 100644
index 00000000..1db35a8e
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/data/remote_non_bookable_spaces.dart
@@ -0,0 +1,53 @@
+import 'dart:async';
+
+import 'package:dio/dio.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/non_bookable_spaces_service.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.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 RemoteNonBookableSpaces implements NonBookableSpacesService {
+ final HTTPService _httpService;
+
+ RemoteNonBookableSpaces(this._httpService);
+
+ static const _defaultErrorMessage = 'Failed to load Spaces';
+
+ @override
+ Future> load(
+ NonBookableSpacesParams params) async {
+ try {
+ final response = await _httpService.get(
+ path: ApiEndpoints.bookableSpaces,
+ queryParameters: {
+ 'configured': false,
+ 'page': params.currentPage,
+ 'search': params.searchedWords,
+ },
+ expectedResponseModel: (json) {
+ final result = json as Map;
+ return PaginatedDataModel.fromJson(
+ result,
+ BookableSpacemodel.fromJsonList,
+ );
+ },
+ );
+ return response;
+ } on DioException catch (e) {
+ final message = e.response?.data as Map?;
+ final error = message?['error'] as Map?;
+ final errorMessage = error?['error'] as String? ?? '';
+ final formattedErrorMessage = [
+ _defaultErrorMessage,
+ errorMessage,
+ ].join(': ');
+ throw APIException(formattedErrorMessage);
+ } catch (e) {
+ final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
+ throw APIException(formattedErrorMessage);
+ }
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/data/remote_send_bookable_spaces.dart b/lib/pages/access_management/manage_bookable_spaces/data/remote_send_bookable_spaces.dart
new file mode 100644
index 00000000..5d50fd55
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/data/remote_send_bookable_spaces.dart
@@ -0,0 +1,35 @@
+import 'package:dio/dio.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/send_bookable_spaces_to_api_params.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/send_bookable_spaces_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 RemoteSendBookableSpaces implements SendBookableSpacesService {
+ final HTTPService _httpService;
+ RemoteSendBookableSpaces(this._httpService);
+ static const _defaultErrorMessage = 'Failed to load Spaces';
+ @override
+ Future sendBookableSpacesToApi(
+ SendBookableSpacesToApiParams params) async {
+ try {
+ await _httpService.post(
+ path: ApiEndpoints.bookableSpaces,
+ body: params.toJson(),
+ expectedResponseModel: (p0) {},
+ );
+ } on DioException catch (e) {
+ final message = e.response?.data as Map?;
+ final error = message?['error'] as Map?;
+ final errorMessage = error?['error'] as String? ?? '';
+ final formattedErrorMessage = [
+ _defaultErrorMessage,
+ errorMessage,
+ ].join(': ');
+ throw APIException(formattedErrorMessage);
+ } catch (e) {
+ final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
+ throw APIException(formattedErrorMessage);
+ }
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/data/remote_update_bookable_space_service.dart b/lib/pages/access_management/manage_bookable_spaces/data/remote_update_bookable_space_service.dart
new file mode 100644
index 00000000..1c0b1c8e
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/data/remote_update_bookable_space_service.dart
@@ -0,0 +1,40 @@
+import 'package:dio/dio.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/update_bookable_space_param.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/update_bookable_space_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 RemoteUpdateBookableSpaceService implements UpdateBookableSpaceService {
+ final HTTPService _httpService;
+ RemoteUpdateBookableSpaceService(this._httpService);
+ static const _defaultErrorMessage = 'Failed to load Bookable Spaces';
+ @override
+ Future update(
+ UpdateBookableSpaceParam updateParam) async {
+ try {
+ final response = await _httpService.put(
+ path: '${ApiEndpoints.bookableSpaces}/${updateParam.spaceUuid}',
+ body: updateParam.toJson(),
+ expectedResponseModel: (json) {
+ return BookableSpaceConfig.fromJson(
+ json['data'] as Map);
+ },
+ );
+ return response;
+ } on DioException catch (e) {
+ final message = e.response?.data as Map?;
+ final error = message?['error'] as Map?;
+ final errorMessage = error?['error'] as String? ?? '';
+ final formattedErrorMessage = [
+ _defaultErrorMessage,
+ errorMessage,
+ ].join(': ');
+ throw APIException(formattedErrorMessage);
+ } catch (e) {
+ final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
+ throw APIException(formattedErrorMessage);
+ }
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart b/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart
new file mode 100644
index 00000000..1e28b686
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart
@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+
+class BookableSpaceConfig {
+ final String configUuid;
+ final List bookableDays;
+ final TimeOfDay? bookingStartTime;
+ final TimeOfDay? bookingEndTime;
+ final int cost;
+ final bool availability;
+ BookableSpaceConfig({
+ required this.configUuid,
+ required this.availability,
+ required this.bookableDays,
+ this.bookingEndTime,
+ this.bookingStartTime,
+ required this.cost,
+ });
+ factory BookableSpaceConfig.zero() => BookableSpaceConfig(
+ configUuid: '',
+ bookableDays: [],
+ availability: false,
+ cost: -1,
+ );
+ factory BookableSpaceConfig.fromJson(Map json) =>
+ BookableSpaceConfig(
+ configUuid: json['uuid'] as String,
+ bookableDays: (json['daysAvailable'] as List).cast(),
+ availability: (json['active'] as bool?) ?? false,
+ bookingStartTime: parseTimeOfDay(json['startTime'] as String),
+ bookingEndTime: parseTimeOfDay(json['endTime'] as String),
+ cost: json['points'] as int,
+ );
+
+ static TimeOfDay parseTimeOfDay(String timeString) {
+ final parts = timeString.split(':');
+ final hour = int.parse(parts[0]);
+ final minute = int.parse(parts[1]);
+ return TimeOfDay(hour: hour, minute: minute);
+ }
+
+ bool get isValid =>
+ bookableDays.isNotEmpty &&
+ cost >= 0 &&
+ bookingStartTime != null &&
+ bookingEndTime != null;
+
+ BookableSpaceConfig copyWith({
+ List? bookableDays,
+ TimeOfDay? bookingStartTime,
+ TimeOfDay? bookingEndTime,
+ int? cost,
+ bool? availability,
+ }) {
+ return BookableSpaceConfig(
+ configUuid: configUuid,
+ availability: availability ?? this.availability,
+ bookableDays: bookableDays ?? this.bookableDays,
+ cost: cost ?? this.cost,
+ bookingEndTime: bookingEndTime ?? this.bookingEndTime,
+ bookingStartTime: bookingStartTime ?? this.bookingStartTime,
+ );
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart b/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart
new file mode 100644
index 00000000..70e700be
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart
@@ -0,0 +1,58 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart';
+
+class BookableSpacemodel {
+ final String spaceUuid;
+ final String spaceName;
+ final BookableSpaceConfig? spaceConfig;
+ final String spaceVirtualAddress;
+
+ BookableSpacemodel({
+ required this.spaceUuid,
+ required this.spaceName,
+ this.spaceConfig,
+ required this.spaceVirtualAddress,
+ });
+ factory BookableSpacemodel.zero() => BookableSpacemodel(
+ spaceUuid: '',
+ spaceName: '',
+ spaceVirtualAddress: '',
+ );
+ factory BookableSpacemodel.fromJson(Map json) =>
+ BookableSpacemodel(
+ spaceUuid: json['uuid'] as String,
+ spaceName: json['spaceName'] as String,
+ spaceConfig: json['bookableConfig'] == null
+ ? BookableSpaceConfig.zero()
+ : BookableSpaceConfig.fromJson(
+ json['bookableConfig'] as Map),
+ spaceVirtualAddress: json['virtualLocation'] as String,
+ );
+
+ static List fromJsonList(List jsonList) =>
+ jsonList
+ .map(
+ (e) => BookableSpacemodel.fromJson(e as Map),
+ )
+ .toList();
+
+ bool get isValid =>
+ spaceUuid.isNotEmpty &&
+ spaceName.isNotEmpty &&
+ spaceVirtualAddress.isNotEmpty &&
+ spaceConfig != null &&
+ spaceConfig!.isValid;
+
+ BookableSpacemodel copyWith({
+ String? spaceUuid,
+ String? spaceName,
+ BookableSpaceConfig? spaceConfig,
+ String? spaceVirtualAddress,
+ }) {
+ return BookableSpacemodel(
+ spaceUuid: spaceUuid ?? this.spaceUuid,
+ spaceName: spaceName ?? this.spaceName,
+ spaceConfig: spaceConfig ?? this.spaceConfig,
+ spaceVirtualAddress: spaceVirtualAddress ?? this.spaceVirtualAddress,
+ );
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart b/lib/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart
new file mode 100644
index 00000000..6007424b
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart
@@ -0,0 +1,10 @@
+class BookableSpacesParam {
+ final int currentPage;
+ BookableSpacesParam({
+ required this.currentPage,
+ });
+
+ Map toJson() => {
+ 'page': currentPage,
+ };
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart b/lib/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart
new file mode 100644
index 00000000..a081ce04
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart
@@ -0,0 +1,12 @@
+class NonBookableSpacesParams {
+final int currentPage;
+final String? searchedWords;
+ NonBookableSpacesParams({
+ required this.currentPage,
+ this.searchedWords,
+ });
+
+ Map toJson() => {
+ 'page': currentPage,
+ };
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/params/send_bookable_spaces_to_api_params.dart b/lib/pages/access_management/manage_bookable_spaces/domain/params/send_bookable_spaces_to_api_params.dart
new file mode 100644
index 00000000..3e1251dd
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/params/send_bookable_spaces_to_api_params.dart
@@ -0,0 +1,41 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/utils/string_utils.dart';
+
+class SendBookableSpacesToApiParams {
+ final List spaceUuids;
+ final List daysAvailable;
+ final String startTime;
+ final String endTime;
+ final int points;
+ SendBookableSpacesToApiParams({
+ required this.spaceUuids,
+ required this.daysAvailable,
+ required this.startTime,
+ required this.endTime,
+ required this.points,
+ });
+
+ static SendBookableSpacesToApiParams fromBookableSpacesModel(
+ List bookableSpaces) {
+ return SendBookableSpacesToApiParams(
+ spaceUuids: bookableSpaces.map((space) => space.spaceUuid).toList(),
+ daysAvailable: bookableSpaces
+ .expand((space) => space.spaceConfig!.bookableDays)
+ .toSet()
+ .toList(),
+ startTime: formatTimeOfDayTo24HourString(
+ bookableSpaces.first.spaceConfig!.bookingStartTime!),
+ endTime: formatTimeOfDayTo24HourString(
+ bookableSpaces.first.spaceConfig!.bookingEndTime!),
+ points: bookableSpaces.first.spaceConfig!.cost,
+ );
+ }
+
+ Map toJson() => {
+ 'spaceUuids': spaceUuids,
+ 'daysAvailable': daysAvailable,
+ 'startTime': startTime,
+ 'endTime': endTime,
+ 'points': points
+ };
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/params/update_bookable_space_param.dart b/lib/pages/access_management/manage_bookable_spaces/domain/params/update_bookable_space_param.dart
new file mode 100644
index 00000000..237f3442
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/params/update_bookable_space_param.dart
@@ -0,0 +1,40 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/utils/string_utils.dart';
+
+class UpdateBookableSpaceParam {
+ final String spaceUuid;
+ final List? bookableDays;
+ final String? bookingStartTime;
+ final String? bookingEndTime;
+ final int? cost;
+ final bool? availability;
+ UpdateBookableSpaceParam({
+ required this.spaceUuid,
+ this.bookingStartTime,
+ this.bookingEndTime,
+ this.bookableDays,
+ this.availability,
+ this.cost,
+ });
+ factory UpdateBookableSpaceParam.fromBookableModel(
+ BookableSpacemodel bookableSpace) {
+ return UpdateBookableSpaceParam(
+ spaceUuid: bookableSpace.spaceUuid,
+ availability: bookableSpace.spaceConfig!.availability,
+ bookableDays: bookableSpace.spaceConfig!.bookableDays,
+ cost: bookableSpace.spaceConfig!.cost,
+ bookingStartTime: formatTimeOfDayTo24HourString(
+ bookableSpace.spaceConfig!.bookingStartTime!),
+ bookingEndTime: formatTimeOfDayTo24HourString(
+ bookableSpace.spaceConfig!.bookingEndTime!),
+ );
+ }
+
+ Map toJson() => {
+ if (bookableDays != null) 'daysAvailable': bookableDays,
+ if (bookingStartTime != null) 'startTime': bookingStartTime,
+ if (bookingEndTime != null) 'endTime': bookingEndTime,
+ if (cost != null) 'points': cost,
+ if (availability != null) 'active': availability,
+ };
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/service/bookable_spaces_service.dart b/lib/pages/access_management/manage_bookable_spaces/domain/service/bookable_spaces_service.dart
new file mode 100644
index 00000000..208589ad
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/service/bookable_spaces_service.dart
@@ -0,0 +1,8 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.dart';
+
+abstract class BookableSpacesService {
+ Future> load(
+ BookableSpacesParam param);
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/service/non_bookable_spaces_service.dart b/lib/pages/access_management/manage_bookable_spaces/domain/service/non_bookable_spaces_service.dart
new file mode 100644
index 00000000..a5034bbf
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/service/non_bookable_spaces_service.dart
@@ -0,0 +1,8 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.dart';
+
+abstract class NonBookableSpacesService {
+ Future> load(
+ NonBookableSpacesParams params);
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/service/send_bookable_spaces_service.dart b/lib/pages/access_management/manage_bookable_spaces/domain/service/send_bookable_spaces_service.dart
new file mode 100644
index 00000000..6b3f40d5
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/service/send_bookable_spaces_service.dart
@@ -0,0 +1,5 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/send_bookable_spaces_to_api_params.dart';
+
+abstract class SendBookableSpacesService{
+ Future sendBookableSpacesToApi(SendBookableSpacesToApiParams params);
+}
\ No newline at end of file
diff --git a/lib/pages/access_management/manage_bookable_spaces/domain/service/update_bookable_space_service.dart b/lib/pages/access_management/manage_bookable_spaces/domain/service/update_bookable_space_service.dart
new file mode 100644
index 00000000..509c69eb
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/domain/service/update_bookable_space_service.dart
@@ -0,0 +1,6 @@
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/update_bookable_space_param.dart';
+
+abstract class UpdateBookableSpaceService {
+ Future update(UpdateBookableSpaceParam updateParam);
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart b/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart
new file mode 100644
index 00000000..c947cd69
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart
@@ -0,0 +1,66 @@
+import 'package:bloc/bloc.dart';
+import 'package:equatable/equatable.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_config.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
+import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/service/bookable_spaces_service.dart';
+import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.dart';
+import 'package:syncrow_web/services/api/api_exception.dart';
+
+part 'bookable_spaces_event.dart';
+part 'bookable_spaces_state.dart';
+
+class BookableSpacesBloc
+ extends Bloc {
+ final BookableSpacesService bookableSpacesService;
+ BookableSpacesBloc(this.bookableSpacesService)
+ : super(BookableSpacesInitial()) {
+ on(_onLoadBookableSpaces);
+ on(_onInsertUpdatedSpaceEven);
+ }
+
+ Future _onLoadBookableSpaces(
+ LoadBookableSpacesEvent event, Emitter emit) async {
+ emit(BookableSpacesLoading());
+ try {
+ final bookableSpaces = await bookableSpacesService.load(event.param);
+ emit(BookableSpacesLoaded(bookableSpacesList: bookableSpaces));
+ } on APIException catch (e) {
+ emit(BookableSpacesError(error: e.message));
+ } catch (e) {
+ emit(
+ BookableSpacesError(error: e.toString()),
+ );
+ }
+ }
+
+ void _onInsertUpdatedSpaceEven(
+ InsertUpdatedSpaceEvent event, Emitter emit) {
+ emit(InsertingUpdatedSpaceState());
+
+ if (event.bookableSpace.spaceConfig!.configUuid ==
+ event.updatedBookableSpaceConfig.configUuid) {
+ final index = event.bookableSpaces.data.indexWhere(
+ (element) => element.spaceUuid == event.bookableSpace.spaceUuid,
+ );
+
+ if (index != -1) {
+ final original = event.bookableSpaces.data[index];
+
+ final updatedConfig = original.spaceConfig!.copyWith(
+ availability: event.updatedBookableSpaceConfig.availability,
+ bookableDays: event.updatedBookableSpaceConfig.bookableDays,
+ bookingEndTime: event.updatedBookableSpaceConfig.bookingEndTime,
+ bookingStartTime: event.updatedBookableSpaceConfig.bookingStartTime,
+ cost: event.updatedBookableSpaceConfig.cost,
+ );
+
+ final updatedSpace = original.copyWith(spaceConfig: updatedConfig);
+
+ event.bookableSpaces.data[index] = updatedSpace;
+ }
+ }
+
+ emit(BookableSpacesLoaded(bookableSpacesList: event.bookableSpaces));
+ }
+}
diff --git a/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_event.dart b/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_event.dart
new file mode 100644
index 00000000..c73f08dc
--- /dev/null
+++ b/lib/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_event.dart
@@ -0,0 +1,24 @@
+part of 'bookable_spaces_bloc.dart';
+
+sealed class BookableSpacesEvent extends Equatable {
+ const BookableSpacesEvent();
+
+ @override
+ List