6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit b216cb29
Changed files
comwell_key_app/assets/icons/ic_checkmark.svg | 5 + comwell_key_app/assets/icons/ic_plus.svg | 3 + comwell_key_app/assets/translations/da-DK.json | 14 ++- comwell_key_app/assets/translations/en-US.json | 13 ++- .../lib/common/components/comwell_text_field.dart | 63 ++++++++---- comwell_key_app/lib/comwell_app.dart | 60 +++++------ .../pregistration/bloc/preregistration_cubit.dart | 110 +++++++++++++++++++++ .../pregistration/bloc/preregistration_state.dart | 43 ++++++++ .../lib/pregistration/pages/edit_profile_page.dart | 20 ++++ .../pages/prereg_confirmation_page.dart | 110 +++++++++++++++++++++ .../pages/prereg_information_page.dart | 82 +++++++++++++++ .../pregistration/pages/prereg_payment_page.dart | 31 ++++++ .../lib/pregistration/preregistration_flow.dart | 96 ++++++++++++++++++ .../lib/pregistration/widgets/add_card.dart | 40 ++++++++ .../lib/pregistration/widgets/card_item.dart | 39 ++++++++ .../pregistration/widgets/information_card.dart | 38 +++++++ comwell_key_app/lib/routing/app_router.dart | 1 + comwell_key_app/pubspec.yaml | 1 + 18 files changed, 719 insertions(+), 50 deletions(-)
Diff
diff --git a/comwell_key_app/assets/icons/ic_checkmark.svg b/comwell_key_app/assets/icons/ic_checkmark.svg
new file mode 100644
index 00000000..5ac9bdbc
--- /dev/null
+++ b/comwell_key_app/assets/icons/ic_checkmark.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="12" fill="black"/>
+<rect width="16" height="16" transform="translate(4 4)" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6651 14.6002L7.13177 11.0669L6.39844 11.7335L9.93177 15.2669L10.6651 16.0002L17.7318 8.93353L16.9984 8.2002L10.6651 14.6002Z" fill="white"/>
+</svg>
diff --git a/comwell_key_app/assets/icons/ic_plus.svg b/comwell_key_app/assets/icons/ic_plus.svg
new file mode 100644
index 00000000..70e623c5
--- /dev/null
+++ b/comwell_key_app/assets/icons/ic_plus.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.25 12.75V20.5H12.75V12.75H20.5V11.25H12.75V3.5H11.25V11.25H3.5V12.75H11.25Z" fill="black"/>
+</svg>
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index 3fd66306..760e7f0f 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -1,4 +1,6 @@
{
+ "generic_continue": "Fortsæt",
+ "generic_information_required": "Dette felt er påkrævet",
"welcome_headline": "Velkommen hos Comwell Hotels",
"welcome_button": "Fortsæt",
"welcome_error": "Der er sket en fejl. Genstart app.",
@@ -90,5 +92,15 @@
"check_in_your_digital_card_subtitle": "Brug din mobiltelefon til at åbne værelset op. Du skal ikke længere checke ind i receptionen.",
"check_in_your_digital_card_nb": "NB: Ønsker du et fysisk nøglekort, kan du altid gå i receptionen og få det udleveret.",
"check_in_error_title": "Værelse ikke fundet...",
- "check_in_error_subtitle": "Vi fandt ikke dit værelse. Du bedes henvende dig i receptionen."
+ "check_in_error_subtitle": "Vi fandt ikke dit værelse. Du bedes henvende dig i receptionen.",
+
+ "preregistration_address_title": "Adresse",
+ "preregistration_address_subtitle": "Det er lovpligtigt at vi kender adressen på den primære beboer på værelset. Dette er pga. brandsikkerhed",
+ "preregistration_address_label_address": "Adresse",
+ "preregistration_address_label_postal_code": "Postnummer",
+ "preregistration_address_label_city": "By",
+ "preregistration_address_label_country": "Land",
+ "preregistration_payment_title": "Betalingskort",
+ "preregistration_payment_subtitle": "For at kunne overnatte på Comwell, skal vi bruge et betalingskort.",
+ "preregistration_payment_add_card": "Tilføj kort"
}
\ 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 6a5c97ed..1f90689a 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -1,4 +1,6 @@
{
+ "generic_continue": "Continue",
+ "generic_information_required": "This information is required",
"welcome_headline": "Welcome at Comwell Hotels",
"welcome_button": "Continue",
"welcome_error": "An error occurred. Please try again later.",
@@ -88,5 +90,14 @@
"check_in_your_digital_card_subtitle": "Use your phone to open your room. You do not have to check in at the reception",
"check_in_your_digital_card_nb": "NB: If you require a physical keycard, you can always get one from the reception",
"check_in_error_title": "Room not found...",
- "check_in_error_subtitle": "We could not find the room. Please check in at the reception."
+ "check_in_error_subtitle": "We could not find the room. Please check in at the reception.",
+ "preregistration_address_title": "Address",
+ "preregistration_address_subtitle": "It is required by law to know your address",
+ "preregistration_address_label_address": "Address",
+ "preregistration_address_label_postal_code": "Postal code",
+ "preregistration_address_label_city": "City",
+ "preregistration_address_label_country": "Country",
+ "preregistration_payment_title": "Payment methods",
+ "preregistration_payment_subtitle": "To stay at Comwell, you need to add a payment method",
+ "preregistration_payment_add_card": "Add card"
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/common/components/comwell_text_field.dart b/comwell_key_app/lib/common/components/comwell_text_field.dart
index 789642b4..33c00d9b 100644
--- a/comwell_key_app/lib/common/components/comwell_text_field.dart
+++ b/comwell_key_app/lib/common/components/comwell_text_field.dart
@@ -1,11 +1,16 @@
import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+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 TextInputType? textInputType;
final TextEditingController controller;
+ final String? errorMessage;
const ComwellTextField({
super.key,
@@ -13,22 +18,22 @@ class ComwellTextField extends StatefulWidget {
required this.initialValue,
required this.readOnly,
required this.controller,
+ this.errorMessage,
+ this.textInputType,
});
+
@override
ComwellTextFieldState createState() => ComwellTextFieldState();
}
class ComwellTextFieldState extends State<ComwellTextField> {
-
- late FocusNode _focusNode;
+ late final FocusNode _focusNode;
bool _isFocused = false;
@override
void initState() {
super.initState();
-
_focusNode = FocusNode();
-
_focusNode.addListener(() {
setState(() {
_isFocused = _focusNode.hasFocus;
@@ -36,37 +41,55 @@ class ComwellTextFieldState extends State<ComwellTextField> {
});
}
-
+ @override
+ void dispose() {
+ _focusNode.dispose();
+ super.dispose();
+ }
@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(
+ final errorMessage = _isFocused ? null : widget.errorMessage;
+ final labelTextColor =
+ errorMessage == null ? Colors.black : const Color(0xFFEB0026);
+ return Column(
+ children: [
+ TextField(
readOnly: widget.readOnly,
controller: widget.controller,
focusNode: _focusNode,
+ keyboardType: widget.textInputType,
decoration: InputDecoration(
+ errorText: errorMessage,
+ errorStyle: Theme.of(context)
+ .textTheme
+ .bodySmall
+ ?.copyWith(color: const Color(0xFFEB0026)),
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),
+ ?.copyWith(color: labelTextColor)),
+ errorBorder: OutlineInputBorder(
+ borderSide: const BorderSide(color: Color(0xFFEB0026)),
+ borderRadius: BorderRadius.circular(8)),
+ focusedErrorBorder: OutlineInputBorder(
+ borderSide: const BorderSide(color: colorDivider),
+ borderRadius: BorderRadius.circular(8)),
+ focusedBorder: OutlineInputBorder(
+ borderSide: const BorderSide(color: colorDivider),
+ borderRadius: BorderRadius.circular(8)),
+ enabledBorder: OutlineInputBorder(
+ borderSide: const BorderSide(color: colorDivider),
+ borderRadius: BorderRadius.circular(8)),
+ contentPadding:
+ const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
),
style: Theme.of(context).textTheme.headlineSmall,
- ),
- ),
+ )
+ ],
);
}
}
diff --git a/comwell_key_app/lib/comwell_app.dart b/comwell_key_app/lib/comwell_app.dart
index c0c78cd6..1b7ac184 100644
--- a/comwell_key_app/lib/comwell_app.dart
+++ b/comwell_key_app/lib/comwell_app.dart
@@ -19,55 +19,59 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-
class ComwellApp extends StatelessWidget {
- final AuthenticationBloc authBloc = AuthenticationBloc(authenticationRepository: AuthenticationRepository());
+ final AuthenticationBloc authBloc =
+ AuthenticationBloc(authenticationRepository: AuthenticationRepository());
+
ComwellApp({super.key});
@override
Widget build(BuildContext context) {
- return BlocProvider<AuthenticationBloc>(
-
- create: (context) => authBloc..add(AuthenticationSubscriptionRequested()),
- child: MultiBlocProvider(
- providers: blocProviderList,
- child:
- MaterialApp.router(
- title: 'Comwell Key App',
- routerConfig: goRouter(authBloc),
- localizationsDelegates: context.localizationDelegates,
- supportedLocales: context.supportedLocales,
- locale: context.locale,
- theme: lightTheme,
- darkTheme: darkTheme,
- themeMode: ThemeMode.system,
- ),),);
-}
-
-
-
+ return BlocProvider<AuthenticationBloc>(
+ create: (context) => authBloc..add(AuthenticationSubscriptionRequested()),
+ child: MultiBlocProvider(
+ providers: blocProviderList,
+ child: MaterialApp.router(
+ title: 'Comwell Key App',
+ routerConfig: goRouter(authBloc),
+ localizationsDelegates: context.localizationDelegates,
+ supportedLocales: context.supportedLocales,
+ locale: context.locale,
+ theme: lightTheme,
+ darkTheme: darkTheme,
+ themeMode: ThemeMode.system,
+ ),
+ ),
+ );
+ }
}
final List<BlocProvider> blocProviderList = [
BlocProvider<HomeBloc>(
lazy: false,
- create: (BuildContext context) => HomeBloc(homeRepository: locator<HomeRepository>()),
+ create: (BuildContext context) =>
+ HomeBloc(homeRepository: locator<HomeRepository>()),
),
BlocProvider<KeyBloc>(
lazy: true,
- create: (BuildContext context) => KeyBloc(keyRepository: locator<KeyRepository>(), homeRepository: locator<HomeRepository>()),
+ create: (BuildContext context) => KeyBloc(
+ keyRepository: locator<KeyRepository>(),
+ homeRepository: locator<HomeRepository>()),
),
BlocProvider<OverviewCubit>(
lazy: true,
- create: (BuildContext context) => OverviewCubit(locator<OverviewRepository>()),
+ create: (BuildContext context) =>
+ OverviewCubit(locator<OverviewRepository>()),
),
BlocProvider<ProfileCubit>(
lazy: false,
- create: (BuildContext context) => ProfileCubit(profileRepository: locator<ProfileRepository>()),
+ create: (BuildContext context) =>
+ ProfileCubit(profileRepository: locator<ProfileRepository>()),
),
BlocProvider<ProfileSettingsCubit>(
lazy: false,
- create: (BuildContext context) => ProfileSettingsCubit(profileSettingsRepository: locator<ProfileSettingsRepository>(), authenticationRepository: locator<AuthenticationRepository>()),
+ create: (BuildContext context) => ProfileSettingsCubit(
+ profileSettingsRepository: locator<ProfileSettingsRepository>(),
+ authenticationRepository: locator<AuthenticationRepository>()),
),
];
-
diff --git a/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
new file mode 100644
index 00000000..5887efdb
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
@@ -0,0 +1,110 @@
+import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:flutter/cupertino.dart';
+
+import '../../profile_settings/repostiory/profile_settings_repository.dart';
+import '../../utils/locator.dart';
+
+class PreregistrationCubit extends Cubit<PreregistrationState> {
+ final _profileSettingsRepository = locator<ProfileSettingsRepository>();
+ final pageController = PageController();
+ final addressTextController = TextEditingController();
+ final postalCodeTextController = TextEditingController();
+ final cityTextController = TextEditingController();
+ final countryTextController = TextEditingController();
+ bool _isAnimating = false;
+
+ PreregistrationCubit() : super(const PreregistrationState.initial());
+
+ void init() async {
+ emit(state.copyWith(loading: true, error: null));
+ try {
+ final user = await _profileSettingsRepository.fetchProfileSettings();
+ if (user != null) {
+ addressTextController.text = user.address.street;
+ postalCodeTextController.text = user.address.zipCode;
+ cityTextController.text = user.address.city;
+ countryTextController.text = user.address.country;
+ emit(state.copyWith(loading: false, user: user));
+ } else {
+ emit(state.copyWith(
+ loading: false, error: Exception("Der skete en fejl")));
+ }
+ } on Exception catch (e) {
+ emit(state.copyWith(error: e));
+ }
+ }
+
+ void onInformationContinueClicked() {
+ if (isAddressValid && isPostalCodeValid && isCityValid && isCountryValid) {
+ _navigateNextPage();
+ } else {
+ emit(state.copyWith(missingInformation: true));
+ }
+ }
+
+ void onContinueClicked() {
+ if (_isAnimating) return;
+ switch (pageController.page?.round()) {
+ case 0:
+ onInformationContinueClicked();
+ break;
+ case 1:
+ onPaymentMethodsContinueClicked();
+ break;
+ case 2:
+ // on Confirm;
+ break;
+ }
+ }
+
+ void onPaymentMethodsContinueClicked() {
+ // TODO: Check if payment method is selected and valid
+ _navigateNextPage();
+ }
+
+ void onEditProfileClicked() {}
+
+ void onBackClicked() {
+ if (_isAnimating) return;
+ final hasPage = pageController.page != null;
+ if (hasPage && pageController.page! >= 1.0) {
+ _navigatePreviousPage();
+ }
+ }
+
+ void _navigateNextPage() async {
+ _isAnimating = true;
+ await pageController.nextPage(
+ duration: const Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
+ _isAnimating = false;
+ }
+
+ void _navigatePreviousPage() async {
+ _isAnimating = true;
+ await pageController.previousPage(
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.fastOutSlowIn);
+ _isAnimating = false;
+ }
+
+ @override
+ Future<void> close() {
+ addressTextController.dispose();
+ postalCodeTextController.dispose();
+ cityTextController.dispose();
+ countryTextController.dispose();
+ pageController.dispose();
+ return super.close();
+ }
+
+ bool get isAddressValid => addressTextController.text.isNotEmpty;
+
+ bool get isPostalCodeValid =>
+ postalCodeTextController.text.isNotEmpty &&
+ postalCodeTextController.text.length <= 4;
+
+ bool get isCityValid => cityTextController.text.isNotEmpty;
+
+ bool get isCountryValid => countryTextController.text.isNotEmpty;
+}
diff --git a/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart b/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart
new file mode 100644
index 00000000..c861da8e
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart
@@ -0,0 +1,43 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:equatable/equatable.dart';
+
+import '../../profile_settings/model/user.dart';
+
+class PreregistrationState extends Equatable {
+ final bool loading;
+ final User? user;
+ final Exception? error;
+ final bool missingInformation;
+ final String buttonText;
+
+ String get buttonTextLocalized => buttonText.tr();
+
+ const PreregistrationState.initial()
+ : this(loading: true, missingInformation: false);
+
+ const PreregistrationState({
+ required this.loading,
+ required this.missingInformation,
+ this.buttonText = "generic_continue",
+ this.user,
+ this.error,
+ });
+
+ @override
+ List<Object?> get props => [loading, user, error, missingInformation, buttonText];
+
+ PreregistrationState copyWith({
+ bool? loading,
+ User? user,
+ Exception? error,
+ bool? missingInformation,
+ String? buttonText,
+ }) {
+ return PreregistrationState(
+ loading: loading ?? this.loading,
+ missingInformation: missingInformation ?? this.missingInformation,
+ user: user ?? this.user,
+ buttonText: buttonText ?? "generic_continue",
+ error: error);
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/pages/edit_profile_page.dart b/comwell_key_app/lib/pregistration/pages/edit_profile_page.dart
new file mode 100644
index 00000000..a2b13e78
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/pages/edit_profile_page.dart
@@ -0,0 +1,20 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+class EditProfilePage extends StatelessWidget {
+ const EditProfilePage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ const SizedBox(height: 40),
+ Text("preregistration_confirmation_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge),
+ const SizedBox(height: 18),
+ Text("preregistration_confirmation_subtitle".tr(),
+ style: Theme.of(context).textTheme.bodySmall),
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
new file mode 100644
index 00000000..e91ce262
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
@@ -0,0 +1,110 @@
+import 'package:comwell_key_app/pregistration/widgets/information_card.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class PreregConfirmationPage extends StatelessWidget {
+ const PreregConfirmationPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return ListView(
+ children: [
+ const SizedBox(height: 40),
+ Text("preregistration_confirmation_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge),
+ const SizedBox(height: 18),
+ Text("preregistration_confirmation_subtitle".tr(),
+ style: Theme.of(context).textTheme.bodySmall),
+ const SizedBox(height: 40),
+ InformationCard(
+ title: "Profilinformation",
+ onEditClick: () {},
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Jeppe Bjorholm Andersen",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ Text(
+ "jad@dwarf.dk",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ Text(
+ "+45 21499736",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ Text(
+ "23-08-1992",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 12),
+ InformationCard(
+ title: "Adresse",
+ onEditClick: () {},
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Bernhard Bangs Allé 25",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ Text(
+ "2000, Frederiksberg, Denmark",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 12),
+ InformationCard(
+ title: "Betalingskort",
+ onEditClick: () {},
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SvgPicture.asset("assets/icons/maestro.svg"),
+ const SizedBox(width: 12),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Name",
+ style: Theme.of(context).textTheme.bodySmall,
+ ),
+ Text(
+ "**** **** **** 1234",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 12),
+ InformationCard(
+ title: "2 valgte tilkøb",
+ onEditClick: () {},
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "600 kr.",
+ style: Theme.of(context).textTheme.bodySmall,
+ ),
+ Text(
+ "Skrives på din værelsesregning",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 40),
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_information_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_information_page.dart
new file mode 100644
index 00000000..5079941a
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/pages/prereg_information_page.dart
@@ -0,0 +1,82 @@
+import 'package:comwell_key_app/common/components/comwell_text_field.dart';
+import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PreregInformationPage extends StatelessWidget {
+ const PreregInformationPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder<PreregistrationCubit, PreregistrationState>(
+ builder: (context, state) {
+ final cubit = context.read<PreregistrationCubit>();
+ final state = cubit.state;
+ if (state.loading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ if (state.error != null) {
+ return const Center(child: Text("Error"));
+ }
+ final addressErrorMessage =
+ !cubit.isAddressValid && state.missingInformation
+ ? "generic_information_required".tr()
+ : null;
+ final postalCodeErrorMessage =
+ !cubit.isPostalCodeValid && state.missingInformation
+ ? "generic_information_required".tr()
+ : null;
+ final cityErrorMessage = !cubit.isCityValid && state.missingInformation
+ ? "generic_information_required".tr()
+ : null;
+ final countryErrorMessage =
+ !cubit.isCountryValid && state.missingInformation
+ ? "generic_information_required".tr()
+ : null;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 40),
+ Text("preregistration_address_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge),
+ Text(state.missingInformation.toString()),
+ const SizedBox(height: 18),
+ Text("preregistration_address_subtitle".tr(),
+ style: Theme.of(context).textTheme.bodySmall),
+ const SizedBox(height: 40),
+ ComwellTextField(
+ fieldName: "preregistration_address_label_address".tr(),
+ initialValue: "",
+ readOnly: false,
+ errorMessage: addressErrorMessage,
+ controller: cubit.addressTextController),
+ const SizedBox(height: 12),
+ ComwellTextField(
+ fieldName: "preregistration_address_label_postal_code".tr(),
+ initialValue: "",
+ textInputType: TextInputType.number,
+ errorMessage: postalCodeErrorMessage,
+ readOnly: false,
+ controller: cubit.postalCodeTextController),
+ const SizedBox(height: 12),
+ ComwellTextField(
+ fieldName: "preregistration_address_label_city".tr(),
+ initialValue: "",
+ readOnly: false,
+ errorMessage: cityErrorMessage,
+ controller: cubit.cityTextController),
+ const SizedBox(height: 12),
+ ComwellTextField(
+ fieldName: "preregistration_address_label_country".tr(),
+ initialValue: "",
+ errorMessage: countryErrorMessage,
+ readOnly: false,
+ controller: cubit.countryTextController),
+ ],
+ );
+ }
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_payment_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_payment_page.dart
new file mode 100644
index 00000000..8a3c07fe
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/pages/prereg_payment_page.dart
@@ -0,0 +1,31 @@
+import 'package:comwell_key_app/pregistration/widgets/add_card.dart';
+import 'package:comwell_key_app/pregistration/widgets/card_item.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+class PreregPaymentPage extends StatelessWidget {
+ const PreregPaymentPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 40),
+ Text("preregistration_payment_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge),
+ const SizedBox(height: 18),
+ Text("preregistration_payment_subtitle".tr(),
+ style: Theme.of(context).textTheme.bodySmall),
+ const SizedBox(height: 40),
+ const CardItem(),
+ const SizedBox(height: 12),
+ const CardItem(),
+ const SizedBox(height: 12),
+ const CardItem(),
+ const SizedBox(height: 12),
+ AddCard(onClick: () {})
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/preregistration_flow.dart b/comwell_key_app/lib/pregistration/preregistration_flow.dart
new file mode 100644
index 00000000..eb4fae18
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/preregistration_flow.dart
@@ -0,0 +1,96 @@
+import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/pages/prereg_confirmation_page.dart';
+import 'package:comwell_key_app/pregistration/pages/prereg_information_page.dart';
+import 'package:comwell_key_app/pregistration/pages/prereg_payment_page.dart';
+import 'package:comwell_key_app/themes/dark_theme.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PreregistrationFlow extends StatefulWidget {
+ const PreregistrationFlow({super.key});
+
+ @override
+ State<PreregistrationFlow> createState() => _PreregistrationFlowState();
+}
+
+class _PreregistrationFlowState extends State<PreregistrationFlow> {
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(
+ create: (context) => PreregistrationCubit()..init(),
+ child: BlocConsumer<PreregistrationCubit, PreregistrationState>(
+ listener: (context, state) {},
+ builder: (context, state) {
+ final cubit = context.read<PreregistrationCubit>();
+ return Scaffold(
+ backgroundColor: Colors.white,
+ appBar: AppBar(
+ backgroundColor: colorSecondary,
+ leading: BackButton(
+ onPressed: () {
+ cubit.onBackClicked();
+ },
+ ),
+ ),
+ bottomNavigationBar: Column(
+ // BOTTOM NAVIGATION
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Divider(
+ color: Colors.black12,
+ height: 0,
+ ),
+ Row(
+ children: [
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: ElevatedButton(
+ onPressed: () {
+ cubit.onInformationContinueClicked();
+ },
+ style: const ButtonStyle(
+ backgroundColor:
+ WidgetStatePropertyAll(Color(0xffAA8D65)),
+ foregroundColor:
+ WidgetStatePropertyAll(Colors.white)),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 16.0),
+ child: Text(state.buttonTextLocalized),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ body: Expanded(
+ child: Padding(
+ padding: const EdgeInsets.all(12.0),
+ child: Builder(
+ builder: (context) {
+ if (state.loading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ return PageView(
+ physics: const NeverScrollableScrollPhysics(),
+ controller: cubit.pageController,
+ children: const [
+ PreregInformationPage(),
+ PreregPaymentPage(),
+ PreregConfirmationPage(),
+ ],
+ );
+ },
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/widgets/add_card.dart b/comwell_key_app/lib/pregistration/widgets/add_card.dart
new file mode 100644
index 00000000..7613ba74
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/widgets/add_card.dart
@@ -0,0 +1,40 @@
+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/flutter_svg.dart';
+
+class AddCard extends StatelessWidget {
+ final VoidCallback onClick;
+
+ const AddCard({super.key, required this.onClick});
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: onClick,
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ ),
+ padding: const EdgeInsets.all(12),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text(
+ "preregistration_payment_add_card".tr(),
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ const SizedBox(width: 12),
+ SvgPicture.asset("assets/icons/visa.svg"),
+ const SizedBox(width: 4),
+ SvgPicture.asset("assets/icons/mastercard.svg"),
+ const SizedBox(width: 4),
+ SvgPicture.asset("assets/icons/maestro.svg"),
+ const Expanded(child: SizedBox()),
+ SvgPicture.asset("assets/icons/ic_plus.svg"),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/widgets/card_item.dart b/comwell_key_app/lib/pregistration/widgets/card_item.dart
new file mode 100644
index 00000000..0d6aea8e
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/widgets/card_item.dart
@@ -0,0 +1,39 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class CardItem extends StatelessWidget {
+ const CardItem({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ ),
+ padding: const EdgeInsets.all(12),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SvgPicture.asset("assets/icons/maestro.svg"),
+ const SizedBox(width: 12),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Name",
+ style: Theme.of(context).textTheme.bodySmall,
+ ),
+ Text(
+ "**** **** **** 1234",
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ const Expanded(child: SizedBox()),
+ SvgPicture.asset("assets/icons/ic_checkmark.svg"),
+ ],
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/widgets/information_card.dart b/comwell_key_app/lib/pregistration/widgets/information_card.dart
new file mode 100644
index 00000000..cfbccf08
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/widgets/information_card.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+
+class InformationCard extends StatelessWidget {
+ final String title;
+ final VoidCallback onEditClick;
+ final Widget child;
+
+ const InformationCard({
+ super.key,
+ required this.title,
+ required this.onEditClick,
+ required this.child,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.all(12),
+ decoration: const BoxDecoration(
+ color: Color(0xFFF9F6F2),
+ borderRadius: BorderRadius.all(Radius.circular(10))),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(title),
+ TextButton(onPressed: onEditClick, child: const Text("Rediger"))
+ ],
+ ),
+ const SizedBox(height: 40),
+ child
+ ],
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index b985f7fb..5b45fd3a 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -10,6 +10,7 @@ import 'package:comwell_key_app/login/login_page.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/overview_page.dart';
import 'package:comwell_key_app/overview/past_cancelled_booking_detail_page.dart';
+import 'package:comwell_key_app/pregistration/preregistration_flow.dart';
import 'package:comwell_key_app/profile/profile_page.dart';
import 'package:comwell_key_app/profile_settings/components/change_password_modal.dart';
import 'package:comwell_key_app/profile_settings/profile_settings_page.dart';
diff --git a/comwell_key_app/pubspec.yaml b/comwell_key_app/pubspec.yaml
index 80121c5c..a12c1745 100644
--- a/comwell_key_app/pubspec.yaml
+++ b/comwell_key_app/pubspec.yaml
@@ -53,6 +53,7 @@ dependencies:
flutter_launcher_icons: ^0.14.1
slider_button: ^2.1.0
country_code_picker: ^3.1.0
+ # adyen_checkout: ^1.1.0
dev_dependencies:
flutter_test: