6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 9e5c1c26
Changed files
.../assets/animations/load_animation.json | 1 + comwell_key_app/assets/translations/da-DK.json | 16 +- comwell_key_app/assets/translations/en-US.json | 14 +- .../lib/common/components/bottom_sheet_widget.dart | 32 +++ .../lib/common/components/comwell_app_bar.dart | 64 ++++++ .../lib/common/components/comwell_text_field.dart | 72 +++++++ .../lib/common/components/generic_dialog.dart | 95 +++++++++ .../lib/common/components/round_icon_button.dart | 28 +++ .../scaffold_messenger_state_extension.dart | 17 ++ .../lib/components/bottom_sheet_widget.dart | 32 --- .../lib/components/comwell_app_bar.dart | 62 ------ .../lib/components/round_icon_button.dart | 26 --- .../scaffold_messenger_state_extension.dart | 17 -- .../components/hotel_list_item_view.dart | 64 ++++++ .../find_booking/components/hotel_tab_view.dart | 29 +++ .../lib/find_booking/find_booking_page.dart | 232 +++++++++++++++++++++ comwell_key_app/lib/find_booking/loading_page.dart | 47 +++++ comwell_key_app/lib/find_booking/models/hotel.dart | 42 ++++ comwell_key_app/lib/home/home_page.dart | 4 +- comwell_key_app/lib/key/key_page.dart | 3 +- .../lib/overview/cubit/overview_cubit.dart | 60 +++++- .../lib/overview/cubit/overview_state.dart | 8 + comwell_key_app/lib/overview/overview_page.dart | 53 ++++- .../past_cancelled_booking_detail_page.dart | 2 +- .../overview/repository/overview_repository.dart | 29 +++ comwell_key_app/lib/profile/profile_page.dart | 3 +- .../components/comwell_text_field.dart | 50 ----- .../profile_settings/profile_settings_page.dart | 16 +- comwell_key_app/lib/redeem_debug/redeem_page.dart | 4 +- comwell_key_app/lib/routing/app_router.dart | 15 +- comwell_key_app/lib/routing/app_routes.dart | 2 +- comwell_key_app/lib/settings/settings_page.dart | 2 +- comwell_key_app/lib/themes/light_theme.dart | 2 + 33 files changed, 935 insertions(+), 208 deletions(-)
Diff
diff --git a/comwell_key_app/assets/animations/load_animation.json b/comwell_key_app/assets/animations/load_animation.json
new file mode 100644
index 00000000..4781dd98
--- /dev/null
+++ b/comwell_key_app/assets/animations/load_animation.json
@@ -0,0 +1 @@
+{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.6.0","a":"","k":"","d":"","tc":""},"fr":59.2332916259766,"ip":0,"op":308.001516397967,"w":650,"h":650,"nm":"Lottie - Load","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Error - Dot","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.972,125.264,0],"ix":2},"a":{"a":0,"k":[4.972,124.264,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":249.001,"s":[0,0,100]},{"t":258.001270229466,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[4.972,124.264],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":208.001024060965,"op":308.001516397967,"st":208.001024060965,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Error - Line","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":248.001,"s":[325,325,0],"to":[3.333,0,0],"ti":[3,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":253.001,"s":[345,325,0],"to":[-3,0,0],"ti":[-0.333,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":258.001,"s":[307,325,0],"to":[0.333,0,0],"ti":[-3,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":263.001,"s":[347,325,0],"to":[3,0,0],"ti":[3.667,0,0]},{"t":268.001319463166,"s":[325,325,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-160.675,0],[0,-165.401],[153.249,0],[0,0]],"o":[[174.852,0],[0,178.228],[0,0.675],[0,0]],"v":[[-3.376,-305.148],[305.148,-0.675],[4.726,304.473],[4.726,-151.224]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":222.001,"s":[0]},{"t":258.001270229466,"s":[85.75]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":222.001,"s":[0]},{"t":258.001270229466,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":208.001024060965,"op":308.001516397967,"st":208.001024060965,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Error - Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[325,325,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[610,610],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":209.001,"s":[0]},{"t":258.001270229466,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":209.001,"s":[0]},{"t":258.001270229466,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":209.001,"s":[0]},{"t":258.001270229466,"s":[0]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":208.001024060965,"op":308.001516397967,"st":208.001024060965,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Success - Checkmark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":157.001,"s":[325,325,0],"to":[0,-11,0],"ti":[0,11,0]},{"t":171.000841896274,"s":[325,259,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[184,0]],"o":[[0,0],[0,0],[0,0],[-205,0]],"v":[[-141,75],[-45,171],[264,-153],[0,-305]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142.001,"s":[100]},{"t":164.000807432684,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":142.001,"s":[100]},{"t":157.000772969094,"s":[46.4]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 2","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":119.000585881033,"op":209.001028984335,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Success - Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[325,325,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[610,610],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":119.001,"s":[0]},{"t":164.000807432684,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":119.001,"s":[0]},{"t":164.000807432684,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":119.001,"s":[0]},{"t":164.000807432684,"s":[0]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":119.000585881033,"op":209.001028984335,"st":119.000585881033,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Loading - Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[325,325,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[610,610],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":30,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[25]},{"t":119.000585881033,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[0.708]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.861]},"t":60,"s":[75]},{"t":119.000585881033,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":119.000585881033,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":122.000600651143,"st":0,"bm":0}],"markers":[{"tm":0,"cm":"{\n\"name\":\"spinner\"\n}","dr":118.000580957663},{"tm":119.000585881033,"cm":"{\r\"name\":\"succes\"\r}","dr":89.000438179932},{"tm":208.822028103052,"cm":"{\n\"name\":\"error\"\n}","dr":98.1794833715455}]}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index e55ad5ed..f27d68ef 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -61,6 +61,20 @@
"payment": "Betaling",
"payment_method": "Betalingsmetode",
"bill": "Kvittering",
- "get_bill": "Hent kvittering"
+ "get_bill": "Hent kvittering",
+ "your_last_name": "Dit efternavn",
+ "find_booking": "Find booking",
+ "choose_hotel": "Vælg hotel",
+ "hotels": "Hoteller",
+ "all": "Alle",
+ "zealand": "Sjælland",
+ "funen": "Fyn",
+ "jutland": "Jylland",
+ "booking_not_found": "Booking blev ikke fundet",
+ "booking_not_found_subtitle": "Den booking du leder efter, kunne ikke findes. \nHar du skrevet oplysningerne korrekt?",
+ "booking_not_found_button": "Prøv igen",
+ "booking_not_found_cancel": "Annuller"
+
+
}
\ 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 8f93b8f2..c885b1ec 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -61,5 +61,17 @@
"payment": "Payment",
"payment_method": "Payment method",
"bill": "Bill",
- "get_bill": "Get bill"
+ "get_bill": "Get bill",
+ "your_last_name": "Your last name",
+ "find_booking": "Find booking",
+ "choose_hotel": "Choose hotel",
+ "hotels": "Hotels",
+ "all": "All",
+ "zealand": "Zealand",
+ "funen": "Funen",
+ "jutland": "Jutland",
+ "booking_not_found": "Booking not found",
+ "booking_not_found_subtitle": "We could not find a booking with the information you provided.",
+ "booking_not_found_button": "Try again",
+ "booking_not_found_cancel": "Cancel"
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/common/components/bottom_sheet_widget.dart b/comwell_key_app/lib/common/components/bottom_sheet_widget.dart
new file mode 100644
index 00000000..fa73391c
--- /dev/null
+++ b/comwell_key_app/lib/common/components/bottom_sheet_widget.dart
@@ -0,0 +1,32 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:sheet/sheet.dart';
+
+class BottomSheetWidget extends StatelessWidget {
+ final List<Widget> widgetChildren;
+ const BottomSheetWidget({
+ required this.widgetChildren,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Sheet(
+ backgroundColor: sandColor[40],
+ initialExtent: 200,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(30),
+ topRight: Radius.circular(30),
+ ),
+ ),
+ resizable: true,
+ fit: SheetFit.expand,
+ minExtent: 100,
+ maxExtent: 600,
+ child: SingleChildScrollView( child: Column(
+ children: widgetChildren
+ )),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/common/components/comwell_app_bar.dart b/comwell_key_app/lib/common/components/comwell_app_bar.dart
new file mode 100644
index 00000000..490ac769
--- /dev/null
+++ b/comwell_key_app/lib/common/components/comwell_app_bar.dart
@@ -0,0 +1,64 @@
+import 'package:comwell_key_app/common/components/round_icon_button.dart';
+import 'package:comwell_key_app/routing/app_routes.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class ComwellAppBar extends StatelessWidget implements PreferredSizeWidget {
+ final bool shouldShowAppBar;
+ final bool shouldShowBackButton;
+ final bool shouldShowProfileButton;
+
+ const ComwellAppBar({
+ super.key,
+ this.shouldShowAppBar = true,
+ this.shouldShowBackButton = true,
+ this.shouldShowProfileButton = true,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: BoxDecoration(
+ color: sandColor[20],
+ borderRadius: const BorderRadius.only(
+ bottomLeft: Radius.circular(24),
+ bottomRight: Radius.circular(24),
+ ),
+ ),
+ height: 112,
+ child: Padding(
+ padding: const EdgeInsets.only(bottom: 10),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Visibility(
+ visible: shouldShowBackButton,
+ child: RoundIconButton(
+ icon: "assets/icons/arrow-right.svg",
+ color: Colors.white,
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ ),
+ Visibility(
+ visible: shouldShowProfileButton,
+ child: RoundIconButton(
+ icon: "assets/icons/user-open.svg",
+ color: Colors.white,
+ onPressed: () {
+ context.goNamed(AppRoutes.profile.name);
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ @override
+ Size get preferredSize => const Size.fromHeight(112);
+}
diff --git a/comwell_key_app/lib/common/components/comwell_text_field.dart b/comwell_key_app/lib/common/components/comwell_text_field.dart
new file mode 100644
index 00000000..9e1d6f27
--- /dev/null
+++ b/comwell_key_app/lib/common/components/comwell_text_field.dart
@@ -0,0 +1,72 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+
+class ComwellTextField extends StatefulWidget {
+ final String fieldName;
+ final String initialValue;
+ final bool readOnly;
+ final TextEditingController controller;
+
+ ComwellTextField({
+ super.key,
+ required this.fieldName,
+ required this.initialValue,
+ required this.readOnly,
+ required this.controller,
+ });
+ @override
+ _ComwellTextFieldState createState() => _ComwellTextFieldState();
+}
+
+class _ComwellTextFieldState extends State<ComwellTextField> {
+
+ late FocusNode _focusNode;
+ bool _isFocused = false;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _focusNode = FocusNode();
+
+ _focusNode.addListener(() {
+ setState(() {
+ _isFocused = _focusNode.hasFocus;
+ });
+ });
+ }
+
+
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Container(
+ height: 62,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(color: colorDivider),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10),
+ child: TextField(
+ readOnly: widget.readOnly,
+ controller: widget.controller,
+ focusNode: _focusNode,
+ decoration: InputDecoration(
+ label: Text(widget.fieldName,
+ style: _isFocused
+ ? theme.textTheme.bodySmall
+ ?.copyWith(color: Colors.black.withOpacity(0.65))
+ : theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.black)),
+ isDense: true,
+ border: InputBorder.none,
+ contentPadding: const EdgeInsets.symmetric(vertical: 0),
+ ),
+ style: Theme.of(context).textTheme.headlineSmall,
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/common/components/generic_dialog.dart b/comwell_key_app/lib/common/components/generic_dialog.dart
new file mode 100644
index 00000000..0088bf14
--- /dev/null
+++ b/comwell_key_app/lib/common/components/generic_dialog.dart
@@ -0,0 +1,95 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:easy_localization/easy_localization.dart';
+
+class GenericDialog extends StatelessWidget {
+ final String title;
+ final String content;
+ final String confirmButtonText;
+ final String cancelButtonText;
+ final VoidCallback onConfirm;
+ final VoidCallback onCancel;
+
+ const GenericDialog({
+ super.key,
+ required this.title,
+ required this.content,
+ required this.confirmButtonText,
+ required this.cancelButtonText,
+ required this.onConfirm,
+ required this.onCancel,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Dialog(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(16),
+ ),
+ child: SizedBox(
+ height: 282,
+ child: Padding(
+ padding: const EdgeInsets.only(left: 20, right: 20, top: 20),
+ child: Column(
+ children: [
+ const SizedBox(height: 10),
+ Text(
+ title,
+ textAlign: TextAlign.center,
+ style: theme.textTheme.headlineMedium
+ ),
+ const SizedBox(height: 20),
+ Text(
+ content,
+ textAlign: TextAlign.center,
+ style: theme.textTheme.bodySmall?.copyWith(color: Colors.black.withOpacity(0.65))
+ ),
+ const SizedBox(height: 20),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ side: const BorderSide(color: colorDivider),
+ minimumSize: const Size(280, 52),
+ maximumSize: const Size(280, 52),
+ ),
+ onPressed: onConfirm,
+ child: Text(
+ confirmButtonText,
+ style: const TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 5),Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: sandColor,
+ minimumSize: const Size(double.infinity, 52),
+ maximumSize: const Size(double.infinity, 52),
+ ),
+ onPressed: onCancel,
+ child: Text(
+ cancelButtonText,
+ style: const TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+
+ const SizedBox(height: 10),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/common/components/round_icon_button.dart b/comwell_key_app/lib/common/components/round_icon_button.dart
new file mode 100644
index 00000000..d6d57142
--- /dev/null
+++ b/comwell_key_app/lib/common/components/round_icon_button.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class RoundIconButton extends StatelessWidget {
+ final String icon;
+ final Function onPressed;
+ final Color color;
+ const RoundIconButton({
+ required this.icon,
+ required this.onPressed,
+ required this.color,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return ElevatedButton(
+ onPressed: () {onPressed();},
+ style: ElevatedButton.styleFrom(
+ fixedSize: const Size(36, 36),
+ elevation: 0,
+ backgroundColor: color,
+ shape: const CircleBorder(side: BorderSide(style: BorderStyle.none)),
+ ),
+ child: SvgPicture.asset(icon),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/common/extensions/scaffold_messenger_state_extension.dart b/comwell_key_app/lib/common/extensions/scaffold_messenger_state_extension.dart
new file mode 100644
index 00000000..6f8163d4
--- /dev/null
+++ b/comwell_key_app/lib/common/extensions/scaffold_messenger_state_extension.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+
+extension ScaffoldMessengerStateExtension on ScaffoldMessengerState {
+ void showActionSnackBar({
+ required Widget content,
+ required String label,
+ required void Function() onPressed}) =>
+ showSnackBar(
+ SnackBar(
+ content: content,
+ action: SnackBarAction(
+ label: label,
+ onPressed: onPressed,
+ ),
+ )
+ );
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/components/bottom_sheet_widget.dart b/comwell_key_app/lib/components/bottom_sheet_widget.dart
deleted file mode 100644
index fa73391c..00000000
--- a/comwell_key_app/lib/components/bottom_sheet_widget.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:flutter/material.dart';
-import 'package:sheet/sheet.dart';
-
-class BottomSheetWidget extends StatelessWidget {
- final List<Widget> widgetChildren;
- const BottomSheetWidget({
- required this.widgetChildren,
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- return Sheet(
- backgroundColor: sandColor[40],
- initialExtent: 200,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(30),
- topRight: Radius.circular(30),
- ),
- ),
- resizable: true,
- fit: SheetFit.expand,
- minExtent: 100,
- maxExtent: 600,
- child: SingleChildScrollView( child: Column(
- children: widgetChildren
- )),
- );
- }
-}
diff --git a/comwell_key_app/lib/components/comwell_app_bar.dart b/comwell_key_app/lib/components/comwell_app_bar.dart
deleted file mode 100644
index ce29531d..00000000
--- a/comwell_key_app/lib/components/comwell_app_bar.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-import 'package:comwell_key_app/components/round_icon_button.dart';
-import 'package:comwell_key_app/routing/app_routes.dart';
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:flutter/material.dart';
-import 'package:go_router/go_router.dart';
-
-class ComwellAppBar extends StatelessWidget implements PreferredSizeWidget {
- final bool shouldShowAppBar;
- final bool shouldShowBackButton;
- final bool shouldShowProfileButton;
-
- const ComwellAppBar({
- super.key,
- this.shouldShowAppBar = true,
- this.shouldShowBackButton = true,
- this.shouldShowProfileButton = true,
- });
-
- @override
- Widget build(BuildContext context) {
- return Container(
- decoration: BoxDecoration(
- color: sandColor[20],
- borderRadius: const BorderRadius.only(
- bottomLeft: Radius.circular(24),
- bottomRight: Radius.circular(24),
- ),
- ),
- height: 112,
- child: Padding(
- padding: const EdgeInsets.only(bottom: 10),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- Visibility(
- visible: shouldShowBackButton,
- child: RoundIconButton(
- icon: "assets/icons/arrow-right.svg",
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- ),
- Visibility(
- visible: shouldShowProfileButton,
- child: RoundIconButton(
- icon: "assets/icons/user-open.svg",
- onPressed: () {
- context.goNamed(AppRoutes.profile.name);
- },
- ),
- ),
- ],
- ),
- ),
- );
- }
-
- @override
- Size get preferredSize => const Size.fromHeight(112);
-}
diff --git a/comwell_key_app/lib/components/round_icon_button.dart b/comwell_key_app/lib/components/round_icon_button.dart
deleted file mode 100644
index 3044bbe5..00000000
--- a/comwell_key_app/lib/components/round_icon_button.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_svg/svg.dart';
-
-class RoundIconButton extends StatelessWidget {
- final String icon;
- final Function onPressed;
- const RoundIconButton({
- required this.icon,
- required this.onPressed,
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- return ElevatedButton(
- onPressed: () {onPressed();},
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(36, 36),
- elevation: 0,
- backgroundColor: Colors.white,
- shape: const CircleBorder(side: BorderSide(style: BorderStyle.none)),
- ),
- child: SvgPicture.asset(icon),
- );
- }
-}
diff --git a/comwell_key_app/lib/extensions/scaffold_messenger_state_extension.dart b/comwell_key_app/lib/extensions/scaffold_messenger_state_extension.dart
deleted file mode 100644
index 6f8163d4..00000000
--- a/comwell_key_app/lib/extensions/scaffold_messenger_state_extension.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'package:flutter/material.dart';
-
-extension ScaffoldMessengerStateExtension on ScaffoldMessengerState {
- void showActionSnackBar({
- required Widget content,
- required String label,
- required void Function() onPressed}) =>
- showSnackBar(
- SnackBar(
- content: content,
- action: SnackBarAction(
- label: label,
- onPressed: onPressed,
- ),
- )
- );
-}
\ No newline at end of file
diff --git a/comwell_key_app/lib/find_booking/components/hotel_list_item_view.dart b/comwell_key_app/lib/find_booking/components/hotel_list_item_view.dart
new file mode 100644
index 00000000..5482e9cf
--- /dev/null
+++ b/comwell_key_app/lib/find_booking/components/hotel_list_item_view.dart
@@ -0,0 +1,64 @@
+import 'package:comwell_key_app/find_booking/models/hotel.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:go_router/go_router.dart';
+
+class HotelListItemView extends StatelessWidget {
+ final Hotel hotel;
+
+
+ const HotelListItemView({
+ super.key,
+ required this.hotel,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return InkWell(
+ onTap: () => {},
+ child: Container(
+ height: 66,
+ margin: const EdgeInsets.only(bottom: 8, left: 8, right: 8),
+ decoration: BoxDecoration(
+ border: Border.all(
+ width: 1,
+ color: Colors.grey.shade300,
+ ),
+ borderRadius: BorderRadius.circular(6),
+ ),
+ child: Row(
+ children: [
+ Container(
+ margin: const EdgeInsets.all(0),
+ decoration: const BoxDecoration(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(6),
+ bottomLeft: Radius.circular(6)),
+ ),
+ width: 84,
+ height: 66,
+ child: Image.asset(hotel.image),
+ ),
+ const SizedBox(width: 8),
+ Padding(
+ padding: const EdgeInsets.all(8),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ hotel.name,
+ style: theme.textTheme.headlineSmall,
+ ),
+
+ ]),
+ ),
+
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/find_booking/components/hotel_tab_view.dart b/comwell_key_app/lib/find_booking/components/hotel_tab_view.dart
new file mode 100644
index 00000000..e83b6f32
--- /dev/null
+++ b/comwell_key_app/lib/find_booking/components/hotel_tab_view.dart
@@ -0,0 +1,29 @@
+import 'package:comwell_key_app/find_booking/components/hotel_list_item_view.dart';
+import 'package:comwell_key_app/find_booking/models/hotel.dart';
+import 'package:comwell_key_app/overview/components/current_booking_list_item_view.dart';
+import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class HotelTabView extends StatelessWidget {
+ List<Hotel> hotels;
+
+ HotelTabView(
+ {required this.hotels,
+
+ super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return ListView.builder(
+ shrinkWrap: true,
+ itemCount: hotels.length,
+ itemBuilder: (context, index) => HotelListItemView(
+ hotel: hotels[index],
+ ),
+ );
+ }
+
+}
diff --git a/comwell_key_app/lib/find_booking/find_booking_page.dart b/comwell_key_app/lib/find_booking/find_booking_page.dart
new file mode 100644
index 00000000..b7d977d5
--- /dev/null
+++ b/comwell_key_app/lib/find_booking/find_booking_page.dart
@@ -0,0 +1,232 @@
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/comwell_text_field.dart';
+import 'package:comwell_key_app/common/components/round_icon_button.dart';
+import 'package:comwell_key_app/find_booking/components/hotel_tab_view.dart';
+import 'package:comwell_key_app/find_booking/loading_page.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:go_router/go_router.dart';
+import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
+
+class FindBookingPage extends StatefulWidget {
+ const FindBookingPage({super.key});
+
+ @override
+ FindBookingPageState createState() => FindBookingPageState();
+}
+
+class FindBookingPageState extends State<FindBookingPage>
+ with SingleTickerProviderStateMixin {
+ late TabController _tabController;
+ final TextEditingController _bookingReferenceController =
+ TextEditingController();
+ final TextEditingController _lastNameController = TextEditingController();
+
+ bool get _isButtonEnabled {
+ return _bookingReferenceController.text.isNotEmpty &&
+ _lastNameController.text.isNotEmpty;
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _tabController = TabController(length: 4, vsync: this);
+ _bookingReferenceController.addListener(_updateButtonState);
+ _lastNameController.addListener(_updateButtonState);
+ }
+
+ @override
+ void dispose() {
+ _bookingReferenceController.dispose();
+ _lastNameController.dispose();
+ _tabController.dispose();
+ super.dispose();
+ }
+
+ void _updateButtonState() {
+ setState(() {});
+ }
+
+ Future<void> _findBooking(BuildContext context) async {
+ final OverviewCubit overviewCubit = BlocProvider.of<OverviewCubit>(context);
+ final Booking? booking = await overviewCubit.findBooking(
+ _bookingReferenceController.text, _lastNameController.text);
+ // Navigate to the loading page
+ context.pushNamed(AppRoutes.loadingPage.name);
+
+ await Future.delayed(const Duration(seconds: 3));
+
+ if (mounted) {
+ context.pop();
+ context.pop();
+ }
+ }
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return Scaffold(
+ appBar: const ComwellAppBar(),
+ backgroundColor: Colors.white,
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ 'Find Booking',
+ style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600),
+ ),
+ const SizedBox(height: 20),
+ /* GestureDetector(
+ onTap: () {
+ showCupertinoModalBottomSheet(
+ backgroundColor: Colors.white,
+ barrierColor: Colors.black.withOpacity(0.5),
+ topRadius: const Radius.circular(30),
+ context: context,
+ builder: (context) => Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 40, left: 16),
+ child: Container(
+ height: 47,
+ color: Colors.white,
+ child: Stack(
+ children: [
+ Align(
+ alignment: Alignment.topRight,
+ child: RoundIconButton(
+ icon: 'assets/icons/close-icon.svg',
+ color: sandColor[20]!,
+ onPressed: () {
+ context.pop();
+ }),
+ ),
+ Align(
+ alignment: Alignment.bottomLeft,
+ child: Text('hotels'.tr(),
+ style: theme.textTheme.titleLarge),
+ )
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(height: 20),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: TabBar(
+ controller: _tabController,
+ indicatorPadding:
+ const EdgeInsets.symmetric(vertical: 8),
+ indicatorSize: TabBarIndicatorSize.tab,
+ indicator: BoxDecoration(
+ borderRadius: BorderRadius.circular(25),
+ color: sandColor,
+ ),
+ labelColor: Colors.white,
+ labelStyle: Theme.of(context).textTheme.labelLarge,
+ unselectedLabelColor: Colors.black,
+ dividerColor: Colors.transparent,
+ tabAlignment: TabAlignment.start,
+ isScrollable: true,
+ tabs: [
+ Tab(
+ text: 'all'.tr(),
+ ),
+ Tab(text: 'zealand'.tr()),
+ Tab(text: 'funen'.tr()),
+ Tab(
+ text: "jutland".tr(),
+ )
+ ],
+ ),
+ ),
+ const Divider(color: colorDivider),
+ Expanded(child: HotelTabView(hotels: hotels)),
+ const Divider(color: colorDivider),
+ const SizedBox(height: 0),
+ Center(
+ child: ElevatedButton(
+ onPressed: () {
+ // Handle find booking action
+ },
+ child: const Text('Find Booking'),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ },
+ child: Container(
+ padding:
+ const EdgeInsets.symmetric(vertical: 15, horizontal: 10),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(5),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text('choose_hotel'.tr()),
+ const Icon(Icons.arrow_drop_down),
+ ],
+ ),
+ ),
+ ), */
+ const SizedBox(height: 20),
+ ComwellTextField(
+ fieldName: 'booking_reference'.tr(),
+ initialValue: '',
+ readOnly: false,
+ controller: _bookingReferenceController,
+ ),
+ const SizedBox(height: 20),
+ ComwellTextField(
+ fieldName: 'your_last_name'.tr(),
+ initialValue: '',
+ readOnly: false,
+ controller: _lastNameController,
+ ),
+ const Spacer(),
+ const Divider(color: colorDivider),
+ const SizedBox(height: 0),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: sandColor,
+ disabledBackgroundColor: disabledButtonColor,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(25),
+ ),
+ minimumSize: const Size(double.infinity, 52),
+ ),
+ onPressed: _isButtonEnabled
+ ? () async {
+ await _findBooking(context);
+ }
+ : null,
+ child: Text(
+ 'Find Booking',
+ style: theme.textTheme.headlineSmall?.copyWith(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 20),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/find_booking/loading_page.dart b/comwell_key_app/lib/find_booking/loading_page.dart
new file mode 100644
index 00000000..593fe5ce
--- /dev/null
+++ b/comwell_key_app/lib/find_booking/loading_page.dart
@@ -0,0 +1,47 @@
+import 'package:comwell_key_app/home/home_page.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+import 'package:lottie/lottie.dart';
+
+class LoadingPage extends StatefulWidget {
+ const LoadingPage({super.key});
+
+ @override
+ _LoadingPageState createState() => _LoadingPageState();
+}
+
+class _LoadingPageState extends State<LoadingPage> {
+ @override
+ void initState() {
+ super.initState();
+ _startLoading();
+ }
+
+ Future<void> _startLoading() async {
+ await Future.delayed(const Duration(seconds: 3)); // Minimum 3 seconds delay
+ if (mounted) {
+ context.pop(); // Pop the loading page
+ // Pop the previous page
+ // Show result or error popup here
+ // For example:
+ // showDialog(context: context, builder: (context) => _buildResultDialog());
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: sandColor,
+ body: Center(
+ child: Lottie.asset(
+ 'assets/animations/load_animation.json', // Replace with your Lottie animation file
+ width: 64,
+ height: 64,
+ fit: BoxFit.cover,
+ animate: true,
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/find_booking/models/hotel.dart b/comwell_key_app/lib/find_booking/models/hotel.dart
new file mode 100644
index 00000000..e080b2ef
--- /dev/null
+++ b/comwell_key_app/lib/find_booking/models/hotel.dart
@@ -0,0 +1,42 @@
+class Hotel {
+ final String id;
+ final String name;
+ final String address;
+ final String city;
+ final String country;
+ final int starRating;
+ final String image;
+
+ Hotel({
+ required this.id,
+ required this.name,
+ required this.address,
+ required this.city,
+ required this.country,
+ required this.starRating,
+ required this.image
+ });
+
+ factory Hotel.fromJson(dynamic json) {
+ return Hotel(
+ id: json['id'] as String,
+ name: json['name'] as String,
+ address: json['address'] as String,
+ city: json['city'] as String,
+ country: json['country'] as String,
+ starRating: json['starRating'] as int,
+ image: json['hotelImage'] as String
+ );
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ 'id': id,
+ 'name': name,
+ 'address': address,
+ 'city': city,
+ 'country': country,
+ 'starRating': starRating,
+ };
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/home/home_page.dart b/comwell_key_app/lib/home/home_page.dart
index 50e60aa2..2719116a 100644
--- a/comwell_key_app/lib/home/home_page.dart
+++ b/comwell_key_app/lib/home/home_page.dart
@@ -1,5 +1,5 @@
-import 'package:comwell_key_app/components/bottom_sheet_widget.dart';
-import 'package:comwell_key_app/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/bottom_sheet_widget.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/home/bloc/home_bloc.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
diff --git a/comwell_key_app/lib/key/key_page.dart b/comwell_key_app/lib/key/key_page.dart
index 73477b3a..652c07d4 100644
--- a/comwell_key_app/lib/key/key_page.dart
+++ b/comwell_key_app/lib/key/key_page.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/components/round_icon_button.dart';
+import 'package:comwell_key_app/common/components/round_icon_button.dart';
import 'package:comwell_key_app/key/bloc/key_bloc.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -38,6 +38,7 @@ class KeyPage extends StatelessWidget {
Align(
alignment: AlignmentDirectional.centerEnd,
child: RoundIconButton(
+ color: Colors.white,
onPressed: () {
context.pop();
},
diff --git a/comwell_key_app/lib/overview/cubit/overview_cubit.dart b/comwell_key_app/lib/overview/cubit/overview_cubit.dart
index 0ae60145..033c6da5 100644
--- a/comwell_key_app/lib/overview/cubit/overview_cubit.dart
+++ b/comwell_key_app/lib/overview/cubit/overview_cubit.dart
@@ -1,4 +1,5 @@
import 'package:bloc/bloc.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/repository/overview_repository.dart';
import 'package:equatable/equatable.dart';
@@ -20,9 +21,66 @@ class OverviewCubit extends Cubit<OverviewState> {
}
}
-
@override
Future<void> close() {
return super.close();
}
+
+ Future<void> addBooking(Booking newBooking) async {
+ if (state is OverviewLoaded) {
+ final currentState = state as OverviewLoaded;
+ final updatedCurrent = List<Booking>.from(currentState.bookings.current);
+ final updatedPast = List<Booking>.from(currentState.bookings.past);
+ final updatedCancelled =
+ List<Booking>.from(currentState.bookings.cancelled);
+
+ switch (newBooking.status) {
+ case BookingStatus.current:
+ updatedCurrent.add(newBooking);
+ break;
+ case BookingStatus.past:
+ updatedPast.add(newBooking);
+ break;
+ case BookingStatus.cancelled:
+ updatedCancelled.add(newBooking);
+ break;
+ }
+
+ final updatedBookings = Bookings(
+ current: updatedCurrent,
+ past: updatedPast,
+ cancelled: updatedCancelled,
+ );
+
+ emit(OverviewLoaded(bookings: updatedBookings));
+ } else {
+ final bookings = Bookings(
+ current: [newBooking],
+ past: [],
+ cancelled: [],
+ );
+ emit(OverviewLoaded(bookings: bookings));
+ }
+ }
+
+ Future<Booking?> findBooking(String bookingReference, String lastName) async {
+ try {
+ Booking? booking =
+ await overviewRepository.findBooking(bookingReference, lastName);
+
+ if (booking != null) {
+ addBooking(booking); // Add the found booking to the current list
+ return booking;
+ } else if (state is OverviewLoaded) {
+ final currentState = state as OverviewLoaded;
+ emit(OverviewNoBookingFound(bookings: currentState.bookings));
+ } else {
+ emit(OverviewNoBookingFound(
+ bookings: Bookings(current: [], past: [], cancelled: [])));
+ }
+ } catch (e) {
+ emit(OverviewError(error: e.toString()));
+ }
+ return null;
+ }
}
diff --git a/comwell_key_app/lib/overview/cubit/overview_state.dart b/comwell_key_app/lib/overview/cubit/overview_state.dart
index 32aa4d67..d965dd38 100644
--- a/comwell_key_app/lib/overview/cubit/overview_state.dart
+++ b/comwell_key_app/lib/overview/cubit/overview_state.dart
@@ -23,6 +23,14 @@ final class OverviewLoaded extends OverviewState {
final Bookings bookings;
const OverviewLoaded({required this.bookings});
+ @override
+ List<Object> get props => [bookings];
+}
+
+final class OverviewNoBookingFound extends OverviewState {
+ final Bookings bookings;
+ const OverviewNoBookingFound({required this.bookings});
+
@override
List<Object> get props => [bookings];
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/overview/overview_page.dart b/comwell_key_app/lib/overview/overview_page.dart
index ca78314a..44bcd131 100644
--- a/comwell_key_app/lib/overview/overview_page.dart
+++ b/comwell_key_app/lib/overview/overview_page.dart
@@ -1,11 +1,14 @@
-import 'package:comwell_key_app/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/generic_dialog.dart';
import 'package:comwell_key_app/overview/components/bookings_tab_view.dart';
import 'package:comwell_key_app/overview/components/current_bookings_tab_view.dart';
import 'package:comwell_key_app/overview/cubit/overview_cubit.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:go_router/go_router.dart';
class OverviewPage extends StatefulWidget {
const OverviewPage({super.key});
@@ -35,7 +38,13 @@ class OverviewTabViewState extends State<OverviewPage>
final OverviewCubit overviewCubit = BlocProvider.of<OverviewCubit>(context);
overviewCubit.fetchBookings();
- return BlocBuilder<OverviewCubit, OverviewState>(
+ return BlocListener<OverviewCubit, OverviewState>(listener:
+ (context, state) {
+ if (state is OverviewNoBookingFound) {
+ showNotFoundDialog(context);
+ }
+ }, child:
+ BlocBuilder<OverviewCubit, OverviewState>(
builder: (context, state) {
return Scaffold(
backgroundColor: Colors.white,
@@ -105,12 +114,50 @@ class OverviewTabViewState extends State<OverviewPage>
],
),
)
- : const Center(child: CircularProgressIndicator()),
+ : ,
+ OutlinedButton.icon(
+ onPressed: () async {
+ context.pushNamed(AppRoutes.findBooking.name);
+ },
+ icon:
+ Icon(Icons.search, color: Theme.of(context).dividerColor),
+ label: Text(
+ 'find_booking'.tr(),
+ style: TextStyle(color: Theme.of(context).dividerColor),
+ ),
+ style: OutlinedButton.styleFrom(
+ side: BorderSide(color: Theme.of(context).dividerColor),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(25),
+ ),
+ ),
+ ),
],
),
),
);
},
+ ),);
+ }
+
+ Future<void> showNotFoundDialog(BuildContext context) {
+ return showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return GenericDialog(
+ title: "booking_not_found".tr(),
+ content: "booking_not_found_subtitle".tr(),
+ confirmButtonText: "booking_not_found_button".tr(),
+ cancelButtonText: "booking_not_found_cancel".tr(),
+ onConfirm: () {
+ context.pushNamed(AppRoutes.findBooking.name);
+ Navigator.of(context).pop(); // Close the dialog
+ },
+ onCancel: () {
+ Navigator.of(context).pop(); // Close the dialog
+ },
+ );
+ },
);
}
}
diff --git a/comwell_key_app/lib/overview/past_cancelled_booking_detail_page.dart b/comwell_key_app/lib/overview/past_cancelled_booking_detail_page.dart
index b70fc437..49774fbf 100644
--- a/comwell_key_app/lib/overview/past_cancelled_booking_detail_page.dart
+++ b/comwell_key_app/lib/overview/past_cancelled_booking_detail_page.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/models/payment_details.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
diff --git a/comwell_key_app/lib/overview/repository/overview_repository.dart b/comwell_key_app/lib/overview/repository/overview_repository.dart
index 1504374e..428a8143 100644
--- a/comwell_key_app/lib/overview/repository/overview_repository.dart
+++ b/comwell_key_app/lib/overview/repository/overview_repository.dart
@@ -1,3 +1,4 @@
+import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/models/bookings.dart';
import 'package:comwell_key_app/services/api.dart';
@@ -14,8 +15,36 @@ class OverviewRepository {
// throw Exception('Failed to fetch bookings');
// }
}
+
+ Future<Booking?> findBooking(String bookingReference, String lastName) async {
+ return null;await Booking.fromJson(json);
+ }
}
+final json = {
+ "id": "1",
+ "userId": "123",
+ "roomNumber": "101",
+ "startDate": "2024-10-22T14:00:00",
+ "endDate": "2024-10-25T12:00:00",
+ "status": "current",
+ "image": "assets/images/current_room.png",
+ "hotelName": "Seaside Resort",
+ "hotelCode": "SR001",
+ "roomType": "Deluxe",
+ "adults": 2,
+ "children": 1,
+ "booker": "John Doe",
+ "bookingDate": "2024-10-15T14:00:00",
+ "paymentDetails": {
+ "cardHolder": "John Doe",
+ "cardNumber": "**** **** **** 1234",
+ "expiryDate": "12/24",
+ "cvc": "123",
+ "cardType": "visa",
+ "cardName": " Doe Visa"
+ }
+};
final response = {
"current": [
{
diff --git a/comwell_key_app/lib/profile/profile_page.dart b/comwell_key_app/lib/profile/profile_page.dart
index 16ec88b3..80688180 100644
--- a/comwell_key_app/lib/profile/profile_page.dart
+++ b/comwell_key_app/lib/profile/profile_page.dart
@@ -1,5 +1,5 @@
import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
-import 'package:comwell_key_app/components/round_icon_button.dart';
+import 'package:comwell_key_app/common/components/round_icon_button.dart';
import 'package:comwell_key_app/profile/components/profile_settings_item.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
@@ -26,6 +26,7 @@ class ProfilePage extends StatelessWidget {
alignment: Alignment.centerRight,
child: RoundIconButton(
icon: "assets/icons/close-icon.svg",
+ color: Colors.white,
onPressed: () {
context.pop();
}),
diff --git a/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart b/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
deleted file mode 100644
index ae68a8df..00000000
--- a/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:flutter/material.dart';
-
-class ComwellTextField extends StatelessWidget {
- final String fieldName;
- final String initialValue;
-
- const ComwellTextField({super.key,
- required this.fieldName,
- required this.initialValue});
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- final TextEditingController controller = TextEditingController(text: initialValue);
- return Container(
- height: 62,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- border: Border.all(color: colorDivider),
- ),
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10),
- child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
- Text(
- fieldName,
- textAlign: TextAlign.start,
- style: theme.textTheme.bodySmall?.copyWith(
- color: Colors.black.withOpacity(
- 0.65,
- ),
- ),
- ),
- TextField(
- readOnly: true,
- controller: controller,
- decoration: const InputDecoration(
- isDense: true,
-
- border: InputBorder.none,
- contentPadding: EdgeInsets.symmetric(vertical: 0),
- ),
- style: Theme.of(context).textTheme.headlineSmall,
-
- ),
- ]),
- ),
- );
- }
-}
diff --git a/comwell_key_app/lib/profile_settings/profile_settings_page.dart b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
index 473043d7..152d2156 100644
--- a/comwell_key_app/lib/profile_settings/profile_settings_page.dart
+++ b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
@@ -1,6 +1,6 @@
-import 'package:comwell_key_app/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/profile_settings/components/Text_field_trailing_icon.dart';
-import 'package:comwell_key_app/profile_settings/components/comwell_text_field.dart';
+import 'package:comwell_key_app/common/components/comwell_text_field.dart';
import 'package:comwell_key_app/profile_settings/components/date_time_picker.dart';
import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
@@ -67,15 +67,21 @@ class ProfileSettingsPage extends StatelessWidget {
const SizedBox(height: 36),
ComwellTextField(
fieldName: "profil_settings_firstname".tr(),
- initialValue: loadedState.user.firstName),
+ initialValue: loadedState.user.firstName,
+ readOnly: true,
+ controller: TextEditingController()),
const SizedBox(height: 8),
ComwellTextField(
fieldName: "profil_settings_lastname".tr(),
- initialValue: loadedState.user.lastName),
+ initialValue: loadedState.user.lastName,
+ readOnly: true,
+ controller: TextEditingController()),
const SizedBox(height: 8),
ComwellTextField(
fieldName: "profil_settings_email".tr(),
- initialValue: loadedState.user.email),
+ initialValue: loadedState.user.email,
+ readOnly: true,
+ controller: TextEditingController()),
const SizedBox(height: 8),
IntlPhoneField(
title: "profil_settings_phone".tr(),
diff --git a/comwell_key_app/lib/redeem_debug/redeem_page.dart b/comwell_key_app/lib/redeem_debug/redeem_page.dart
index 400b6d01..385f0527 100644
--- a/comwell_key_app/lib/redeem_debug/redeem_page.dart
+++ b/comwell_key_app/lib/redeem_debug/redeem_page.dart
@@ -1,10 +1,10 @@
-import 'package:comwell_key_app/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/utils/secure_storage.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'invitation_code_textfield.dart';
-import '../extensions/scaffold_messenger_state_extension.dart';
+import '../common/extensions/scaffold_messenger_state_extension.dart';
import '../utils/singleton.dart';
class RedeemPage extends StatefulWidget {
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index 230285e2..2e535a72 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -1,5 +1,7 @@
import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
+import 'package:comwell_key_app/find_booking/find_booking_page.dart';
+import 'package:comwell_key_app/find_booking/loading_page.dart';
import 'package:comwell_key_app/home/home_page.dart';
import 'package:comwell_key_app/key/key_page.dart';
import 'package:comwell_key_app/login/login_page.dart';
@@ -19,7 +21,7 @@ final _rootNavigatorKey = GlobalKey<NavigatorState>();
GoRouter goRouter(AuthenticationBloc authBloc) {
return GoRouter(
- initialLocation: '/login',
+ initialLocation: '/oauthredirect',
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
refreshListenable:
@@ -49,6 +51,17 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
return null;
},
routes: <RouteBase>[
+ GoRoute(
+ path: '/loading_page',
+ name: AppRoutes.loadingPage.name,
+ builder: (context, state) {
+ return const LoadingPage();
+ }),
+ GoRoute(
+ path: "/find_booking",
+ name: AppRoutes.findBooking.name,
+ builder: (context, state) => const FindBookingPage(),
+ ),
GoRoute(
path: "/oauthredirect",
name: AppRoutes.overview.name,
diff --git a/comwell_key_app/lib/routing/app_routes.dart b/comwell_key_app/lib/routing/app_routes.dart
index 53c8738e..27653110 100644
--- a/comwell_key_app/lib/routing/app_routes.dart
+++ b/comwell_key_app/lib/routing/app_routes.dart
@@ -11,5 +11,5 @@ enum AppRoutes {
profile,
overview,
profileSettings,
- bookingDetails,
+ bookingDetails, findBooking, loadingPage,
}
diff --git a/comwell_key_app/lib/settings/settings_page.dart b/comwell_key_app/lib/settings/settings_page.dart
index 365680b6..a42dff5f 100644
--- a/comwell_key_app/lib/settings/settings_page.dart
+++ b/comwell_key_app/lib/settings/settings_page.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import '../utils/singleton.dart';
-import '../extensions/scaffold_messenger_state_extension.dart';
+import '../common/extensions/scaffold_messenger_state_extension.dart';
class SettingsPage extends StatefulWidget {
const SettingsPage({super.key});
diff --git a/comwell_key_app/lib/themes/light_theme.dart b/comwell_key_app/lib/themes/light_theme.dart
index 556ddee2..dec9e2b3 100644
--- a/comwell_key_app/lib/themes/light_theme.dart
+++ b/comwell_key_app/lib/themes/light_theme.dart
@@ -21,6 +21,7 @@ ThemeData lightTheme = ThemeData(
bodyMedium: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),
bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
labelLarge: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600),
+ titleLarge: TextStyle(fontSize: 28.0, fontWeight: FontWeight.w600),
),
@@ -54,6 +55,7 @@ const colorTertiaryText = Color(0xFF000000);
const colorTertiarySystem = Color(0xFF000000);
const colorShadow = Color(0xFF000000);
const colorDivider = Color(0xFFE0E0E0);
+const disabledButtonColor = Color(0xFFF0F0F0);
const int _earthColor = 0xFF677169;
const earthColor = MaterialColor(_earthColor, <int,Color>