6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit c68483a0
Changed files
comwell_key_app/assets/translations/da-DK.json | 16 +- comwell_key_app/assets/translations/en-US.json | 18 +- .../lib/.generated/services/models/room_dto.g.dart | 33 +++ .../lib/check_in/check_in_repository.dart | 1 + .../choose_share_room/choose_share_room_page.dart | 96 +++---- .../choose_share_room_repository.dart | 163 +++++++++++- .../components/choose_room_widget.dart | 285 ++++++++++++++------- .../components/my_room_widget.dart | 110 ++++++++ .../cubit/choose_share_room_cubit.dart | 45 +++- .../cubit/choose_share_room_state.dart | 34 ++- .../choose_share_room/pages/room_info_page.dart | 198 ++++++++++++++ .../choose_share_room/pages/share_room_page.dart | 175 +++++++++++++ .../choose_share_room_shimmer_loader.dart | 32 +++ .../shimmer_loader/room_info_shimmer_loader.dart | 50 ++++ .../components/current_booking_list_item_view.dart | 2 - .../components/current_bookings_tab_view.dart | 6 +- .../lib/overview/cubit/overview_cubit.dart | 1 + comwell_key_app/lib/overview/models/booking.dart | 6 + comwell_key_app/lib/overview/models/room.dart | 28 ++ .../overview/repository/overview_repository.dart | 60 +++-- .../pregistration/pregistration_repository.dart | 1 - .../lib/profile/profile_repository.dart | 2 +- comwell_key_app/lib/routing/app_router.dart | 27 +- comwell_key_app/lib/routing/app_routes.dart | 2 + comwell_key_app/lib/services/api.dart | 13 +- .../lib/services/mappers/booking_mapper.dart | 41 ++- .../lib/services/mappers/bookings_mapper.dart | 9 +- .../lib/services/mappers/room_mapper.dart | 22 ++ comwell_key_app/lib/services/models/room_dto.dart | 34 +++ comwell_key_app/lib/themes/dark_theme.dart | 2 +- comwell_key_app/lib/themes/light_theme.dart | 3 +- .../up_sales/components/room_image_carousel.dart | 56 ++++ .../test/overview_test/overview_cubic_test.dart | 14 +- .../overview_test/overview_repository_test.dart | 6 +- 34 files changed, 1389 insertions(+), 202 deletions(-)
Diff
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index ef5e91b0..01e5c04b 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -294,5 +294,19 @@
"room_selection": "Vælg værelse",
"room_selection_subtitle": "Vælg et værelse til dit ophold",
"choose_room": "Vælg dit værelse",
- "choose_room_subtitle": "Du skal vælge dét værelse du gerne vil sove på. Når du har valgt, kan du tildele de andre værelser til andre."
+ "choose_room_subtitle": "Du skal vælge dét værelse du gerne vil sove på. Når du har valgt, kan du tildele de andre værelser til andre.",
+ "check_in_date": "Check-in dato",
+ "check_out_date": "Check-out dato",
+ "confirmation_number": "Bekræftelsesnummer",
+ "close": "Luk",
+ "choose_room_confirmation_title": "Er du sikker på du vil vælge dette værelse?",
+ "choose_room_confirmation_subtitle": "Du kan ikke fortryde dit valg. Resterende værelser skal fordeles.",
+ "choose_room_confirmation_confirm": "Ja, vælg værelse",
+ "choose_room_confirmation_cancel": "Nej",
+ "my_room": "Mit værelse",
+ "share_room": "Del værelse",
+ "share_room_page_title": "Del værelse",
+ "share_room_page_subtitle": "Her kan du dele dit værelse med en anden gæst og give dem adgang til bookinginformation, nøglekort og Concierge",
+ "share_room_page_button": "Del dit værelse",
+ "addon": "Tilkøbt"
}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/en-US.json b/comwell_key_app/assets/translations/en-US.json
index adcfd630..71112ebb 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -293,7 +293,19 @@
"room_selection": "Room selection",
"room_selection_subtitle": "Select a room for your stay",
"choose_room": "Choose room",
- "choose_room_subtitle": "You need to choose the room you want to sleep in. When you have chosen, you can assign the other rooms to others."
-
-
+ "choose_room_subtitle": "You need to choose the room you want to sleep in. When you have chosen, you can assign the other rooms to others.",
+ "check_in_date": "Check-in date",
+ "check_out_date": "Check-out date",
+ "confirmation_number": "Confirmation number",
+ "close": "Close",
+ "choose_room_confirmation_title": "Are you sure you want to choose this room?",
+ "choose_room_confirmation_subtitle": "You cannot undo your choice. Remaining rooms must be assigned.",
+ "choose_room_confirmation_confirm": "Yes, choose room",
+ "choose_room_confirmation_cancel": "No",
+ "my_room": "My room",
+ "share_room": "Share room",
+ "share_room_page_title": "Share room",
+ "share_room_page_subtitle": "Here you can share your room with another guest and give them access to booking information, keycard and Concierge",
+ "share_room_page_button": "Share your room",
+ "addon": "Added purchase"
}
diff --git a/comwell_key_app/lib/.generated/services/models/room_dto.g.dart b/comwell_key_app/lib/.generated/services/models/room_dto.g.dart
new file mode 100644
index 00000000..2b5496f8
--- /dev/null
+++ b/comwell_key_app/lib/.generated/services/models/room_dto.g.dart
@@ -0,0 +1,33 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of '../../../services/models/room_dto.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RoomDto _$RoomDtoFromJson(Map json) => RoomDto(
+ confirmationNumber: json['confirmationNumber'] as String,
+ assignedTo: json['assignedTo'] as String?,
+ name: json['name'] as String,
+ description: json['description'] as String,
+ guests: (json['guests'] as num).toInt(),
+ imageAssets:
+ (json['imageAssets'] as List<dynamic>?)?.map((e) => e as String) ??
+ [],
+ roomFacilities: (json['roomFacilities'] as List<dynamic>?)?.map((e) =>
+ RoomFacilityDTO.fromJson(Map<String, dynamic>.from(e as Map))) ??
+ [],
+ tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String) ?? [],
+ );
+
+Map<String, dynamic> _$RoomDtoToJson(RoomDto instance) => <String, dynamic>{
+ 'confirmationNumber': instance.confirmationNumber,
+ 'assignedTo': instance.assignedTo,
+ 'name': instance.name,
+ 'description': instance.description,
+ 'guests': instance.guests,
+ 'imageAssets': instance.imageAssets.toList(),
+ 'roomFacilities': instance.roomFacilities.map((e) => e.toJson()).toList(),
+ 'tags': instance.tags.toList(),
+ };
diff --git a/comwell_key_app/lib/check_in/check_in_repository.dart b/comwell_key_app/lib/check_in/check_in_repository.dart
index 193d39e4..3287eeec 100644
--- a/comwell_key_app/lib/check_in/check_in_repository.dart
+++ b/comwell_key_app/lib/check_in/check_in_repository.dart
@@ -73,5 +73,6 @@ class CheckInRepository {
bookingDate: DateTime.now(),
digitalCard: true,
guests: null,
+ rooms: const [],
);
}
diff --git a/comwell_key_app/lib/choose_share_room/choose_share_room_page.dart b/comwell_key_app/lib/choose_share_room/choose_share_room_page.dart
index 2404185c..a5309f68 100644
--- a/comwell_key_app/lib/choose_share_room/choose_share_room_page.dart
+++ b/comwell_key_app/lib/choose_share_room/choose_share_room_page.dart
@@ -1,9 +1,13 @@
+import 'package:comwell_key_app/choose_share_room/components/my_room_widget.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_cubit.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_state.dart';
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:comwell_key_app/choose_share_room/components/choose_room_widget.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/choose_share_room_shimmer_loader.dart';
class ChooseShareRoomPage extends StatelessWidget {
final Booking booking;
@@ -15,50 +19,54 @@ class ChooseShareRoomPage extends StatelessWidget {
return Scaffold(
backgroundColor: Colors.white,
appBar: const ComwellAppBar(),
- body: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ListView(
- children: [
- const SizedBox(height: 24),
- Text(
- 'choose_room'.tr(),
- style: theme.textTheme.headlineLarge,
- ),
- const SizedBox(height: 8),
- Text(
- 'choose_room_subtitle'.tr(),
- style: theme.textTheme.bodySmall,
- ),
- const SizedBox(height: 24),
- ChooseRoomWidget(
- booking: booking,
- roomName: 'Standard Single Room',
- description: 'Overnatning med morgenmad',
- guests: 1,
- imageAsset: 'assets/images/current_room.png',
- onSelect: () {},
- ),
- ChooseRoomWidget(
- booking: booking,
- roomName: 'Standard Twin Room',
- description: 'Overnatning med morgenmad',
- guests: 2,
- imageAsset: 'assets/images/borupgaard.png',
- extraInfo: 'Babyseng',
- onSelect: () {},
- ),
- ChooseRoomWidget(
- booking: booking,
- roomName: 'Standard Twin Room',
- description: 'Overnatning med morgenmad',
- guests: 2,
- imageAsset: 'assets/images/borupgaard.png',
- onSelect: () {},
+ body: BlocBuilder<ChooseShareRoomCubit, ChooseShareRoomState>(
+ builder: (context, state) {
+ if (state.isLoading) {
+ return const ChooseShareRoomShimmerLoader();
+ }
+
+ final cubit = context.read<ChooseShareRoomCubit>();
+
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ListView(
+ children: [
+ const SizedBox(height: 24),
+ Text(
+ 'choose_room'.tr(),
+ style: theme.textTheme.headlineLarge,
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'choose_room_subtitle'.tr(),
+ style: theme.textTheme.bodySmall,
+ ),
+ const SizedBox(height: 24),
+ ...cubit.rooms
+ .where((room) => room.assignedTo == null)
+ .map((room) => ChooseRoomWidget(
+ booking: booking,
+ roomName: room.name,
+ description: room.description,
+ guests: room.guests,
+ imageAsset: room.imageAssets.first,
+ )),
+ const SizedBox(height: 32),
+ if (cubit.rooms.any((room) => room.assignedTo != null))
+ ...cubit.rooms
+ .where((room) => room.assignedTo != null)
+ .map((room) => MyRoomWidget(
+ roomName: room.name,
+ description: room.description,
+ guests: room.guests,
+ imageAsset: room.imageAssets.first,
+ )),
+ const SizedBox(height: 32),
+ ],
),
- const SizedBox(height: 32),
- ],
- ),
+ );
+ },
),
);
}
-}
\ No newline at end of file
+}
diff --git a/comwell_key_app/lib/choose_share_room/choose_share_room_repository.dart b/comwell_key_app/lib/choose_share_room/choose_share_room_repository.dart
index 11663b35..4b3df905 100644
--- a/comwell_key_app/lib/choose_share_room/choose_share_room_repository.dart
+++ b/comwell_key_app/lib/choose_share_room/choose_share_room_repository.dart
@@ -1,5 +1,164 @@
+import 'package:comwell_key_app/overview/models/room.dart';
+import 'package:comwell_key_app/services/mappers/room_mapper.dart';
+import 'package:comwell_key_app/services/models/room_dto.dart';
+import 'package:comwell_key_app/up_sales/models/dto/room_facility_dto.dart';
+
class ChooseShareRoomRepository {
String baseUrl;
- ChooseShareRoomRepository({ this.baseUrl = ''});
-}
\ No newline at end of file
+ ChooseShareRoomRepository({this.baseUrl = ''});
+
+ Future<List<Room>> getMockRooms() async {
+ return mockRooms.toRooms();
+ }
+
+ Future<Room> assignRoom(String roomId, String userId) async {
+ await Future.delayed(const Duration(seconds: 2));
+ final room =
+ mockRooms.firstWhere((room) => room.confirmationNumber == roomId);
+ room.assignedTo = userId;
+ return room.toRoom();
+ }
+
+ List<RoomDto> mockRooms = [
+ RoomDto(
+ confirmationNumber: 'CONF001',
+ assignedTo: null,
+ name: 'Standard Double Room',
+ description:
+ 'A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience.',
+ guests: 2,
+ imageAssets: [
+ 'assets/images/welcome_image.jpeg',
+ 'assets/images/current_room.png'
+ ],
+ tags: ['34'],
+ roomFacilities: [
+ RoomFacilityDTO(
+ name: '1x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ ],
+ ),
+ RoomDto(
+ confirmationNumber: 'CONF002',
+ assignedTo: null,
+ name: 'Junior Suite',
+ description:
+ 'Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury.',
+ guests: 2,
+ imageAssets: ['assets/images/no_current_bookings_background.jpeg'],
+ tags: ['27'],
+ roomFacilities: [
+ RoomFacilityDTO(
+ name: '2x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'Badekar',
+ icon: 'assets/icons/ic_bathtub.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Terrasse',
+ icon: 'assets/icons/ic_balcony.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ RoomDto(
+ confirmationNumber: 'CONF003',
+ assignedTo: null,
+ name: 'Suite',
+ description:
+ 'Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay.',
+ guests: 2,
+ imageAssets: ['assets/images/current_room.png'],
+ tags: ['45'],
+ roomFacilities: [
+ RoomFacilityDTO(
+ name: '1x enkelseng',
+ icon: 'assets/icons/ic_single_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'Stue',
+ icon: 'assets/icons/ic_leather_chair.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Roomservice',
+ icon: 'assets/icons/ic_service_bowl.svg',
+ facilityType: 'Service'),
+ ],
+ ),
+ RoomDto(
+ confirmationNumber: 'CONF004',
+ assignedTo: null,
+ name: 'Standard Double Plus Room',
+ description:
+ 'An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay.',
+ guests: 2,
+ imageAssets: ['assets/images/login_screen_background.png'],
+ tags: ['45'],
+ roomFacilities: [
+ RoomFacilityDTO(
+ name: '2x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ ],
+ ),
+ RoomDto(
+ confirmationNumber: 'CONF005',
+ assignedTo: null,
+ name: 'Standard Twin Plus Room',
+ description:
+ 'A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together.',
+ guests: 2,
+ imageAssets: ['assets/images/login_screen_background.png'],
+ tags: ['32'],
+ roomFacilities: [
+ RoomFacilityDTO(
+ name: '2x enkelseng',
+ icon: 'assets/icons/ic_single_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Strygejern & -bræt',
+ icon: 'assets/icons/ic_iron.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ ];
+}
diff --git a/comwell_key_app/lib/choose_share_room/components/choose_room_widget.dart b/comwell_key_app/lib/choose_share_room/components/choose_room_widget.dart
index 818565c5..53072d73 100644
--- a/comwell_key_app/lib/choose_share_room/components/choose_room_widget.dart
+++ b/comwell_key_app/lib/choose_share_room/components/choose_room_widget.dart
@@ -1,8 +1,13 @@
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_cubit.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_state.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
+import 'package:go_router/go_router.dart';
class ChooseRoomWidget extends StatelessWidget {
final Booking booking;
@@ -11,7 +16,6 @@ class ChooseRoomWidget extends StatelessWidget {
final int guests;
final String imageAsset;
final String? extraInfo;
- final VoidCallback onSelect;
const ChooseRoomWidget({
super.key,
@@ -21,127 +25,218 @@ class ChooseRoomWidget extends StatelessWidget {
required this.guests,
required this.imageAsset,
this.extraInfo,
- required this.onSelect,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- return Container(
- margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 0),
- decoration: BoxDecoration(
- border: Border.all(color: colorDivider),
- borderRadius: BorderRadius.circular(16),
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.all(16.0),
- child: Row(
+ return BlocBuilder<ChooseShareRoomCubit, ChooseShareRoomState>(
+ builder: (context, state) {
+ final cubit = context.read<ChooseShareRoomCubit>();
+ final isAssigned = cubit.rooms.any((room) => room.confirmationNumber == booking.rooms.first.confirmationNumber && room.assignedTo != null);
+ return GestureDetector(
+ onTap: () {
+ context.pushNamed(AppRoutes.roomInfo.name, extra: booking);
+ },
+ child: Container(
+ margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 0),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(16),
+ ),
+ child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Expanded(
+ Padding(
+ padding: const EdgeInsets.all(16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- roomName,
- style: theme.textTheme.headlineSmall,
- ),
- const SizedBox(height: 4),
- Text(
- description,
- style: theme.textTheme.bodySmall,
- ),
- ],
- ),
- ClipRRect(
- borderRadius: BorderRadius.circular(8),
- child: Image.asset(
- imageAsset,
- width: 60,
- height: 60,
- fit: BoxFit.cover,
+ Expanded(
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ roomName,
+ style: theme.textTheme.headlineSmall,
+ ),
+ const SizedBox(height: 4),
+ SizedBox(
+ width: 200,
+ child: Text(
+ description,
+ style: theme.textTheme.bodySmall,
+ maxLines: 2,
+ overflow: TextOverflow.ellipsis,
+ softWrap: true,
+ ),
+ ),
+ ],
+ ),
+ ClipRRect(
+ borderRadius: BorderRadius.circular(8),
+ child: Image.asset(
+ imageAsset,
+ width: 60,
+ height: 60,
+ fit: BoxFit.cover,
+ ),
+ ),
+ ],
),
),
],
),
),
- ],
- ),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SvgPicture.asset("assets/icons/user-circle.svg",
- width: 20, height: 20),
- const SizedBox(width: 4),
- Text(
- '${booking.adults} ${booking.adults > 1 ? 'adults'.tr() : 'adult'.tr()}${booking.children > 0 ? ' | ${booking.children} ${booking.children > 1 ? 'children'.tr() : 'child'.tr()}' : ''}',
- style: theme.textTheme.bodySmall,
+ Padding(
+ padding:
+ const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 8.0),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SvgPicture.asset("assets/icons/user-circle.svg",
+ width: 20, height: 20),
+ const SizedBox(width: 4),
+ Text(
+ '${booking.adults} ${booking.adults > 1 ? 'adults'.tr() : 'adult'.tr()}${booking.children > 0 ? ' | ${booking.children} ${booking.children > 1 ? 'children'.tr() : 'child'.tr()}' : ''}',
+ style: theme.textTheme.bodySmall,
+ ),
+ const VerticalDivider(color: colorDivider, thickness: 1.5),
+ Text(
+ 'read_more'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ decoration: TextDecoration.underline,
+ ),
+ ),
+ ],
+ ),
),
- const SizedBox(width: 8),
- const VerticalDivider(),
- GestureDetector(
- onTap: () {},
- child: Text(
- 'read_more'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- decoration: TextDecoration.underline,
+ if (extraInfo != null) ...[
+ const SizedBox(height: 8),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
+ child: Text(
+ 'Tilkøbt på værelse',
+ style: theme.textTheme.bodySmall,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
+ child: Text(
+ extraInfo!,
+ style: theme.textTheme.bodySmall
+ ?.copyWith(fontWeight: FontWeight.bold),
),
),
+ const SizedBox(height: 8),
+ ],
+ Column(
+ children: [
+ const Divider(color: colorDivider),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 16.0, right: 16.0, top: 8.0, bottom: 16.0),
+ child: SizedBox(
+ width: double.infinity,
+ child: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ elevation: 0,
+ foregroundColor: Colors.white,
+ ),
+ onPressed: () async {
+ if (isAssigned) {
+ context.pushNamed(AppRoutes.shareRoom.name, extra: booking);
+ return;
+ }
+ await showDialog<bool>(
+ context: context,
+ barrierDismissible: false,
+ builder: (context) {
+ return _buildConfirmationDialog(context, cubit);
+ },
+ );
+ },
+ child: Text(isAssigned ? 'share_room'.tr() : 'choose_room'.tr()),
+ ),
+ ),
+ ),
+ ],
),
],
),
),
- if (extraInfo != null) ...[
- const SizedBox(height: 8),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
- child: Text(
- 'Tilkøbt på værelse',
- style: theme.textTheme.bodySmall,
- ),
+ );
+ }
+ );
+ }
+
+ Widget _buildConfirmationDialog(BuildContext context, ChooseShareRoomCubit cubit) {
+ final theme = Theme.of(context);
+ return Dialog(
+ backgroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(24),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 16.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ 'choose_room_confirmation_title'.tr(),
+ textAlign: TextAlign.center,
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(height: 16),
+ Text(
+ 'choose_room_confirmation_subtitle'.tr(),
+ textAlign: TextAlign.center,
+ style: theme.textTheme.bodySmall,
),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
- child: Text(
- extraInfo!,
- style: theme.textTheme.bodySmall
- ?.copyWith(fontWeight: FontWeight.bold),
+ const SizedBox(height: 32),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: sandColor,
+ foregroundColor: Colors.white,
+ elevation: 0,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(40),
+ ),
+ padding: const EdgeInsets.symmetric(vertical: 16),
),
+ onPressed: () {
+ cubit.assignRoomToUser(booking.rooms.first.confirmationNumber, booking.booker.id);
+ context.pop();
+ },
+ child: Text('choose_room_confirmation_confirm'.tr(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white)),
),
- const SizedBox(height: 8),
- ],
- Column(
- children: [
- const Divider(color: colorDivider),
- Padding(
- padding: const EdgeInsets.only(
- left: 16.0, right: 16.0, top: 8.0, bottom: 16.0),
- child: SizedBox(
- width: double.infinity,
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- elevation: 0,
- foregroundColor: Colors.white,
- ),
- onPressed: onSelect,
- child: const Text('Vælg værelse'),
- ),
+ const SizedBox(height: 16),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Colors.white,
+ foregroundColor: Colors.black,
+ elevation: 0,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(40),
),
+ side: const BorderSide(color: colorDivider),
+ padding: const EdgeInsets.symmetric(vertical: 16),
),
- ],
- ),
- ],
+ onPressed: () {
+ context.pop();
+ },
+ child: Text('choose_room_confirmation_cancel'.tr(),
+ style: theme.textTheme.headlineSmall),
+ ),
+ ],
+ ),
),
);
}
diff --git a/comwell_key_app/lib/choose_share_room/components/my_room_widget.dart b/comwell_key_app/lib/choose_share_room/components/my_room_widget.dart
new file mode 100644
index 00000000..5d82de69
--- /dev/null
+++ b/comwell_key_app/lib/choose_share_room/components/my_room_widget.dart
@@ -0,0 +1,110 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class MyRoomWidget extends StatelessWidget {
+ final String roomName;
+ final String description;
+ final int guests;
+ final String imageAsset;
+
+ const MyRoomWidget({
+ super.key,
+ required this.roomName,
+ required this.description,
+ required this.guests,
+ required this.imageAsset,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("my_room".tr(), style: theme.textTheme.headlineMedium),
+ const SizedBox(height: 8),
+ Opacity(
+ opacity: 0.5,
+ child: Container(
+ margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 0),
+ decoration: BoxDecoration(
+ border: Border.all(color: Colors.grey.shade300),
+ borderRadius: BorderRadius.circular(16),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ roomName,
+ style: theme.textTheme.headlineSmall,
+ ),
+ const SizedBox(height: 4),
+ SizedBox(
+ width: 200,
+ child: Text(
+ description,
+ style: theme.textTheme.bodySmall,
+ maxLines: 2,
+ overflow: TextOverflow.ellipsis,
+ softWrap: true,
+ ),
+ ),
+ ],
+ ),
+ ClipRRect(
+ borderRadius: BorderRadius.circular(8),
+ child: Image.asset(
+ imageAsset,
+ width: 60,
+ height: 60,
+ fit: BoxFit.cover,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 16.0, right: 16.0, bottom: 16.0),
+ child: Row(
+ children: [
+ SvgPicture.asset(
+ 'assets/icons/user-circle.svg',
+ width: 20,
+ height: 20,
+ ),
+ const SizedBox(width: 4),
+ Text(
+ guests == 1
+ ? '$guests adult'.tr()
+ : '$guests adults'.tr(),
+ style: theme.textTheme.bodySmall,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_cubit.dart b/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_cubit.dart
index b9e9f132..e49f7a67 100644
--- a/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_cubit.dart
+++ b/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_cubit.dart
@@ -1,9 +1,46 @@
+import 'package:comwell_key_app/choose_share_room/choose_share_room_repository.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_state.dart';
+import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:comwell_key_app/overview/models/room.dart';
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:share_plus/share_plus.dart';
class ChooseShareRoomCubit extends Cubit<ChooseShareRoomState> {
- ChooseShareRoomCubit() : super(ChooseShareRoomInitial());
-}
+ final ChooseShareRoomRepository chooseShareRoomRepository;
+ List<Room> rooms = [];
+ ChooseShareRoomCubit(this.chooseShareRoomRepository)
+ : super(ChooseShareRoomState.initial());
+
+ void init() async {
+ emit(ChooseShareRoomState.loading());
+ rooms = await chooseShareRoomRepository.getMockRooms();
+ emit(ChooseShareRoomState.main(rooms));
+ }
+
+ Future<void> shareRoom(Booking booking) async {
+ Share.share(
+ '${booking.hotelName}\n\n'
+ '${'dates'.tr()}: ${DateFormat('d. MMM').format(booking.startDate)} - ${DateFormat('d. MMM').format(booking.endDate)}\n'
+ '${'guests'.tr()}: ${booking.adults} ${booking.adults > 1 ? 'adults'.tr() : 'adult'.tr()}${booking.children > 0 ? ' | ${booking.children} ${booking.children > 1 ? 'children'.tr() : 'child'.tr()}' : ''}\n\n'
+ '${'view_booking'.tr()}: https://comwell.app/booking/${booking.id}',
+ subject: 'comwell_booking'.tr(),
+ );
+ }
-class ChooseShareRoomState {}
+ Future<Room> assignRoomToUser(String roomId, String userId) async {
+ emit(ChooseShareRoomState.loading());
+ try {
+ final room = await chooseShareRoomRepository.assignRoom(roomId, userId);
-class ChooseShareRoomInitial extends ChooseShareRoomState {}
\ No newline at end of file
+ rooms =
+ rooms.map((r) => r.confirmationNumber == roomId ? room : r).toList();
+
+ emit(ChooseShareRoomState.main(rooms));
+ return room;
+ } catch (e) {
+ emit(ChooseShareRoomState.error(e as Error));
+ rethrow;
+ }
+ }
+}
diff --git a/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_state.dart b/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_state.dart
index cd0e985f..22674791 100644
--- a/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_state.dart
+++ b/comwell_key_app/lib/choose_share_room/cubit/choose_share_room_state.dart
@@ -1,3 +1,33 @@
-class ChooseShareRoomState {}
+import 'package:comwell_key_app/overview/models/room.dart';
+import 'package:equatable/equatable.dart';
-class ChooseShareRoomInitial extends ChooseShareRoomState {}
\ No newline at end of file
+class ChooseShareRoomState extends Equatable {
+ final Error? error;
+ final bool isLoading;
+ final List<Room> rooms;
+
+ const ChooseShareRoomState._(
+ {required this.rooms, required this.error, required this.isLoading});
+
+ ChooseShareRoomState.initial() : this._(rooms: [], error: null, isLoading: false);
+
+ ChooseShareRoomState.loading() : this._(rooms: [], error: null, isLoading: true);
+ ChooseShareRoomState.error(Error error) : this._(rooms: [], error: error, isLoading: false);
+ const ChooseShareRoomState.loaded(List<Room> rooms) : this._(rooms: rooms, error: null, isLoading: false);
+ ChooseShareRoomState.assigned(Room room) : this._(rooms: [room], error: null, isLoading: false);
+ const ChooseShareRoomState.main(List<Room> rooms) : this._(rooms: rooms, error: null, isLoading: false);
+
+ @override
+ List<Object?> get props => [rooms, error, isLoading];
+
+ ChooseShareRoomState copyWith({
+ List<Room>? rooms,
+ Error? error,
+ bool? isLoading,
+ }) {
+ return ChooseShareRoomState._(
+ rooms: rooms ?? this.rooms,
+ error: error ?? this.error,
+ isLoading: isLoading ?? this.isLoading);
+ }
+}
diff --git a/comwell_key_app/lib/choose_share_room/pages/room_info_page.dart b/comwell_key_app/lib/choose_share_room/pages/room_info_page.dart
new file mode 100644
index 00000000..3d26fb1b
--- /dev/null
+++ b/comwell_key_app/lib/choose_share_room/pages/room_info_page.dart
@@ -0,0 +1,198 @@
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_cubit.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_state.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/const.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/up_sales/components/room_image_carousel.dart';
+import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:comwell_key_app/up_sales/components/facility_icon_text.dart';
+import 'package:comwell_key_app/up_sales/components/facilities_bottom_sheet.dart';
+import 'package:comwell_key_app/up_sales/components/tags.dart';
+import 'package:comwell_key_app/up_sales/models/room_facility.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/room_info_shimmer_loader.dart';
+
+class RoomInfoPage extends StatefulWidget {
+ final Booking booking;
+ const RoomInfoPage({super.key, required this.booking});
+
+ @override
+ State<RoomInfoPage> createState() => _RoomInfoPageState();
+}
+
+class _RoomInfoPageState extends State<RoomInfoPage> {
+ bool _isExpanded = false;
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final images = widget.booking.rooms
+ .map((room) => room.imageAssets)
+ .toList(); // Use booking image
+ final room =
+ widget.booking.rooms.isNotEmpty ? widget.booking.rooms.first : null;
+ final facilities = room?.roomFacilities.toList() ?? <RoomFacility>[];
+ final hasFacilities = facilities.isNotEmpty;
+ final description = room?.description ?? '';
+
+ return BlocBuilder<ChooseShareRoomCubit, ChooseShareRoomState>(
+ builder: (context, state) {
+ if (state.isLoading) {
+ return const RoomInfoShimmerLoader();
+ }
+
+ return Scaffold(
+ extendBodyBehindAppBar: true,
+ appBar: const ComwellAppBar(),
+ backgroundColor: Colors.white,
+ body: SingleChildScrollView(
+ physics: const AlwaysScrollableScrollPhysics(),
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ minHeight:
+ MediaQuery.of(context).size.height - kComwellAppBarHeight - 80,
+ ),
+ child: Column(
+ children: [
+ RoomImageCarousel(images: images.expand((x) => x).toList()),
+ Container(
+ width: double.infinity,
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(24),
+ topRight: Radius.circular(24),
+ ),
+ ),
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ room?.name ?? '',
+ style: theme.textTheme.headlineLarge,
+ ),
+ if (room?.tags.isNotEmpty ?? false)
+ TagWidget(
+ text: '${room?.tags.first} M2',
+ textColor: sandColor),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Text(
+ description.isNotEmpty
+ ? description
+ : '${widget.booking.hotelName} - ${widget.booking.adults} adults, ${widget.booking.children} children',
+ style: theme.textTheme.bodySmall,
+ maxLines: _isExpanded ? null : 3,
+ overflow: _isExpanded ? null : TextOverflow.ellipsis,
+ ),
+ const SizedBox(height: 4),
+ GestureDetector(
+ onTap: () {
+ setState(() {
+ _isExpanded = !_isExpanded;
+ });
+ },
+ child: Text(
+ _isExpanded ? 'read_less'.tr() : 'read_more'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor,
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor,
+ ),
+ ),
+ ),
+ const SizedBox(height: 24),
+ if (hasFacilities) ...[
+ Wrap(
+ spacing: 8,
+ runSpacing: 8,
+ children: [
+ ...facilities.map((f) => FacilityIconText(
+ facility: f, showDivider: true)),
+ GestureDetector(
+ onTap: () =>
+ _showFacilitiesSheet(context, facilities),
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 4.0),
+ child: Text(
+ 'see_all_facilities'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor,
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 32),
+ ],
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ bottomNavigationBar: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Divider(color: colorDivider),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 16.0,
+ right: 16.0,
+ top: 16.0,
+ bottom: 40,
+ ),
+ child: ElevatedButton(
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ child: Text(
+ 'choose_room'.tr(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+ );
+ }
+
+ void _showFacilitiesSheet(
+ BuildContext context, List<RoomFacility> facilities) {
+ final height = MediaQuery.of(context).size.height;
+ showModalBottomSheet<void>(
+ context: context,
+ isScrollControlled: true,
+ enableDrag: true,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
+ ),
+ builder: (context) {
+ return ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: height - kComwellAppBarHeight,
+ ),
+ child: FacilitiesBottomSheet(facilities: facilities),
+ );
+ },
+ );
+ }
+}
diff --git a/comwell_key_app/lib/choose_share_room/pages/share_room_page.dart b/comwell_key_app/lib/choose_share_room/pages/share_room_page.dart
new file mode 100644
index 00000000..65b925ed
--- /dev/null
+++ b/comwell_key_app/lib/choose_share_room/pages/share_room_page.dart
@@ -0,0 +1,175 @@
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_cubit.dart';
+import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_state.dart';
+import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+
+class ShareRoomPage extends StatelessWidget {
+ final Booking booking;
+ const ShareRoomPage({super.key, required this.booking});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return BlocBuilder<ChooseShareRoomCubit, ChooseShareRoomState>(
+ builder: (context, state) {
+ final cubit = context.read<ChooseShareRoomCubit>();
+ return Scaffold(
+ backgroundColor: sandColor,
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const SizedBox(width: 52),
+ Text('share_room_page_title'.tr(),
+ style: theme.textTheme.headlineMedium
+ ?.copyWith(color: Colors.white)),
+ Padding(
+ padding: const EdgeInsets.only(right: 16),
+ child: ElevatedButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ style: ElevatedButton.styleFrom(
+ minimumSize: const Size(36, 36),
+ padding: EdgeInsets.zero,
+ backgroundColor: Colors.white,
+ shape: const CircleBorder(),
+ elevation: 0,
+ ),
+ child: const Icon(
+ Icons.close,
+ color: Colors.black,
+ size: 24,
+ ),
+ ),
+ )
+ ],
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 32),
+ child: Card(
+ color: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ elevation: 2,
+ margin: const EdgeInsets.symmetric(horizontal: 24),
+ clipBehavior: Clip.antiAlias,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Stack(
+ children: [
+ ClipRRect(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ child: Image.asset(
+ 'assets/images/borupgaard.png',
+ height: 200,
+ width: double.infinity,
+ fit: BoxFit.cover,
+ ),
+ ),
+ Positioned(
+ top: 16,
+ left: 16,
+ child: Text(
+ booking.hotelName,
+ style: theme.textTheme.headlineLarge
+ ?.copyWith(color: Colors.white),
+ ),
+ ),
+ ],
+ ),
+ Padding(
+ padding: const EdgeInsets.all(20.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(booking.rooms.first.name,
+ style: theme.textTheme.headlineMedium),
+ const SizedBox(height: 4),
+ Text(
+ booking.rooms.first.description,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ ),
+ ),
+ const SizedBox(height: 16),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SvgPicture.asset('assets/icons/user-circle.svg',
+ width: 24, height: 24),
+ const SizedBox(width: 4),
+ Text(
+ '${booking.adults} ${booking.adults > 1 ? 'adults'.tr() : 'adult'.tr()}${booking.children > 0 ? ' | ${booking.children} ${booking.children > 1 ? 'children'.tr() : 'child'.tr()}' : ''}',
+ style: theme.textTheme.bodySmall,
+ ),
+ ],
+ ),
+ const SizedBox(height: 16),
+ Text(
+ 'addon'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ ),
+ ),
+ Text('Babyseng', style: theme.textTheme.headlineSmall),
+ const SizedBox(height: 24),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 40),
+ child: Text(
+ 'share_room_page_subtitle'.tr(),
+ style: Theme.of(context).textTheme.bodySmall?.copyWith(
+ color: Colors.white.withValues(alpha: 0.65),
+ ),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: SizedBox(
+ width: double.infinity,
+ child: ElevatedButton(
+ onPressed: () {
+ cubit.shareRoom(booking);
+ },
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Colors.white,
+ minimumSize: const Size.fromHeight(52),
+ elevation: 0,
+ ),
+ child: Text('share_room_page_button'.tr(),
+ style: theme.textTheme.bodyMedium?.copyWith(
+ color: Colors.black,
+ )),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+ );
+ }
+}
diff --git a/comwell_key_app/lib/common/components/shimmer_loader/choose_share_room_shimmer_loader.dart b/comwell_key_app/lib/common/components/shimmer_loader/choose_share_room_shimmer_loader.dart
new file mode 100644
index 00000000..f8161616
--- /dev/null
+++ b/comwell_key_app/lib/common/components/shimmer_loader/choose_share_room_shimmer_loader.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+import 'package:shimmer/shimmer.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/placeholders/title_placeholder.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/placeholders/content_placeholder.dart';
+
+class ChooseShareRoomShimmerLoader extends StatelessWidget {
+ const ChooseShareRoomShimmerLoader({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Shimmer.fromColors(
+ baseColor: sandColor[40]!,
+ highlightColor: sandColor[10]!,
+ enabled: true,
+ child: ListView(
+ children: [
+ const SizedBox(height: 24),
+ const TitlePlaceholder(width: 180),
+ const SizedBox(height: 8),
+ const TitlePlaceholder(width: double.infinity),
+ const SizedBox(height: 24),
+ ...List.generate(3, (index) => const Padding(
+ padding: EdgeInsets.only(bottom: 24),
+ child: ContentPlaceholder(lineType: ContentLineType.threeLines),
+ )),
+ const SizedBox(height: 32),
+ ],
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/common/components/shimmer_loader/room_info_shimmer_loader.dart b/comwell_key_app/lib/common/components/shimmer_loader/room_info_shimmer_loader.dart
new file mode 100644
index 00000000..9cecdd7a
--- /dev/null
+++ b/comwell_key_app/lib/common/components/shimmer_loader/room_info_shimmer_loader.dart
@@ -0,0 +1,50 @@
+import 'package:flutter/material.dart';
+import 'package:shimmer/shimmer.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/placeholders/banner_placeholder.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/placeholders/title_placeholder.dart';
+import 'package:comwell_key_app/common/components/shimmer_loader/placeholders/content_placeholder.dart';
+
+class RoomInfoShimmerLoader extends StatelessWidget {
+ const RoomInfoShimmerLoader({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Shimmer.fromColors(
+ baseColor: sandColor[40]!,
+ highlightColor: sandColor[10]!,
+ enabled: true,
+ child: ListView(
+ children: [
+ const BannerPlaceholder(),
+ const SizedBox(height: 16),
+ const TitlePlaceholder(width: double.infinity),
+ const SizedBox(height: 16),
+ const ContentPlaceholder(lineType: ContentLineType.threeLines),
+ const SizedBox(height: 16),
+ Row(
+ children: List.generate(4, (index) => const Padding(
+ padding: EdgeInsets.only(right: 8.0),
+ child: ContentPlaceholder(lineType: ContentLineType.twoLines),
+ )),
+ ),
+ const SizedBox(height: 32),
+ const Padding(
+ padding: EdgeInsets.symmetric(horizontal: 32.0),
+ child: SizedBox(
+ width: double.infinity,
+ height: 48,
+ child: DecoratedBox(
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.all(Radius.circular(8)),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 24),
+ ],
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/overview/components/current_booking_list_item_view.dart b/comwell_key_app/lib/overview/components/current_booking_list_item_view.dart
index 8494df02..2a131b29 100644
--- a/comwell_key_app/lib/overview/components/current_booking_list_item_view.dart
+++ b/comwell_key_app/lib/overview/components/current_booking_list_item_view.dart
@@ -1,8 +1,6 @@
import 'package:comwell_key_app/overview/components/prepare_room_widget.dart';
-import 'package:comwell_key_app/overview/components/room_selection_widget.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
diff --git a/comwell_key_app/lib/overview/components/current_bookings_tab_view.dart b/comwell_key_app/lib/overview/components/current_bookings_tab_view.dart
index 1873d602..7702b2a2 100644
--- a/comwell_key_app/lib/overview/components/current_bookings_tab_view.dart
+++ b/comwell_key_app/lib/overview/components/current_bookings_tab_view.dart
@@ -2,13 +2,10 @@ import 'package:comwell_key_app/overview/components/current_booking_list_item_vi
import 'package:comwell_key_app/overview/components/room_selection_widget.dart';
import 'package:comwell_key_app/overview/cubit/overview_cubit.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
-import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:comwell_key_app/common/components/shimmer_loader/overview_shimmer_loader.dart';
-import 'package:go_router/go_router.dart';
class CurrentBookingsTabView extends StatelessWidget {
final Iterable<Booking> bookings;
@@ -103,8 +100,7 @@ class CurrentBookingsTabView extends StatelessWidget {
return Column(
children: [
CurrentBookingListItem(booking: booking),
- if (booking.reservationStatus == ReservationStatus.checkedin)
- RoomSelectionWidget(booking: booking),
+ RoomSelectionWidget(booking: booking),
],
);
},
diff --git a/comwell_key_app/lib/overview/cubit/overview_cubit.dart b/comwell_key_app/lib/overview/cubit/overview_cubit.dart
index 5bcfb162..d7ef0698 100644
--- a/comwell_key_app/lib/overview/cubit/overview_cubit.dart
+++ b/comwell_key_app/lib/overview/cubit/overview_cubit.dart
@@ -16,6 +16,7 @@ class OverviewCubit extends Cubit<OverviewState> {
try {
final bookings = await overviewRepository.fetchAllBookingsForUser();
+
emit(OverviewLoaded(bookings: bookings));
} catch (e, st) {
if (kDebugMode) print("err=$e, $st");
diff --git a/comwell_key_app/lib/overview/models/booking.dart b/comwell_key_app/lib/overview/models/booking.dart
index dacc36bd..7b889ebf 100644
--- a/comwell_key_app/lib/overview/models/booking.dart
+++ b/comwell_key_app/lib/overview/models/booking.dart
@@ -1,5 +1,6 @@
import 'package:comwell_key_app/overview/models/guest.dart';
import 'package:comwell_key_app/overview/models/payment_details.dart';
+import 'package:comwell_key_app/overview/models/room.dart';
import 'package:equatable/equatable.dart';
class Booking extends Equatable {
@@ -23,6 +24,7 @@ class Booking extends Equatable {
final num? totalCharge;
final num? balance;
final String? maskedCardNumber;
+ final List<Room> rooms;
Booking({
required this.id,
@@ -44,6 +46,7 @@ class Booking extends Equatable {
required this.totalCharge,
required this.balance,
required this.maskedCardNumber,
+ required this.rooms,
Iterable<Guest>? guests,
}) : guests = _ensureBookerInGuestList(booker, guests ?? []);
@@ -84,6 +87,7 @@ class Booking extends Equatable {
balance,
maskedCardNumber,
reservationStatus,
+ rooms,
];
Booking copyWith({
@@ -106,6 +110,7 @@ class Booking extends Equatable {
String? confirmationId,
Iterable<Guest>? guests,
num? totalCharge,
+ List<Room>? rooms,
}) {
return Booking(
id: id ?? this.id,
@@ -128,6 +133,7 @@ class Booking extends Equatable {
totalCharge: totalCharge ?? this.totalCharge,
balance: balance,
maskedCardNumber: maskedCardNumber,
+ rooms: rooms ?? this.rooms,
);
}
diff --git a/comwell_key_app/lib/overview/models/room.dart b/comwell_key_app/lib/overview/models/room.dart
new file mode 100644
index 00000000..34cf0ec8
--- /dev/null
+++ b/comwell_key_app/lib/overview/models/room.dart
@@ -0,0 +1,28 @@
+import 'package:comwell_key_app/up_sales/models/room_facility.dart';
+
+class Room {
+ final String confirmationNumber;
+ String? assignedTo;
+ final String name;
+ final String description;
+ final int guests;
+ final Iterable<String> imageAssets;
+ final Iterable<RoomFacility> roomFacilities;
+ final Iterable<String> tags;
+
+ Room({
+ required this.confirmationNumber,
+ this.assignedTo,
+ required this.name,
+ required this.description,
+ required this.guests,
+ required this.imageAssets,
+ required this.roomFacilities,
+ required this.tags,
+ });
+
+ @override
+ String toString() {
+ return 'Room(confirmationNumber: $confirmationNumber, assignedTo: $assignedTo, name: $name, description: $description, guests: $guests, imageAssets: $imageAssets, roomFacilities: $roomFacilities, tags: $tags)';
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/overview/repository/overview_repository.dart b/comwell_key_app/lib/overview/repository/overview_repository.dart
index f98ffe18..31fd1c06 100644
--- a/comwell_key_app/lib/overview/repository/overview_repository.dart
+++ b/comwell_key_app/lib/overview/repository/overview_repository.dart
@@ -1,7 +1,9 @@
+import 'package:comwell_key_app/choose_share_room/choose_share_room_repository.dart';
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/models/bookings.dart';
import 'package:comwell_key_app/overview/models/guest.dart';
+import 'package:comwell_key_app/overview/models/room.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
@@ -13,16 +15,19 @@ class OverviewRepository {
final api = Api();
final database = locator<ComwellDatabase>();
final profileRepository = locator<ProfileRepository>();
+ final chooseShareRoomRepository = locator<ChooseShareRoomRepository>();
OverviewRepository();
Future<Bookings> fetchAllBookingsForUser() async {
try {
final response = await api.fetchAllBookingsForUser();
-
+
final user = await profileRepository.fetchProfileSettings();
+ final rooms = await chooseShareRoomRepository.getMockRooms();
await database.bookingsDao.insertBookings(response);
- return response.toBookings(user.id);
+
+ return response.toBookings(user.id, rooms);
} catch (e) {
throw Exception('Failed to fetch bookings $e');
}
@@ -54,27 +59,38 @@ class OverviewRepository {
totalCharge: 12345,
balance: 0,
maskedCardNumber: "1234567890");
- return dto.toBooking(user.id, BookingStatus.current);
+ return dto.toBooking(user.id, BookingStatus.current, []);
}
}
final mockBookings = [1, 2, 3].map((i) => Booking(
- id: "id$i",
- confirmationId: "confirmationId$i",
- roomNumber: "roomNumber$i",
- startDate: DateTime.now(),
- endDate: DateTime.now(),
- bookingStatus: BookingStatus.current,
- reservationStatus: ReservationStatus.newreservation,
- image: "assets/images/no_current_bookings_background.jpeg",
- hotelName: "hotelName$i",
- roomType: "roomType$i",
- totalCharge: 100,
- children: 3,
- adults: 3,
- hotelCode: "hotelCode$i",
- booker: const Guest(id: "id", name: "name"),
- bookingDate: DateTime.now(),
- digitalCard: false,
- balance: 0,
- maskedCardNumber: "1234567890"));
+ id: "id$i",
+ confirmationId: "confirmationId$i",
+ roomNumber: "roomNumber$i",
+ startDate: DateTime.now(),
+ endDate: DateTime.now(),
+ bookingStatus: BookingStatus.current,
+ reservationStatus: ReservationStatus.newreservation,
+ image: "assets/images/no_current_bookings_background.jpeg",
+ hotelName: "hotelName$i",
+ roomType: "roomType$i",
+ totalCharge: 100,
+ children: 3,
+ adults: 3,
+ hotelCode: "hotelCode$i",
+ booker: const Guest(id: "id", name: "name"),
+ bookingDate: DateTime.now(),
+ digitalCard: false,
+ balance: 0,
+ maskedCardNumber: "1234567890",
+ rooms: [
+ Room(
+ confirmationNumber: "CONF00$i",
+ assignedTo: "assignedTo$i",
+ name: "roomName$i",
+ description: "roomDescription$i",
+ guests: 3,
+ imageAssets: ["roomImageAsset$i"],
+ roomFacilities: [],
+ tags: ["10 M2"])
+ ]));
diff --git a/comwell_key_app/lib/pregistration/pregistration_repository.dart b/comwell_key_app/lib/pregistration/pregistration_repository.dart
index c55a1367..d635ab58 100644
--- a/comwell_key_app/lib/pregistration/pregistration_repository.dart
+++ b/comwell_key_app/lib/pregistration/pregistration_repository.dart
@@ -22,7 +22,6 @@ class PreregistrationRepository {
final id = sessionResponse["id"] as String;
final sessionData = sessionResponse["sessionData"] as String;
- print("sessionResponse ${sessionResponse["amount"]["value"]}");
final session = await AdyenCheckout.session.create(
sessionId: id,
sessionData: sessionData,
diff --git a/comwell_key_app/lib/profile/profile_repository.dart b/comwell_key_app/lib/profile/profile_repository.dart
index 96132980..ecca5f05 100644
--- a/comwell_key_app/lib/profile/profile_repository.dart
+++ b/comwell_key_app/lib/profile/profile_repository.dart
@@ -52,7 +52,7 @@ class ProfileRepository {
user = await fetchProfileSettings();
final response = await api.getBookingDetails(bookingId);
await db.bookingsDao.insertBookings(BookingsDTO(current: [response!], past: [], cancelled: []));
- final booking = response.toBooking(user.id, BookingStatus.current);
+ final booking = response.toBooking(user.id, BookingStatus.current, []);
return booking;
}
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index 14736b5a..05912bfa 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -6,7 +6,10 @@ import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
import 'package:comwell_key_app/check_out/bloc/check_out_state.dart';
import 'package:comwell_key_app/check_out/check_out_flow.dart';
import 'package:comwell_key_app/choose_share_room/choose_share_room_page.dart';
+import 'package:comwell_key_app/choose_share_room/choose_share_room_repository.dart';
import 'package:comwell_key_app/choose_share_room/cubit/choose_share_room_cubit.dart';
+import 'package:comwell_key_app/choose_share_room/pages/room_info_page.dart';
+import 'package:comwell_key_app/choose_share_room/pages/share_room_page.dart';
import 'package:comwell_key_app/common/const.dart';
import 'package:comwell_key_app/contact/contact_page.dart';
import 'package:comwell_key_app/contact/cubit/contact_cubit.dart';
@@ -447,11 +450,33 @@ GoRouter goRouter() {
builder: (context, state) {
final booking = state.extra as Booking;
return BlocProvider(
- create: (context) => ChooseShareRoomCubit(),
+ create: (context) => ChooseShareRoomCubit(locator<ChooseShareRoomRepository>())..init(),
child: ChooseShareRoomPage(booking: booking),
);
},
),
+ GoRoute(
+ path: "/${AppRoutes.roomInfo.name}",
+ name: AppRoutes.roomInfo.name,
+ builder: (context, state) {
+ final booking = state.extra as Booking;
+ return BlocProvider(
+ create: (context) => ChooseShareRoomCubit(locator<ChooseShareRoomRepository>()),
+ child: RoomInfoPage(booking: booking),
+ );
+ },
+ ),
+ GoRoute(
+ path: "/${AppRoutes.shareRoom.name}",
+ name: AppRoutes.shareRoom.name,
+ builder: (context, state) {
+ final booking = state.extra as Booking;
+ return BlocProvider(
+ create: (context) => ChooseShareRoomCubit(locator<ChooseShareRoomRepository>()),
+ child: ShareRoomPage(booking: booking),
+ );
+ },
+ ),
/* GoRoute(
path: "/keys",
name: AppRoutes.keys.name,
diff --git a/comwell_key_app/lib/routing/app_routes.dart b/comwell_key_app/lib/routing/app_routes.dart
index d8a3c915..4620275a 100644
--- a/comwell_key_app/lib/routing/app_routes.dart
+++ b/comwell_key_app/lib/routing/app_routes.dart
@@ -33,4 +33,6 @@ enum AppRoutes {
upSaleConfirmation,
upSalesAnimation,
chooseShareRoom,
+ roomInfo,
+ shareRoom,
}
diff --git a/comwell_key_app/lib/services/api.dart b/comwell_key_app/lib/services/api.dart
index 4e08aaae..24ee76b9 100644
--- a/comwell_key_app/lib/services/api.dart
+++ b/comwell_key_app/lib/services/api.dart
@@ -1,6 +1,4 @@
import 'dart:convert';
-
-import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:comwell_key_app/hotel_information/models/hotel.dart';
import 'package:comwell_key_app/housekeeping/models/housekeeping.dart';
import 'package:comwell_key_app/notifications/models/notification_permission.dart';
@@ -52,7 +50,6 @@ class Api {
final response =
await dio.post<dynamic>(ApiEndpoints.createAdyenSession, data: json);
- print("response ${response.data}");
return response.data;
}
@@ -238,6 +235,16 @@ class Api {
return BookingDTO.fromJson(response.data!);
}
+ Future<Json> postRoomSelection(String bookingId, String userId ) async {
+ final body = {
+ "bookingConfirmationId": bookingId,
+ "userId": userId,
+ };
+ final data = jsonEncode(body);
+ final response = await dio.post<Json>('ApiEndpoints.roomSelection', data: data);
+ return response.data!;
+ }
+
Future<Json> fetchUpSales() async {
// final response = await dio.get<Json>(ApiEndpoints.upSales);
// return response.data!.map((json) => RoomUpgrade.fromJson(json)).toList();
diff --git a/comwell_key_app/lib/services/mappers/booking_mapper.dart b/comwell_key_app/lib/services/mappers/booking_mapper.dart
index 47195266..a11208d6 100644
--- a/comwell_key_app/lib/services/mappers/booking_mapper.dart
+++ b/comwell_key_app/lib/services/mappers/booking_mapper.dart
@@ -1,10 +1,13 @@
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/models/guest.dart';
+import 'package:comwell_key_app/overview/models/room.dart';
import 'package:comwell_key_app/services/models/booking_dto.dart';
+import 'package:comwell_key_app/services/models/room_dto.dart';
+import 'package:comwell_key_app/services/mappers/room_mapper.dart';
//TODO: Fix actual image
extension BookingDTOMapper on BookingDTO {
- Booking toBooking(int userId, BookingStatus status) {
+ Booking toBooking(int userId, BookingStatus status, List<Room> rooms) {
final startDate = DateTime.parse(dayIn);
final endDate = DateTime.parse(dayOut!);
return Booking(
@@ -27,6 +30,7 @@ extension BookingDTOMapper on BookingDTO {
digitalCard: true,
balance: balance,
maskedCardNumber: maskedCardNumber,
+ rooms: rooms,
);
}
}
@@ -55,7 +59,38 @@ extension BookingMapper on Booking {
}
}
+extension BookingWithRoomsMapper on Booking {
+ Booking withRooms(List<Room> rooms) {
+ return Booking(
+ id: id,
+ confirmationId: confirmationId,
+ roomNumber: roomNumber,
+ startDate: startDate,
+ endDate: endDate,
+ bookingStatus: bookingStatus,
+ reservationStatus: reservationStatus,
+ image: image,
+ hotelName: hotelName,
+ roomType: roomType,
+ totalCharge: totalCharge,
+ children: children,
+ booker: booker,
+ adults: adults,
+ hotelCode: hotelCode,
+ bookingDate: bookingDate,
+ digitalCard: digitalCard,
+ balance: balance,
+ maskedCardNumber: maskedCardNumber,
+ rooms: rooms,
+ );
+ }
+}
+
+ extension ListRoomMapper on List<RoomDto> {
+ List<Room> toRooms() => map((dto) => dto.toRoom()).toList();
+ }
+
extension ListBookingMapper on Iterable<BookingDTO> {
- Iterable<Booking> toBookings(int userId, BookingStatus status) =>
- map((dto) => dto.toBooking(userId, status));
+ Iterable<Booking> toBookings(int userId, BookingStatus status, List<Room> rooms) =>
+ map((dto) => dto.toBooking(userId, status, rooms));
}
diff --git a/comwell_key_app/lib/services/mappers/bookings_mapper.dart b/comwell_key_app/lib/services/mappers/bookings_mapper.dart
index 46e5462c..877f6890 100644
--- a/comwell_key_app/lib/services/mappers/bookings_mapper.dart
+++ b/comwell_key_app/lib/services/mappers/bookings_mapper.dart
@@ -1,14 +1,15 @@
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/models/bookings.dart';
+import 'package:comwell_key_app/overview/models/room.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
import 'package:comwell_key_app/services/models/bookings_dto.dart';
extension BookingsMapper on BookingsDTO {
- Bookings toBookings(int userId) {
+ Bookings toBookings(int userId, List<Room> rooms) {
return Bookings(
- current: current.toBookings(userId, BookingStatus.current),
- past: past.toBookings(userId, BookingStatus.past),
- cancelled: cancelled.toBookings(userId, BookingStatus.cancelled),
+ current: current.toBookings(userId, BookingStatus.current, rooms),
+ past: past.toBookings(userId, BookingStatus.past, rooms),
+ cancelled: cancelled.toBookings(userId, BookingStatus.cancelled, rooms),
);
}
}
diff --git a/comwell_key_app/lib/services/mappers/room_mapper.dart b/comwell_key_app/lib/services/mappers/room_mapper.dart
new file mode 100644
index 00000000..80dc11ae
--- /dev/null
+++ b/comwell_key_app/lib/services/mappers/room_mapper.dart
@@ -0,0 +1,22 @@
+import 'package:comwell_key_app/overview/models/room.dart';
+import 'package:comwell_key_app/services/models/room_dto.dart';
+import 'package:comwell_key_app/up_sales/mappers/room_facility_mapper.dart';
+
+extension RoomDTOMapper on RoomDto {
+ Room toRoom() {
+ return Room(
+ confirmationNumber: confirmationNumber,
+ assignedTo: assignedTo,
+ name: name,
+ description: description,
+ guests: guests,
+ imageAssets: imageAssets,
+ roomFacilities: roomFacilities.toRoomFacilities(),
+ tags: tags,
+ );
+ }
+}
+
+extension ListRoomMapper on List<RoomDto> {
+ List<Room> toRooms() => map((dto) => dto.toRoom()).toList();
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/services/models/room_dto.dart b/comwell_key_app/lib/services/models/room_dto.dart
new file mode 100644
index 00000000..e478f873
--- /dev/null
+++ b/comwell_key_app/lib/services/models/room_dto.dart
@@ -0,0 +1,34 @@
+import 'package:comwell_key_app/up_sales/models/dto/room_facility_dto.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part '../../.generated/services/models/room_dto.g.dart';
+
+@JsonSerializable()
+class RoomDto {
+ final String confirmationNumber;
+ String? assignedTo;
+ final String name;
+ final String description;
+ final int guests;
+ @JsonKey(defaultValue: [])
+ final Iterable<String> imageAssets;
+ @JsonKey(defaultValue: [])
+ final Iterable<RoomFacilityDTO> roomFacilities;
+ @JsonKey(defaultValue: [])
+ final Iterable<String> tags;
+
+ RoomDto({
+ required this.confirmationNumber,
+ this.assignedTo,
+ required this.name,
+ required this.description,
+ required this.guests,
+ required this.imageAssets,
+ required this.roomFacilities,
+ required this.tags,
+ });
+
+ factory RoomDto.fromJson(Map<String, dynamic> json) => _$RoomDtoFromJson(json);
+
+ Map<String, dynamic> toJson() => _$RoomDtoToJson(this);
+}
diff --git a/comwell_key_app/lib/themes/dark_theme.dart b/comwell_key_app/lib/themes/dark_theme.dart
index c3990b3a..171e5f3d 100644
--- a/comwell_key_app/lib/themes/dark_theme.dart
+++ b/comwell_key_app/lib/themes/dark_theme.dart
@@ -19,7 +19,7 @@ ThemeData darkTheme = ThemeData(
headlineMedium: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600),
headlineSmall: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),
bodyMedium: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),
- bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500)),
+ bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400)),
colorScheme: ColorScheme(
primary: colorPrimary,
secondary: colorSecondary,
diff --git a/comwell_key_app/lib/themes/light_theme.dart b/comwell_key_app/lib/themes/light_theme.dart
index ff9ea50a..13e61394 100644
--- a/comwell_key_app/lib/themes/light_theme.dart
+++ b/comwell_key_app/lib/themes/light_theme.dart
@@ -20,7 +20,7 @@ ThemeData lightTheme = ThemeData(
headlineMedium: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600),
headlineSmall: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),
bodyMedium: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),
- bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500, fontFamily: 'Fellix-Light'),
+ bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400),
labelLarge: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600),
titleLarge: TextStyle(fontSize: 28.0, fontWeight: FontWeight.w600),
),
@@ -42,6 +42,7 @@ ThemeData lightTheme = ThemeData(
surfaceTint: colorHeadlineText),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
+ elevation: 0,
backgroundColor: sandColor[80],
minimumSize: const Size(double.infinity, 52),
textStyle: const TextStyle(
diff --git a/comwell_key_app/lib/up_sales/components/room_image_carousel.dart b/comwell_key_app/lib/up_sales/components/room_image_carousel.dart
index 39269d01..c7319280 100644
--- a/comwell_key_app/lib/up_sales/components/room_image_carousel.dart
+++ b/comwell_key_app/lib/up_sales/components/room_image_carousel.dart
@@ -47,6 +47,62 @@ class _RoomImageCarouselState extends State<RoomImageCarousel> {
);
},
),
+ // Left arrow button
+ if (widget.images.length > 1 && _currentPage > 0)
+ Positioned(
+ left: 16,
+ bottom: 150,
+ child: Center(
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: BorderRadius.circular(24),
+ onTap: () {
+ if (_currentPage > 0) {
+ _pageController.previousPage(duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
+ }
+ },
+ child: Container(
+ width: 32,
+ height: 32,
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ shape: BoxShape.circle,
+ ),
+ child: const Icon(Icons.arrow_back_ios_new, color: Colors.black, size: 16),
+ ),
+ ),
+ ),
+ ),
+ ),
+ // Right arrow button
+ if (widget.images.length > 1 && _currentPage < widget.images.length - 1)
+ Positioned(
+ right: 16,
+ bottom: 150,
+ child: Center(
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: BorderRadius.circular(24),
+ onTap: () {
+ if (_currentPage < widget.images.length - 1) {
+ _pageController.nextPage(duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
+ }
+ },
+ child: Container(
+ width: 32,
+ height: 32,
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ shape: BoxShape.circle,
+ ),
+ child: const Icon(Icons.arrow_forward_ios, color: Colors.black, size: 16),
+ ),
+ ),
+ ),
+ ),
+ ),
// Dot indicators
Positioned(
bottom: 16,
diff --git a/comwell_key_app/test/overview_test/overview_cubic_test.dart b/comwell_key_app/test/overview_test/overview_cubic_test.dart
index c4bda538..5131e79b 100644
--- a/comwell_key_app/test/overview_test/overview_cubic_test.dart
+++ b/comwell_key_app/test/overview_test/overview_cubic_test.dart
@@ -29,7 +29,7 @@ void main() {
when(() => mockOverviewRepository.fetchAllBookingsForUser())
.thenAnswer((_) async => Bookings(
current: [
- Booking(
+ Booking(
id: '1',
bookingStatus: BookingStatus.current,
confirmationId: "s",
@@ -48,7 +48,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890")
+ maskedCardNumber: "1234567890",
+ rooms: const [])
],
past: const [],
cancelled: const [],
@@ -80,7 +81,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890")
+ maskedCardNumber: "1234567890",
+ rooms: const [])
],
past: const [],
cancelled: const [],
@@ -134,7 +136,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890")),
+ maskedCardNumber: "1234567890",
+ rooms: const [])),
expect: () => [
OverviewLoaded(
bookings: Bookings(
@@ -158,7 +161,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890")
+ maskedCardNumber: "1234567890",
+ rooms: const [])
],
past: const [],
cancelled: const [],
diff --git a/comwell_key_app/test/overview_test/overview_repository_test.dart b/comwell_key_app/test/overview_test/overview_repository_test.dart
index 66f295f5..c1c2e7d3 100644
--- a/comwell_key_app/test/overview_test/overview_repository_test.dart
+++ b/comwell_key_app/test/overview_test/overview_repository_test.dart
@@ -38,7 +38,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890"
+ maskedCardNumber: "1234567890",
+ rooms: const []
),
],
past: const [],
@@ -77,7 +78,8 @@ void main() {
totalCharge: 100,
reservationStatus: ReservationStatus.newreservation,
balance: 100,
- maskedCardNumber: "1234567890"
+ maskedCardNumber: "1234567890",
+ rooms: const []
);
when(() => overviewRepository.findBooking(bookingReference, lastName))