6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 527087db

AuthorNKL<nikolaj.king@gmail.com>
Date2024-11-13 15:42:47 +0100
profile settings page with cubit and repo

Changed files

comwell_key_app/assets/icons/calendar.svg          |   3 +
 comwell_key_app/assets/icons/edit-alt.svg          |   4 +
 comwell_key_app/assets/icons/trash-can.svg         |   3 +
 comwell_key_app/assets/translations/da-DK.json     |  18 ++-
 comwell_key_app/assets/translations/en-US.json     |  12 +-
 .../ios/Pods/Pods.xcodeproj/project.pbxproj        |  12 +-
 comwell_key_app/lib/comwell_app.dart               |   6 +
 comwell_key_app/lib/profile/profile_page.dart      |   4 +-
 .../components/Text_field_trailing_icon.dart       |  63 +++++++++
 .../components/comwell_text_field.dart             |  48 +++++--
 .../components/date_time_picker.dart               |  77 +++++++++++
 .../components/intl_phone_field.dart               | 105 +++++++++++++++
 .../cubit/profile_settings_cubit.dart              |  22 ++++
 .../cubit/profile_settings_state.dart              |  25 ++++
 .../lib/profile_settings/model/address.dart        |  31 +++++
 .../lib/profile_settings/model/user.dart           |  48 +++++++
 .../profile_settings/profile_settings_page.dart    | 146 +++++++++++++++++----
 .../profile_settings_repository.dart               |  17 +++
 comwell_key_app/lib/routing/app_router.dart        |  15 ++-
 comwell_key_app/lib/services/api.dart              |  29 +++-
 comwell_key_app/lib/themes/light_theme.dart        |   4 +-
 comwell_key_app/pubspec.yaml                       |   1 +
 22 files changed, 631 insertions(+), 62 deletions(-)

Diff

