From c6729f476f808581823dced0235e595c86a9fe89 Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 16 Jul 2025 15:36:49 +0300 Subject: [PATCH] Enhance booking system: update API endpoints, improve event loading with caching, and refine UI components --- .../services/remote_calendar_service.dart | 144 +-------- .../services/calendar_system_service.dart | 2 + .../bloc/calendar/events_bloc.dart | 73 ++++- .../bloc/calendar/events_state.dart | 8 +- .../presentation/view/booking_page.dart | 8 +- .../view/widgets/booking_sidebar.dart | 7 +- .../view/widgets/event_tile_widget.dart | 98 +++++-- .../view/widgets/room_list_item.dart | 4 + .../view/widgets/weekly_calendar_page.dart | 276 +++++++++--------- lib/utils/constants/api_const.dart | 3 +- 10 files changed, 307 insertions(+), 316 deletions(-) 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..15fb1fd9 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 @@ -14,146 +14,20 @@ class RemoteCalendarService implements CalendarSystemService { @override Future getCalendarEvents({ required String spaceId, + required String month, + required String year, }) async { + 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}', spaceId), 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/services/calendar_system_service.dart b/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart index 9e178040..d999ef1a 100644 --- a/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart +++ b/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart @@ -3,5 +3,7 @@ import 'package:syncrow_web/pages/access_management/booking_system/domain/models abstract class CalendarSystemService { Future getCalendarEvents({ required String spaceId, + required String month, + required String year, }); } diff --git a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart index da782d74..1985348e 100644 --- a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart +++ b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart @@ -4,35 +4,70 @@ import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.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'; - part 'events_event.dart'; part 'events_state.dart'; class CalendarEventsBloc extends Bloc { final EventController eventController = EventController(); final CalendarSystemService calendarService; + final Map> _eventsCache = {}; + + String? _lastSpaceId; + int? _lastMonth; + int? _lastYear; CalendarEventsBloc({required this.calendarService}) : super(EventsInitial()) { on(_onLoadEvents); on(_onAddEvent); - on(_onStartTimer); on(_onDisposeResources); on(_onGoToWeek); } - Future _onLoadEvents( LoadEvents event, Emitter emit, ) async { + final month = event.weekEnd.month; + final year = event.weekEnd.year; + final cacheKey = + '${event.spaceId}-$year-${month.toString().padLeft(2, '0')}'; + + if (_eventsCache.containsKey(cacheKey)) { + final cachedEvents = _eventsCache[cacheKey]!; + eventController.addAll(cachedEvents); + emit(EventsLoaded( + events: cachedEvents, + spaceId: event.spaceId, + month: month, + year: year, + )); + return; + } + if (_lastSpaceId == event.spaceId && + _lastMonth == month && + _lastYear == year) { + return; + } + emit(EventsLoading()); try { final response = await calendarService.getCalendarEvents( + month: month.toString().padLeft(2, '0'), + year: year.toString(), spaceId: event.spaceId, ); - final events = - response.data.map(_toCalendarEventData).toList(); + + final events = response.data.map(_toCalendarEventData).toList(); + _eventsCache[cacheKey] = events; eventController.addAll(events); - emit(EventsLoaded(events: events)); + _lastSpaceId = event.spaceId; + _lastMonth = month; + _lastYear = year; + emit(EventsLoaded( + events: events, + spaceId: event.spaceId, + month: month, + year: year, + )); } catch (e) { emit(EventsError('Failed to load events')); } @@ -40,16 +75,28 @@ class CalendarEventsBloc extends Bloc { void _onAddEvent(AddEvent event, Emitter emit) { eventController.add(event.event); + if (state is EventsLoaded) { final loaded = state as EventsLoaded; + final cacheKey = + '${loaded.spaceId}-${loaded.year}-${loaded.month.toString().padLeft(2, '0')}'; + + if (_eventsCache.containsKey(cacheKey)) { + final cachedEvents = + List.from(_eventsCache[cacheKey]!); + cachedEvents.add(event.event); + _eventsCache[cacheKey] = cachedEvents; + } + emit(EventsLoaded( events: [...eventController.events], + spaceId: loaded.spaceId, + month: loaded.month, + year: loaded.year, )); } } - void _onStartTimer(StartTimer event, Emitter emit) {} - void _onDisposeResources( DisposeResources event, Emitter emit) { eventController.dispose(); @@ -61,6 +108,9 @@ class CalendarEventsBloc extends Bloc { final newWeekDays = _getWeekDays(event.weekDate); emit(EventsLoaded( events: loaded.events, + spaceId: loaded.spaceId, + month: loaded.month, + year: loaded.year, )); } } @@ -90,14 +140,13 @@ class CalendarEventsBloc extends Bloc { ); return CalendarEventData( - date: startTime, + date: startTime, startTime: startTime, endTime: endTime, - title: - '${booking.space.spaceName} - ${booking.user.firstName} ${booking.user.lastName}', + title: '${booking.user.firstName} ${booking.user.lastName}', description: 'Cost: ${booking.cost}', color: Colors.blue, - event: booking, + event: booking, ); } diff --git a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_state.dart b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_state.dart index bc0c2e31..b98fd2fb 100644 --- a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_state.dart +++ b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_state.dart @@ -7,11 +7,17 @@ class EventsInitial extends CalendarEventState {} class EventsLoading extends CalendarEventState {} -class EventsLoaded extends CalendarEventState { +final class EventsLoaded extends CalendarEventState { final List events; + final String spaceId; + final int month; + final int year; EventsLoaded({ required this.events, + required this.spaceId, + required this.month, + required this.year, }); } diff --git a/lib/pages/access_management/booking_system/presentation/view/booking_page.dart b/lib/pages/access_management/booking_system/presentation/view/booking_page.dart index 0ff9aaf6..8d04f932 100644 --- a/lib/pages/access_management/booking_system/presentation/view/booking_page.dart +++ b/lib/pages/access_management/booking_system/presentation/view/booking_page.dart @@ -62,8 +62,9 @@ class _BookingPageState extends State { BlocProvider(create: (_) => DateSelectionBloc()), BlocProvider( create: (_) => CalendarEventsBloc( - calendarService: - FakeRemoteCalendarService(HTTPService(), useDummy: true), + calendarService: RemoteCalendarService( + HTTPService(), + ), ), ), ], @@ -138,7 +139,7 @@ class _BookingPageState extends State { ), ), Expanded( - flex: 4, + flex: 5, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( @@ -187,6 +188,7 @@ class _BookingPageState extends State { ], ), Expanded( + flex: 5, child: BlocBuilder( builder: (context, roomState) { diff --git a/lib/pages/access_management/booking_system/presentation/view/widgets/booking_sidebar.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/booking_sidebar.dart index e3d84924..666df3bb 100644 --- a/lib/pages/access_management/booking_system/presentation/view/widgets/booking_sidebar.dart +++ b/lib/pages/access_management/booking_system/presentation/view/widgets/booking_sidebar.dart @@ -72,11 +72,7 @@ class __SidebarContentState extends State<_SidebarContent> { @override Widget build(BuildContext context) { return BlocConsumer( - listener: (context, state) { - if (state.currentPage == 1 && searchController.text.isNotEmpty) { - searchController.clear(); - } - }, + listener: (context, state) {}, builder: (context, state) { return Column( children: [ @@ -147,6 +143,7 @@ class __SidebarContentState extends State<_SidebarContent> { IconButton( icon: const Icon(Icons.close), onPressed: () { + searchController.clear(); context.read().add(ResetSearch()); }, ), diff --git a/lib/pages/access_management/booking_system/presentation/view/widgets/event_tile_widget.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/event_tile_widget.dart index 6c0f9cb2..b7e942d6 100644 --- a/lib/pages/access_management/booking_system/presentation/view/widgets/event_tile_widget.dart +++ b/lib/pages/access_management/booking_system/presentation/view/widgets/event_tile_widget.dart @@ -1,16 +1,15 @@ import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class EventTileWidget extends StatelessWidget { final List> events; - const EventTileWidget({ super.key, required this.events, }); - @override Widget build(BuildContext context) { return Container( @@ -18,39 +17,86 @@ class EventTileWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: events.map((event) { - final bool isEventEnded = + final booking = event.event is CalendarEventBooking + ? event.event! as CalendarEventBooking + : null; + + final companyName = booking?.user.companyName ?? 'Unknown Company'; + final startTime = DateFormat('hh:mm a').format(event.startTime!); + final endTime = DateFormat('hh:mm a').format(event.endTime!); + final isEventEnded = event.endTime != null && event.endTime!.isBefore(DateTime.now()); + + final duration = event.endTime!.difference(event.startTime!); + final bool isLongEnough = duration.inMinutes >= 31; return Expanded( child: Container( width: double.infinity, - padding: const EdgeInsets.all(6), + padding: EdgeInsets.all(5), decoration: BoxDecoration( color: isEventEnded - ? ColorsManager.lightGrayBorderColor - : ColorsManager.blue1.withOpacity(0.25), + ? ColorsManager.grayColor.withOpacity(0.1) + : ColorsManager.blue1.withOpacity(0.1), borderRadius: BorderRadius.circular(6), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - DateFormat('h:mm a').format(event.startTime!), - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - color: Colors.black87, - ), + border: const Border( + left: BorderSide( + color: ColorsManager.grayColor, + width: 4, ), - const SizedBox(height: 2), - Text( - event.title, - style: const TextStyle( - fontSize: 12, - color: ColorsManager.blackColor, - ), - ), - ], + ), ), + child: isLongEnough + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '$startTime - $endTime', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12, + color: isEventEnded + ? ColorsManager.grayColor.withOpacity(0.9) + : ColorsManager.blackColor, + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 2), + Text( + event.title, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + color: isEventEnded + ? ColorsManager.grayColor + : ColorsManager.blackColor, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 2), + Text( + companyName, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + color: isEventEnded + ? ColorsManager.grayColor.withOpacity(0.9) + : ColorsManager.blackColor, + fontWeight: FontWeight.w400, + ), + ), + ], + ) + : Text( + event.title, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + color: isEventEnded + ? ColorsManager.grayColor + : ColorsManager.blackColor, + fontWeight: FontWeight.bold, + ), + ), ), ); }).toList(), diff --git a/lib/pages/access_management/booking_system/presentation/view/widgets/room_list_item.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/room_list_item.dart index 4a4b608d..83eda16b 100644 --- a/lib/pages/access_management/booking_system/presentation/view/widgets/room_list_item.dart +++ b/lib/pages/access_management/booking_system/presentation/view/widgets/room_list_item.dart @@ -24,17 +24,21 @@ class RoomListItem extends StatelessWidget { activeColor: ColorsManager.primaryColor, title: Text( room.spaceName, + maxLines: 2, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: ColorsManager.lightGrayColor, fontWeight: FontWeight.w700, + overflow: TextOverflow.ellipsis, fontSize: 12), ), subtitle: Text( room.virtualLocation, + maxLines: 2, style: Theme.of(context).textTheme.bodySmall?.copyWith( fontSize: 10, fontWeight: FontWeight.w400, color: ColorsManager.textGray, + overflow: TextOverflow.ellipsis, ), ), ); diff --git a/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart index 0dd343a7..03972632 100644 --- a/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart +++ b/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:calendar_view/calendar_view.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/event_tile_widget.dart'; -import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/hatched_column_background.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/time_line_widget.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/week_day_header.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -23,6 +22,12 @@ class WeeklyCalendarPage extends StatelessWidget { this.endTime, this.selectedDateFromSideBarCalender, }); + static const double timeLineWidth = 65; + static const int totalDays = 7; + static const double dayColumnWidth = 220; // or any width you want + + final double calendarContentWidth = + timeLineWidth + (totalDays * dayColumnWidth); @override Widget build(BuildContext context) { @@ -52,154 +57,159 @@ class WeeklyCalendarPage extends StatelessWidget { ); } - final weekDays = _getWeekDays(weekStart); + - final selectedDayIndex = - weekDays.indexWhere((d) => isSameDay(d, selectedDate)); - final selectedSidebarIndex = selectedDateFromSideBarCalender == null - ? -1 - : weekDays - .indexWhere((d) => isSameDay(d, selectedDateFromSideBarCalender!)); + const double timeLineWidth = 65; - const double timeLineWidth = 80; - const int totalDays = 7; - final DateTime highlightStart = DateTime(2025, 7, 10); - final DateTime highlightEnd = DateTime(2025, 7, 19); return LayoutBuilder( builder: (context, constraints) { - final double calendarWidth = constraints.maxWidth; - final double dayColumnWidth = - (calendarWidth - timeLineWidth) / totalDays - 0.1; + bool isInRange(DateTime date, DateTime start, DateTime end) { - return !date.isBefore(start) && !date.isAfter(end); + !date.isBefore(start) && !date.isAfter(end); + // remove this line and Check if the date is within the range + return false; } - return Padding( - padding: const EdgeInsets.only(left: 25.0, right: 25.0, top: 25), - child: Stack( - children: [ - WeekView( - weekDetectorBuilder: ({ - required date, - required height, - required heightPerMinute, - required minuteSlotSize, - required width, - }) { - return isInRange(date, highlightStart, highlightEnd) - ? HatchedColumnBackground( - backgroundColor: ColorsManager.grey800, - lineColor: ColorsManager.textGray, - opacity: 0.3, - stripeSpacing: 12, - borderRadius: BorderRadius.circular(8), - ) - : const SizedBox(); - }, - pageViewPhysics: const NeverScrollableScrollPhysics(), - key: ValueKey(weekStart), - controller: eventController, - initialDay: weekStart, - startHour: startHour - 1, - endHour: endHour, - heightPerMinute: 1.1, - showLiveTimeLineInAllDays: false, - showVerticalLines: true, - emulateVerticalOffsetBy: -80, - startDay: WeekDays.monday, - liveTimeIndicatorSettings: const LiveTimeIndicatorSettings( - showBullet: false, - height: 0, - ), - weekDayBuilder: (date) { - return WeekDayHeader( - date: date, - isSelectedDay: isSameDay(date, selectedDate), - ); - }, - timeLineBuilder: (date) { - return TimeLineWidget(date: date); - }, - timeLineWidth: timeLineWidth, - weekPageHeaderBuilder: (start, end) => Container(), - weekTitleHeight: 60, - weekNumberBuilder: (firstDayOfWeek) => Padding( - padding: const EdgeInsets.only(right: 15, bottom: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - firstDayOfWeek.timeZoneName.replaceAll(':00', ''), - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - fontSize: 12, - color: ColorsManager.blackColor, - fontWeight: FontWeight.w400, - ), + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: SizedBox( + width: calendarContentWidth, + child: Padding( + padding: + const EdgeInsets.only(left: 25.0, right: 25.0, top: 25), + child: Stack( + children: [ + Container( + child: WeekView( + minuteSlotSize: MinuteSlotSize.minutes15, + weekDetectorBuilder: ({ + required date, + required height, + required heightPerMinute, + required minuteSlotSize, + required width, + }) { + final isSelected = isSameDay(date, selectedDate); + final isSidebarSelected = + selectedDateFromSideBarCalender != null && + isSameDay( + date, selectedDateFromSideBarCalender!); + if (isSidebarSelected && !isSelected) { + return Container( + height: height, + width: width, + decoration: BoxDecoration( + color: Colors.orange.withOpacity(0.13), + borderRadius: BorderRadius.circular(8), + ), + ); + } else if (isSelected) { + return Container( + height: height, + width: width, + decoration: BoxDecoration( + color: + ColorsManager.spaceColor.withOpacity(0.07), + borderRadius: BorderRadius.circular(8), + ), + ); + } + return const SizedBox.shrink(); + }, + + // weekDetectorBuilder: ({ + // required date, + // required height, + // required heightPerMinute, + // required minuteSlotSize, + // required width, + // }) { + // return isInRange(date, highlightStart, highlightEnd) + // ? HatchedColumnBackground( + // backgroundColor: ColorsManager.grey800, + // lineColor: ColorsManager.textGray, + // opacity: 0.3, + // stripeSpacing: 12, + // borderRadius: BorderRadius.circular(8), + // ) + // : const SizedBox(); + // }, + pageViewPhysics: const NeverScrollableScrollPhysics(), + key: ValueKey(weekStart), + controller: eventController, + initialDay: weekStart, + startHour: startHour - 1, + endHour: endHour, + heightPerMinute: 1.7, + showLiveTimeLineInAllDays: false, + showVerticalLines: true, + emulateVerticalOffsetBy: -80, + startDay: WeekDays.monday, + liveTimeIndicatorSettings: + const LiveTimeIndicatorSettings( + showBullet: false, + height: 0, + ), + weekDayBuilder: (date) { + return WeekDayHeader( + date: date, + isSelectedDay: isSameDay(date, selectedDate), + ); + }, + timeLineBuilder: (date) { + return TimeLineWidget(date: date); + }, + timeLineWidth: timeLineWidth, + weekPageHeaderBuilder: (start, end) => Container(), + weekTitleHeight: 60, + weekNumberBuilder: (firstDayOfWeek) => Padding( + padding: const EdgeInsets.only(right: 15, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + firstDayOfWeek.timeZoneName + .replaceAll(':00', ''), + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + fontSize: 12, + color: ColorsManager.blackColor, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + eventTileBuilder: (date, events, boundary, start, end) { + return EventTileWidget( + events: events, + ); + }, ), - ], - ), - ), - eventTileBuilder: (date, events, boundary, start, end) { - return EventTileWidget( - events: events, - ); - }, - ), - if (selectedDayIndex >= 0) - Positioned( - left: (timeLineWidth + 3) + - (dayColumnWidth - 8) * (selectedDayIndex - 0.01), - top: 0, - bottom: 0, - width: dayColumnWidth, - child: IgnorePointer( - child: Container( - margin: const EdgeInsets.symmetric( - vertical: 0, horizontal: 4), - color: ColorsManager.spaceColor.withOpacity(0.07), ), - ), - ), - if (selectedSidebarIndex >= 0 && - selectedSidebarIndex != selectedDayIndex) - Positioned( - left: (timeLineWidth + 3) + - (dayColumnWidth - 8) * (selectedSidebarIndex - 0.01), - top: 0, - bottom: 0, - width: dayColumnWidth, - child: IgnorePointer( - child: Container( - margin: const EdgeInsets.symmetric( - vertical: 0, horizontal: 4), - color: Colors.orange.withOpacity(0.14), + Positioned( + right: 0, + top: 50, + bottom: 0, + child: IgnorePointer( + child: Container( + width: 1, + color: Theme.of(context).scaffoldBackgroundColor, + ), + ), ), - ), - ), - Positioned( - right: 0, - top: 50, - bottom: 0, - child: IgnorePointer( - child: Container( - width: 1, - color: Theme.of(context).scaffoldBackgroundColor, - ), + ], ), ), - ], - ), - ); + )); }, ); } - List _getWeekDays(DateTime date) { - final int weekday = date.weekday; - final DateTime monday = date.subtract(Duration(days: weekday - 1)); - return List.generate(7, (i) => monday.add(Duration(days: i))); - } + } bool isSameDay(DateTime d1, DateTime d2) { diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index b3c8a168..e99f4796 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -140,5 +140,6 @@ abstract class ApiEndpoints { static const String saveSchedule = '/schedule/{deviceUuid}'; static const String getBookableSpaces = '/bookable-spaces'; - static const String getCalendarEvents = '/api'; + static const String getBookings = + '/bookings?month={mm}%2F{yyyy}&space={space}'; }