diff --git a/comwell_key_app/assets/icons/calendar.svg b/comwell_key_app/assets/icons/calendar.svg
new file mode 100644
index 00000000..3ab8c13e
--- /dev/null
+++ b/comwell_key_app/assets/icons/calendar.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 d="M19.5 3H16.5V1.5H15V3H9V1.5H7.5V3H4.5C3.675 3 3 3.675 3 4.5V19.5C3 20.325 3.675 21 4.5 21H19.5C20.325 21 21 20.325 21 19.5V4.5C21 3.675 20.325 3 19.5 3ZM19.5 19.5H4.5V9H19.5V19.5ZM19.5 7.5H4.5V4.5H7.5V6H9V4.5H15V6H16.5V4.5H19.5V7.5Z" fill="black"/>
+</svg>
diff --git a/comwell_key_app/assets/icons/edit-alt.svg b/comwell_key_app/assets/icons/edit-alt.svg
new file mode 100644
index 00000000..41d94c66
--- /dev/null
+++ b/comwell_key_app/assets/icons/edit-alt.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.5 19.5H1.5V21H22.5V19.5Z" fill="black"/>
+<path d="M19.05 6.75C19.65 6.15 19.65 5.25 19.05 4.65L16.35 1.95C15.75 1.35 14.85 1.35 14.25 1.95L3 13.2V18H7.8L19.05 6.75ZM15.3 3L18 5.7L15.75 7.95L13.05 5.25L15.3 3ZM4.5 16.5V13.8L12 6.3L14.7 9L7.2 16.5H4.5Z" fill="black"/>
+</svg>
diff --git a/comwell_key_app/assets/icons/trash-can.svg b/comwell_key_app/assets/icons/trash-can.svg
new file mode 100644
index 00000000..31fcaf96
--- /dev/null
+++ b/comwell_key_app/assets/icons/trash-can.svg
@@ -0,0 +1,3 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 1H6.5V2H10.5V1ZM2.5 3V4H3.5V14C3.5 14.5523 3.94772 15 4.5 15H12.5C13.0523 15 13.5 14.5523 13.5 14V4H14.5V3H2.5ZM4.5 14V4H12.5V14H4.5ZM6.5 6H7.5V12H6.5V6ZM10.5 6H9.5V12H10.5V6Z" fill="#EB0026"/>
+</svg>
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index cccf8953..a4b625c3 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -33,15 +33,21 @@
"children": "børn",
"adult": "voksen",
"child": "barn",
- "prepare_room":"Klargør dit værelse",
+ "prepare_room": "Klargør dit værelse",
"jump_line_text": "Spring køen over med digital check-in",
"overview_add_booking": "Find booking",
"open_room": "Åben værelse",
"hold_phone_to_door": "Hold tæt på læser",
"open_room_success": "Succes",
- "open_room_error": "Prøv igen!"
-
-
-
-
+ "open_room_error": "Prøv igen!",
+ "profile_settings": "Profilindstillinger",
+ "profil_settings_firstname": "Fornavn",
+ "profil_settings_lastname": "Efternavn",
+ "profil_settings_email": "Email",
+ "profil_settings_phone": "Telefon",
+ "profil_settings_address": "Adresse",
+ "profil_settings_birthday": "Fødselsdag",
+ "profil_settings_edit_password": "Ret adgangskode",
+ "profile_settings_error": "Der skete en fejl. Prøv igen.",
+ "delete_profile": "Slet profil"
}
\ 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 371e0b3d..d1cca5a2 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -39,5 +39,15 @@
"open_room": "Åben værelse",
"hold_phone_to_door": "Hold tæt på læser",
"open_room_success": "Succes",
- "open_room_error": "Prøv igen!"
+ "open_room_error": "Prøv igen!",
+ "profile_settings": "Profile settings",
+ "profil_settings_firstname": "First name",
+ "profil_settings_lastname": "Last name",
+ "profil_settings_email": "Email",
+ "profil_settings_phone": "Phone",
+ "profil_settings_address": "Address",
+ "profil_settings_birthday": "Birthday",
+ "profil_settings_edit_password": "Edit password",
+ "profile_settings_error": "An error occurred. Please try again later.",
+ "delete_profile": "Delete profile"
}
\ No newline at end of file
diff --git a/comwell_key_app/ios/Pods/Pods.xcodeproj/project.pbxproj b/comwell_key_app/ios/Pods/Pods.xcodeproj/project.pbxproj
index 8f86500a..c0446a42 100644
--- a/comwell_key_app/ios/Pods/Pods.xcodeproj/project.pbxproj
+++ b/comwell_key_app/ios/Pods/Pods.xcodeproj/project.pbxproj
@@ -98,8 +98,8 @@
5F1E34B02320621ADD70645B3B3F686A /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CC3EE236CFF6E3734FD0457BD774CAD3 /* PrivacyInfo.xcprivacy */; };
5F5A2FC226273299987042A6E5EDE906 /* DDFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AA8DDD3068346B61AA50EF87582074A /* DDFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
5F7428C718CB1956EC6F27E8D514A742 /* messages.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62256C568ABC53E00196E3E709849CB /* messages.g.swift */; };
- 60BC38382CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60BC38372CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework */; };
- 60BC383B2CDF5B2600EC35BC /* SeosMobileKeysSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60BC38372CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework */; };
+ 60BAB9A12CE37DDC00306826 /* SeosMobileKeysSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60BAB9A02CE37DDC00306826 /* SeosMobileKeysSDK.xcframework */; };
+ 60BAB9A42CE37DE400306826 /* SeosMobileKeysSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60BAB9A02CE37DDC00306826 /* SeosMobileKeysSDK.xcframework */; };
636C023F38B67A7BD547AF1593CC40AD /* JSONModelError.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C270AC53CF3B301FAC72EFDCC164C40 /* JSONModelError.m */; };
642F76E8AEF2094E8B48CD89516886BE /* FWFObjectHostApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 5199E34A55C34C6C790DEC69D4335D33 /* FWFObjectHostApi.m */; };
64B4D11469EE08608C25EB35ABD7A510 /* JSONHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E90EBCA7E43DCF9725F47115A6D71D2 /* JSONHTTPClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -607,7 +607,7 @@
5F2A2AD481C2DE0858B9CB5B15AA3A4E /* flutter_secure_storage.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = flutter_secure_storage.modulemap; sourceTree = "<group>"; };
5FC914D74A0C35CD9D61A4F2421C5950 /* shared_preferences_foundation-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "shared_preferences_foundation-dummy.m"; sourceTree = "<group>"; };
5FC949014A2CA3E61802E1985020214E /* PhonePermissionStrategy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PhonePermissionStrategy.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/ios/Classes/strategies/PhonePermissionStrategy.m"; sourceTree = "<group>"; };
- 60BC38372CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:333BNLD22V:ASSAABLOY AB"; lastKnownFileType = wrapper.xcframework; name = SeosMobileKeysSDK.xcframework; path = "/Users/nkl/Documents/GitHub/comwell-app/comwell_key_app/ios/../../mobilekeys_sdk_plugin/XCFrameworks/SeosMobileKeysSDK.xcframework"; sourceTree = "<absolute>"; };
+ 60BAB9A02CE37DDC00306826 /* SeosMobileKeysSDK.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:333BNLD22V:ASSAABLOY AB"; lastKnownFileType = wrapper.xcframework; name = SeosMobileKeysSDK.xcframework; path = "/Users/nkl/Documents/GitHub/comwell-app/comwell_key_app/ios/../../mobilekeys_sdk_plugin/XCFrameworks/SeosMobileKeysSDK.xcframework"; sourceTree = "<absolute>"; };
60D6271F10B8137EC4D477615AC0BD63 /* SharedPreferencesPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SharedPreferencesPlugin.swift; path = "../../../../../../../../../../../../.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.0/darwin/shared_preferences_foundation/Sources/shared_preferences_foundation/SharedPreferencesPlugin.swift"; sourceTree = "<group>"; };
61EE5DC6377CAAF6DD8A600301813986 /* vibration.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = vibration.release.xcconfig; sourceTree = "<group>"; };
62913BA9BBD7FF7F3463C26CB8EFEB48 /* ResourceBundle-CocoaLumberjackPrivacy-CocoaLumberjack-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-CocoaLumberjackPrivacy-CocoaLumberjack-Info.plist"; sourceTree = "<group>"; };
@@ -912,7 +912,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 60BC383B2CDF5B2600EC35BC /* SeosMobileKeysSDK.xcframework in Frameworks */,
+ 60BAB9A12CE37DDC00306826 /* SeosMobileKeysSDK.xcframework in Frameworks */,
1BA7E7CDE434910A21FD7A43B83763AD /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -957,7 +957,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 60BC38382CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework in Frameworks */,
+ 60BAB9A42CE37DE400306826 /* SeosMobileKeysSDK.xcframework in Frameworks */,
F13C984AB4264D7BFDAA818D3A29CB63 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -2962,7 +2962,7 @@
D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 60BC38372CDF5B1C00EC35BC /* SeosMobileKeysSDK.xcframework */,
+ 60BAB9A02CE37DDC00306826 /* SeosMobileKeysSDK.xcframework */,
578452D2E740E91742655AC8F1636D1F /* iOS */,
);
name = Frameworks;
diff --git a/comwell_key_app/lib/comwell_app.dart b/comwell_key_app/lib/comwell_app.dart
index 3c3a46e2..9d35d8b1 100644
--- a/comwell_key_app/lib/comwell_app.dart
+++ b/comwell_key_app/lib/comwell_app.dart
@@ -7,6 +7,8 @@ import 'package:comwell_key_app/key/repository/key_repository.dart';
import 'package:comwell_key_app/overview/cubit/overview_cubit.dart';
import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
+import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
+import 'package:comwell_key_app/profile_settings/profile_settings_repository.dart';
import 'package:comwell_key_app/routing/app_router.dart';
import 'package:comwell_key_app/themes/dark_theme.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
@@ -62,5 +64,9 @@ final List<BlocProvider> blocProviderList = [
lazy: false,
create: (BuildContext context) => ProfileCubit(profileRepository: ProfileRepository()),
),
+ BlocProvider<ProfileSettingsCubit>(
+ lazy: false,
+ create: (BuildContext context) => ProfileSettingsCubit(profileSettingsRepository: ProfileSettingsRepository()),
+ ),
];
diff --git a/comwell_key_app/lib/profile/profile_page.dart b/comwell_key_app/lib/profile/profile_page.dart
index e02679ea..16ec88b3 100644
--- a/comwell_key_app/lib/profile/profile_page.dart
+++ b/comwell_key_app/lib/profile/profile_page.dart
@@ -1,7 +1,7 @@
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/profile/components/profile_settings_item.dart';
-import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
+import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/secure_storage.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -123,7 +123,7 @@ class ProfilePage extends StatelessWidget {
text: 'profile_settings_profile_menu'.tr(),
trailingIcon: Icons.chevron_right,
onTap: () {
- // Navigate to profile settings
+ context.pushNamed(AppRoutes.profileSettings.name);
},
),
const Padding(
diff --git a/comwell_key_app/lib/profile_settings/components/Text_field_trailing_icon.dart b/comwell_key_app/lib/profile_settings/components/Text_field_trailing_icon.dart
new file mode 100644
index 00000000..aaa00ac0
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/components/Text_field_trailing_icon.dart
@@ -0,0 +1,63 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class TextFieldWithTrailingIcon extends StatelessWidget {
+ final String title;
+ final String text;
+ final String trailingIcon;
+ final VoidCallback onTap;
+ final bool showTitle;
+
+ const TextFieldWithTrailingIcon({
+ super.key,
+ required this.title,
+ required this.text,
+ required this.trailingIcon,
+ required this.onTap,
+ required this.showTitle,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return GestureDetector(
+ onTap: onTap,
+ child: Container(
+ height: 62,
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(8.0),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ if (showTitle)
+ Text(
+ title,
+ textAlign: TextAlign.start,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: Colors.black.withOpacity(
+ 0.65,
+ ),
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ Text(text, style: theme.textTheme.headlineSmall),
+ ],
+ ),
+ SvgPicture.asset(
+ trailingIcon,
+ height: 24.0,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
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
index 1dc4ff15..ae68a8df 100644
--- a/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
+++ b/comwell_key_app/lib/profile_settings/components/comwell_text_field.dart
@@ -3,22 +3,48 @@ import 'package:flutter/material.dart';
class ComwellTextField extends StatelessWidget {
final String fieldName;
+ final String initialValue;
- const ComwellTextField({super.key, required this.fieldName});
+ const ComwellTextField({super.key,
+ required this.fieldName,
+ required this.initialValue});
@override
Widget build(BuildContext context) {
- return TextField(
-
- decoration: InputDecoration(
- labelText: fieldName,
- floatingLabelBehavior: FloatingLabelBehavior.always,
- border: const OutlineInputBorder(
- borderSide: BorderSide(
- color: colorDivider,
+ 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,
+
),
- ),
+ ]),
),
);
}
-}
\ No newline at end of file
+}
diff --git a/comwell_key_app/lib/profile_settings/components/date_time_picker.dart b/comwell_key_app/lib/profile_settings/components/date_time_picker.dart
new file mode 100644
index 00000000..5bd4a499
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/components/date_time_picker.dart
@@ -0,0 +1,77 @@
+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';
+
+class DateTimePicker extends StatefulWidget {
+ final String title;
+ final DateTime initialValue;
+ const DateTimePicker(
+ {required this.title, required this.initialValue, super.key});
+
+ @override
+ State<DateTimePicker> createState() => _DatePickerState();
+}
+
+class _DatePickerState extends State<DateTimePicker> {
+ DateTime? _selectedDate;
+
+ Future _selectDate(BuildContext context) async => showDatePicker(
+ context: context,
+ initialDate: DateTime.now(),
+ firstDate: DateTime(2000),
+ lastDate: DateTime(2050),
+ ).then((DateTime? selected) {
+ if (selected != null && selected != _selectedDate) {
+ setState(() => _selectedDate = selected);
+ }
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final dateFormat = DateFormat('dd/MM/yyyy');
+
+ return GestureDetector(
+ onTap: () => _selectDate(context),
+ child: Container(
+ height: 62,
+ padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0),
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ borderRadius: BorderRadius.circular(8.0),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ widget.title,
+ textAlign: TextAlign.start,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: Colors.black.withOpacity(
+ 0.65,
+ ),
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ Text(
+ _selectedDate != null
+ ? dateFormat.format(_selectedDate!)
+ : dateFormat.format(widget.initialValue),
+ style: theme.textTheme.headlineSmall),
+ ],
+ ),
+ SvgPicture.asset(
+ "assets/icons/calendar.svg",
+ height: 24.0,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart b/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart
new file mode 100644
index 00000000..a32755df
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/components/intl_phone_field.dart
@@ -0,0 +1,105 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+class IntlPhoneField extends StatefulWidget {
+ final String title;
+ final String phoneNumber;
+ const IntlPhoneField(
+ {required this.title, required this.phoneNumber, super.key});
+
+ @override
+ _IntlPhoneFieldState createState() => _IntlPhoneFieldState();
+}
+
+class _IntlPhoneFieldState extends State<IntlPhoneField> {
+ final GlobalKey<FormState> formKey = GlobalKey<FormState>();
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Form(
+ key: formKey,
+ child: Container(
+ height: 62,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(color: colorDivider),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: <Widget>[
+ CountryCodePicker(
+ initialSelection: "DK",
+ showFlag: false,
+ favorite: const [
+ 'SE',
+ 'DK',
+ 'NO',
+ 'DE',
+ ],
+ showDropDownButton: true,
+ padding: const EdgeInsets.symmetric(horizontal: 0),
+ textStyle: theme.textTheme.headlineSmall,
+ ),
+ Container(
+ width: 1,
+ height: 40,
+ color: colorDivider,
+ ),
+ const SizedBox(
+ width: 20,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ widget.title,
+ textAlign: TextAlign.start,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: Colors.black.withOpacity(
+ 0.65,
+ ),
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ Text(widget.phoneNumber, style: theme.textTheme.headlineSmall),
+ ],
+ ),
+ /* InternationalPhoneNumberInput(
+
+ inputBorder: InputBorder.none,
+ onInputChanged: (PhoneNumber number) {
+ print(number.phoneNumber);
+ },
+ onInputValidated: (bool value) {
+ print(value);
+ },
+ selectorConfig: const SelectorConfig(
+ selectorType: PhoneInputSelectorType.DROPDOWN,
+ useBottomSheetSafeArea: true,
+ showFlags: false,
+ ),
+ ignoreBlank: false,
+ textStyle: theme.textTheme.headlineSmall,
+ autoValidateMode: AutovalidateMode.disabled,
+ selectorTextStyle: const TextStyle(color: Colors.black),
+ initialValue: number,
+
+ textFieldController: controller,
+ formatInput: true,
+ keyboardType:
+ const TextInputType.numberWithOptions(signed: true, decimal: true),
+
+ onSaved: (PhoneNumber number) {
+ print('On Saved: $number');
+ },
+ ), */
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart b/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart
new file mode 100644
index 00000000..2051aaa3
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/cubit/profile_settings_cubit.dart
@@ -0,0 +1,22 @@
+import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/profile_settings/profile_settings_repository.dart';
+import 'package:equatable/equatable.dart';
+
+part 'profile_settings_state.dart';
+
+class ProfileSettingsCubit extends Cubit<ProfileSettingsState> {
+ final ProfileSettingsRepository profileSettingsRepository;
+ ProfileSettingsCubit({required this.profileSettingsRepository}) : super(ProfileSettingsInitial());
+
+ void fetchProfileSettings() async {
+ emit(ProfileSettingsLoading());
+ try {
+ // Fetch profile settings
+ final user = await profileSettingsRepository.fetchProfileSettings();
+ emit(ProfileSettingsLoaded(user!));
+ } catch (e) {
+ emit(ProfileSettingsError());
+ }
+ }
+}
diff --git a/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart b/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart
new file mode 100644
index 00000000..5414bc88
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/cubit/profile_settings_state.dart
@@ -0,0 +1,25 @@
+part of 'profile_settings_cubit.dart';
+
+sealed class ProfileSettingsState extends Equatable {
+ const ProfileSettingsState();
+
+ @override
+ List<Object> get props => [];
+}
+
+final class ProfileSettingsInitial extends ProfileSettingsState {}
+
+final class ProfileSettingsLoading extends ProfileSettingsState {}
+
+final class ProfileSettingsLoaded extends ProfileSettingsState {
+ final User user;
+
+ const ProfileSettingsLoaded(this.user);
+
+ @override
+ List<Object> get props => [user];
+}
+
+final class ProfileSettingsError extends ProfileSettingsState {}
+
+
diff --git a/comwell_key_app/lib/profile_settings/model/address.dart b/comwell_key_app/lib/profile_settings/model/address.dart
new file mode 100644
index 00000000..4a7258c8
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/model/address.dart
@@ -0,0 +1,31 @@
+class Address {
+ final String street;
+ final String city;
+ final String country;
+ final String zipCode;
+
+ Address({
+ required this.street,
+ required this.city,
+ required this.country,
+ required this.zipCode,
+ });
+
+ factory Address.fromJson(Map<String, dynamic> json) {
+ return Address(
+ street: json['street'] as String,
+ city: json['city'] as String,
+ country: json['state'] as String,
+ zipCode: json['zipCode'] as String,
+ );
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ 'street': street,
+ 'city': city,
+ 'state': country,
+ 'zipCode': zipCode,
+ };
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/profile_settings/model/user.dart b/comwell_key_app/lib/profile_settings/model/user.dart
new file mode 100644
index 00000000..61ff5fff
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/model/user.dart
@@ -0,0 +1,48 @@
+import 'package:comwell_key_app/profile_settings/model/address.dart';
+
+class User {
+ final String id;
+ final String firstName;
+ final String lastName;
+ final String countryCode;
+ final String phone;
+ final String email;
+ final Address address;
+ final DateTime birthday;
+
+ User({
+ required this.id,
+ required this.firstName,
+ required this.lastName,
+ required this.countryCode,
+ required this.phone,
+ required this.email,
+ required this.address,
+ required this.birthday,
+ });
+
+ factory User.fromJson(dynamic json) {
+ return User(
+ id: json['id'] as String,
+ firstName: json['firstName'] as String,
+ lastName: json['lastName'] as String,
+ countryCode: json['countryCode'] as String,
+ phone: json['phone'] as String,
+ email: json['email'] as String,
+ address: Address.fromJson(json['address'] as Map<String, dynamic>),
+ birthday: DateTime.parse(json['birthday'] as String),
+ );
+ }
+
+ Map<String, dynamic> toJson() {
+ return {
+ 'id': id,
+ 'firstName': firstName,
+ 'lastName': lastName,
+ 'phone': phone,
+ 'email': email,
+ 'address': address.toJson(),
+ 'birthday': birthday.toIso8601String(),
+ };
+ }
+}
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 28b3648f..cc86a987 100644
--- a/comwell_key_app/lib/profile_settings/profile_settings_page.dart
+++ b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
@@ -1,44 +1,138 @@
import 'package:comwell_key_app/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/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';
+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/flutter_svg.dart';
class ProfileSettingsPage extends StatelessWidget {
-
const ProfileSettingsPage({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
+ final TextEditingController controller = TextEditingController();
+ context.read<ProfileSettingsCubit>().fetchProfileSettings();
+ return BlocBuilder<ProfileSettingsCubit, ProfileSettingsState>(
+ builder: (context, state) {
+ if (state is ProfileSettingsLoading) {
+ return const Scaffold(
+ appBar: ComwellAppBar(
+ shouldShowProfileButton: false,
+ ),
+ backgroundColor: Colors.white,
+ body: Center(child: CircularProgressIndicator()));
+ } else if (state is ProfileSettingsLoaded) {
+ return _buildProfileSettingsPage(theme, state);
+ } else {
+ return Scaffold(
+ appBar: const ComwellAppBar(
+ shouldShowProfileButton: false,
+ ),
+ backgroundColor: Colors.white,
+ body: Center(
+ child: Text(
+ "profile_settings_error".tr(),
+ style: theme.textTheme.headlineLarge,
+ )));
+ }
+ },
+ );
+ }
+
+ Widget _buildProfileSettingsPage(
+ ThemeData theme, ProfileSettingsState state) {
+ final ProfileSettingsLoaded loadedState = state as ProfileSettingsLoaded;
return Scaffold(
backgroundColor: Colors.white,
appBar: const ComwellAppBar(
shouldShowProfileButton: false,
),
- body: Container(margin: const EdgeInsets.symmetric(horizontal: 16), child: SafeArea( child:
- Column(
-
- children: [
- const Spacer(),
- Text("profile_settings".tr(), style: theme.textTheme.headlineLarge, textAlign: TextAlign.start),
- const Spacer(),
- const ComwellTextField(fieldName: "Fornavn"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: "Efternavn"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: "Email"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: "Telefonnummer"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: "Adresse"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: "Fødselsdag"),
- const SizedBox(height: 8),
- const ComwellTextField(fieldName: 'password'),
- const SizedBox(height: 100),
- ],
- ),
+ body: SingleChildScrollView(
+ child: Container(
+ margin: const EdgeInsets.symmetric(horizontal: 16),
+ child: SafeArea(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 36),
+ Text("profile_settings".tr(),
+ style: theme.textTheme.headlineLarge,
+ textAlign: TextAlign.start),
+ const SizedBox(height: 36),
+ ComwellTextField(
+ fieldName: "profil_settings_firstname".tr(),
+ initialValue: loadedState.user.firstName),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ fieldName: "profil_settings_lastname".tr(),
+ initialValue: loadedState.user.lastName),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ fieldName: "profil_settings_email".tr(),
+ initialValue: loadedState.user.email),
+ const SizedBox(height: 8),
+ IntlPhoneField(
+ title: "profil_settings_phone".tr(),
+ phoneNumber: loadedState.user.phone,
+ ),
+ const SizedBox(height: 8),
+ TextFieldWithTrailingIcon(
+ title: "profil_settings_address".tr(),
+ text:
+ "${loadedState.user.address.street}, ${loadedState.user.address.city}, ${loadedState.user.address.zipCode}, ${loadedState.user.address.country}",
+ trailingIcon: "assets/icons/edit-alt.svg",
+ onTap: () {},
+ showTitle: true),
+ const SizedBox(height: 8),
+ DateTimePicker(
+ title: "profil_settings_birthday".tr(),
+ initialValue: loadedState.user.birthday,
+ ),
+ const SizedBox(height: 8),
+ TextFieldWithTrailingIcon(
+ title: "",
+ text: "profil_settings_edit_password".tr(),
+ trailingIcon: "assets/icons/arrow-left.svg",
+ onTap: () {},
+ showTitle: false),
+ const SizedBox(height: 40),
+ Center(
+ child: OutlinedButton(
+ onPressed: () {},
+ style: OutlinedButton.styleFrom(
+ side: const BorderSide(color: colorDivider),
+ backgroundColor: Colors.transparent,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(20)),
+ ),
+ minimumSize: const Size(135, 36),
+ maximumSize: const Size(135, 36),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ SvgPicture.asset("assets/icons/trash-can.svg",
+ height: 16),
+ const SizedBox(width: 4),
+ Text(
+ "delete_profile".tr(),
+ style: theme.textTheme.labelLarge
+ ?.copyWith(color: Colors.red),
+ ),
+ ]),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
),
- ),);
+ );
}
-}
\ No newline at end of file
+}
diff --git a/comwell_key_app/lib/profile_settings/profile_settings_repository.dart b/comwell_key_app/lib/profile_settings/profile_settings_repository.dart
new file mode 100644
index 00000000..87be0d10
--- /dev/null
+++ b/comwell_key_app/lib/profile_settings/profile_settings_repository.dart
@@ -0,0 +1,17 @@
+import 'package:comwell_key_app/profile_settings/model/user.dart';
+import 'package:comwell_key_app/services/api.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'dart:convert';
+
+class ProfileSettingsRepository {
+ final Api api = Api();
+
+
+ Future<User?> fetchProfileSettings() async {
+ final userJson = await api.fetchProfileSettings();
+ if (userJson != null) {
+ return User.fromJson(jsonDecode(userJson as String));
+ }
+ return null;
+}
+ }
\ No newline at end of file
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index e1709d17..5e6b968d 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -16,7 +16,7 @@ final _rootNavigatorKey = GlobalKey<NavigatorState>();
GoRouter goRouter(AuthenticationBloc authBloc) {
return GoRouter(
- initialLocation: '/profilesettings',
+ initialLocation: '/login',
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
refreshListenable:
@@ -46,11 +46,6 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
return null;
},
routes: <RouteBase>[
- GoRoute(
- path: "/profilesettings",
- name: AppRoutes.profileSettings.name,
- builder: (context, state) => const ProfileSettingsPage(),
- ),
GoRoute(
path: "/oauthredirect",
name: AppRoutes.overview.name,
@@ -74,6 +69,14 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
builder: (context, state) {
return ProfilePage(); //mobileKey: key);
},
+ routes: [
+ GoRoute(
+ path: "profilesettings",
+ name: AppRoutes.profileSettings.name,
+ builder: (context, state) =>
+ const ProfileSettingsPage(),
+ ),
+ ],
)
]),
]),
diff --git a/comwell_key_app/lib/services/api.dart b/comwell_key_app/lib/services/api.dart
index 2656fb9b..179baa54 100644
--- a/comwell_key_app/lib/services/api.dart
+++ b/comwell_key_app/lib/services/api.dart
@@ -26,8 +26,31 @@ class Api {
}
Future<Response<dynamic>> provisionKey(String bookingId) async {
- return await dio.post('/keys/v1/ProvisionKey', data: {
- 'bookingId': bookingId
- });
+ return await dio
+ .post('/keys/v1/ProvisionKey', data: {'bookingId': bookingId});
+ }
+
+ Future<dynamic> fetchProfileSettings() async {
+ await Future.delayed(const Duration(seconds: 2));
+
+ // Return the mock JSON data
+ return '''
+ {
+ "id": "1",
+ "firstName": "John",
+ "lastName": "Doe",
+ "countryCode": "+45",
+ "phone": "12345678",
+ "email": "john.doe@example.com",
+ "address": {
+ "street": "123 Main St",
+ "city": "Copenhagen",
+ "state": "Capital Region",
+ "zipCode": "1000",
+ "country": "Denmark"
+ },
+ "birthday": "1989-08-24T00:00:00.000Z"
+ }
+ ''';
}
}
diff --git a/comwell_key_app/lib/themes/light_theme.dart b/comwell_key_app/lib/themes/light_theme.dart
index 3e36ff5d..556ddee2 100644
--- a/comwell_key_app/lib/themes/light_theme.dart
+++ b/comwell_key_app/lib/themes/light_theme.dart
@@ -19,7 +19,9 @@ 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)
+ bodySmall: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
+ labelLarge: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600),
+
),
colorScheme: const ColorScheme(
diff --git a/comwell_key_app/pubspec.yaml b/comwell_key_app/pubspec.yaml
index adb71429..bb5dcdb4 100644
--- a/comwell_key_app/pubspec.yaml
+++ b/comwell_key_app/pubspec.yaml
@@ -52,6 +52,7 @@ dependencies:
jwt_decoder: ^2.0.1
flutter_launcher_icons: ^0.14.1
slider_button: ^2.1.0
+ country_code_picker: ^3.1.0
dev_dependencies:
flutter_test: