From 001334819e2253f927660dfb120d10a20b8c544e Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 30 Oct 2025 17:14:26 +0530 Subject: [PATCH] register oidc changes, Login by oidc --- lib/config/my_router.dart | 30 +- .../auth_verification/registration.dart | 826 +++++++++++------- .../auth_routes/fcsc_profile_linking.dart | 222 ++--- .../routes/auth_routes/login_route.dart | 225 ++--- .../routes/auth_routes/register_route.dart | 730 ++++++++-------- pubspec.lock | 68 +- 6 files changed, 1149 insertions(+), 952 deletions(-) diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index c7311117..9b59b19b 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -94,7 +94,25 @@ final GoRouter router = GoRouter( return LoginRoute(fromPage: fromPage, userInfo: userInfo); }, ), + GoRoute( + path: '/register', + builder: (context, state) { + final extra = state.extra; + final fromPage = (extra is Map && extra['fromPage'] is String) + ? extra['fromPage'] as String + : null; + final userInfo = (extra is Map && extra['userInfo'] is Map) + ? Map.from(extra['userInfo']) + : {}; + + return RegisterScreen(fromPage: fromPage, userInfo: userInfo); + }, + ), + // GoRoute( + // path: '/register', + // builder: (context, state) => RegisterScreen(), + // ), GoRoute( path: '/fcscprofilelinking', builder: (context, state) { @@ -114,10 +132,7 @@ final GoRouter router = GoRouter( path: '/myhomepage', builder: (context, state) => MyHomePage(), ), - GoRoute( - path: '/register', - builder: (context, state) => RegisterScreen(), - ), + // GoRoute( // path: '/DemoHome/:dataSets', // builder: (context, state) { @@ -380,7 +395,7 @@ final GoRouter router = GoRouter( builder: (context, state) { final report = state.extra as Map; return ReportDetailPage( - title:report['title']!, + title: report['title']!, ); }, ), @@ -395,10 +410,9 @@ final GoRouter router = GoRouter( state.uri.path == '/login' || state.uri.path == '/register' || state.uri.path.startsWith('/forgot-password/') || - state.uri.path == '/termsandconditions'|| + state.uri.path == '/termsandconditions' || state.uri.path == '/privacy_policy' || - state.uri.path == '/fcscprofilelinking' - ) { + state.uri.path == '/fcscprofilelinking') { return null; } diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index f5e17320..85297e17 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -17,9 +17,19 @@ import 'package:uae_stat/l10n/app_localizations.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../routes/auth_routes/login_route.dart'; class RegisterScreen extends ConsumerStatefulWidget { + final String? fromPage; + final Map? userInfo; + + const RegisterScreen({ + Key? key, + this.fromPage, + this.userInfo, + }) : super(key: key); + @override _RegisterScreenState createState() => _RegisterScreenState(); } @@ -41,6 +51,7 @@ class _RegisterScreenState extends ConsumerState { bool registrationFailed = false; bool isRegistering = false; dynamic userID; + bool cameFromLinking = false; final pb = PocketBase(apiUrl); // final pb = PocketBase('http://127.0.0.1:8090'); @@ -66,6 +77,9 @@ class _RegisterScreenState extends ConsumerState { void initState() { super.initState(); + print( + 'REGISTRATION -FROMPAGE - ${widget.fromPage} - userInfo - ${widget.userInfo}'); + // Add listeners for focus nodes for (int i = 0; i < _focusNodes.length; i++) { _focusNodes[i].addListener(() { @@ -236,16 +250,37 @@ class _RegisterScreenState extends ConsumerState { var mailID = _emailController.text; var email = mailID.toLowerCase(); // Create user in PocketBase - final response = await pb.collection('users').create(body: { - 'uname': _usernameController.text, - 'email': email, - 'password': _passwordController.text, - 'passwordConfirm': _passwordController.text, - 'status': 'Pending', - 'role': 'user', - }, headers: { - // 'Authorization': adminToken - }); + final response = cameFromLinking + ? await pb.collection('users').create( + body: { + 'uname': _usernameController.text, + 'email': email, + 'password': '', + 'passwordConfirm': '', + 'status': 'Approved', + 'role': 'user', + 'user_mail_verify': true, + 'reviewed': true, + 'emiratesid': widget.userInfo?['uuid'], + "is_oauth_login": 1, + }, + headers: { + // 'Authorization': adminToken + }, + ) + : await pb.collection('users').create( + body: { + 'uname': _usernameController.text, + 'email': email, + 'password': _passwordController.text, + 'passwordConfirm': _passwordController.text, + 'status': 'Pending', + 'role': 'user', + }, + headers: { + // 'Authorization': adminToken + }, + ); if (response.id != null) { userID = response.id; // Request email verification @@ -359,11 +394,104 @@ class _RegisterScreenState extends ConsumerState { } } + Future oAuthOIDCLogin( + BuildContext context, WidgetRef ref, platform) async { + setState(() { + hasValidated = true; + }); + + if (!(_formKey.currentState?.validate() ?? false)) return; + + if (!isChecked) { + setState(() => showError = true); + return; + } + + setState(() { + isLoading = true; + isRegistering = true; + }); + + print('platform $platform'); + try { + print('platform $platform'); + + final authData = + await pb.collection('users').authWithOAuth2(platform, (url) async { + await launchUrl(url); + }); + + print('authData $authData'); + // ✅ Check if authData is valid + if (authData.token.isNotEmpty && authData.record != null) { + print("✅ Login Successful"); + print(authData.record); + + final metaDetails = authData.meta; + final userDetails = authData.record; + final token = authData.token; + final userId = userDetails?.id; + final email = userDetails?.data['email'] ?? ''; + final isProfileComplete = + userDetails?.data['is_profile_completed'] ?? ''; + final loginCount = userDetails?.data['login_count'] ?? ''; + + print("User ID: ${userId}"); + print("Email: ${email}"); + print("Email: ${isProfileComplete}"); + print("Email: ${loginCount}"); + + // final session = await context.loaderWithErrorDialog( + // () => ref + // .read( + // authUseCaseProvider.notifier, + // ) + // .googleAndAppleAuthencation(authData), + // errorDialogBuilder: ( + // error, [ + // StackTrace? stackTrace, + // ]) { + // if (error == LoginError.invalidEmailPw) { + // return context.simpleDialog( + // title: context.translate( + // 'Incorrect Credentials', + // 'أوراق غير صحيحة', + // ), + // content: context.translate( + // 'Your email or password is invalid. Please try again.', + // 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.', + // ), + // ); + // } + // return context.simpleDialog(); + // }, + } else { + print("❌ Login failed: Invalid authData"); + } + } catch (e) { + print("❌ Error during Google login: $e"); + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar(content: Text("Login failed. Please try again.")), + // ); + } + } + + void handleSuccess(RecordModel response) { + setState(() { + userID = response.id; + registrationSuccess = true; + registrationFailed = false; + isRegistering = false; + isLoading = false; + }); + } + @override Widget build(BuildContext context) { double screenheight = MediaQuery.of(context).size.height; double screenwidth = MediaQuery.of(context).size.width; final registerLocale = ref.watch(localeProvider); + cameFromLinking = widget.fromPage == 'fcscprofilelinking'; ref.listen>(connectivityProvider, (previous, hasInternet) { if (hasInternet.value == false) { @@ -933,270 +1061,282 @@ class _RegisterScreenState extends ConsumerState { ), ), SizedBox(height: 15), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: _passwordController, - // focusNode: _focusNodes[2], - obscureText: _obscurePassword, - decoration: InputDecoration( - filled: true, - fillColor: isDarkTheme - ? const Color(0xFF000000) - : Colors.white, - errorStyle: TextStyle( - color: Color(0xFFD83731), - // color: isDarkTheme - // ? Color(0xFFFFA200) - // : Color(0xFFb22222), - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - ), - hintText: _showHints[2] - ? AppLocalizations.of( - context)! - .enter_your_password - : null, - // _showHints[2] ? 'Enter your password' : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: - const EdgeInsetsDirectional - .only( - start: 16, - end: 10, - ), - child: Image.asset( - MiscIconAssetPath.lock, - fit: BoxFit.fitHeight, - height: 25, - width: 25, - ), - ), - // prefixIcon: Icon( - // Icons.lock, - // color: Color(0xFF90B0D5), - // ), - suffixIcon: IconButton( - // icon: Icon( - // _obscurePassword - // ? Icons.visibility_off - // : Icons.visibility, - // color: Color(0xFF9EA2A9), + if (!cameFromLinking) ...[ + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: _passwordController, + // focusNode: _focusNodes[2], + obscureText: _obscurePassword, + decoration: InputDecoration( + filled: true, + fillColor: isDarkTheme + ? const Color(0xFF000000) + : Colors.white, + errorStyle: TextStyle( + color: Color(0xFFD83731), + // color: isDarkTheme + // ? Color(0xFFFFA200) + // : Color(0xFFb22222), + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + ), + hintText: _showHints[2] + ? AppLocalizations.of( + context)! + .enter_your_password + : null, + // _showHints[2] ? 'Enter your password' : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), + prefixIcon: Padding( + padding: + const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.lock, + fit: BoxFit.fitHeight, + height: 25, + width: 25, + ), + ), + + // prefixIcon: Icon( + // Icons.lock, + // color: Color(0xFF90B0D5), // ), + suffixIcon: IconButton( + // icon: Icon( + // _obscurePassword + // ? Icons.visibility_off + // : Icons.visibility, + // color: Color(0xFF9EA2A9), + // ), - icon: Image.asset( - _obscurePassword - ? MiscIconAssetPath - .visibilityOff - : MiscIconAssetPath - .visibleOn, + icon: Image.asset( + _obscurePassword + ? MiscIconAssetPath + .visibilityOff + : MiscIconAssetPath + .visibleOn, - color: Color( - 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. - width: 24, - height: 24, + color: Color( + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + width: 24, + height: 24, + ), + + onPressed: () { + setState(() { + _obscurePassword = + !_obscurePassword; + }); + }, + ), + // border: OutlineInputBorder(), + enabledBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFB68A34), + width: 1), + ), + focusedBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFB68A34), + width: + 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFD83731), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFD83731), + width: + 1), // Match the error color ), - onPressed: () { - setState(() { - _obscurePassword = - !_obscurePassword; - }); - }, - ), - // border: OutlineInputBorder(), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFB68A34), - width: 1), - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFB68A34), - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFD83731), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFD83731), - width: - 1), // Match the error color - ), - - counterText: '', - hintStyle: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', + counterText: '', + hintStyle: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + color: + const Color(0xFFC3C6CB), + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 14 + : 16, ), - color: const Color(0xFFC3C6CB), - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 14 - : 16, ), + validator: _validatePassword, + maxLength: 40, + maxLengthEnforcement: + MaxLengthEnforcement.enforced, ), - validator: _validatePassword, - maxLength: 40, - maxLengthEnforcement: - MaxLengthEnforcement.enforced, ), - ), - SizedBox(height: 10), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 10, - left: 30, - right: 30), - child: TextFormField( - controller: - _confirmpasswordController, - // focusNode: _focusNodes[3], - obscureText: - _obscureConfirmPassword, - decoration: InputDecoration( - filled: true, - fillColor: isDarkTheme - ? const Color(0xFF000000) - : Colors.white, - errorStyle: TextStyle( - color: Color(0xFFD83731), - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', + SizedBox(height: 10), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 10, + left: 30, + right: 30), + child: TextFormField( + controller: + _confirmpasswordController, + // focusNode: _focusNodes[3], + obscureText: + _obscureConfirmPassword, + decoration: InputDecoration( + filled: true, + fillColor: isDarkTheme + ? const Color(0xFF000000) + : Colors.white, + errorStyle: TextStyle( + color: Color(0xFFD83731), + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), ), - ), - hintText: _showHints[3] - ? AppLocalizations.of( - context)! - .register_Confirm_password - : null, - // _showHints[3] ? 'Confirm password' : null, - prefixIconConstraints: - const BoxConstraints( - maxWidth: 25 + 16 + 10, - maxHeight: 25 + (8 * 2), - ), - prefixIcon: Padding( - padding: - const EdgeInsetsDirectional - .only( - start: 16, - end: 10, + hintText: _showHints[3] + ? AppLocalizations.of( + context)! + .register_Confirm_password + : null, + // _showHints[3] ? 'Confirm password' : null, + prefixIconConstraints: + const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), ), - child: Image.asset( - MiscIconAssetPath.lock, - fit: BoxFit.fitHeight, - height: 25, - width: 25, + prefixIcon: Padding( + padding: + const EdgeInsetsDirectional + .only( + start: 16, + end: 10, + ), + child: Image.asset( + MiscIconAssetPath.lock, + fit: BoxFit.fitHeight, + height: 25, + width: 25, + ), ), - ), - suffixIcon: IconButton( - icon: Image.asset( - _obscureConfirmPassword - ? MiscIconAssetPath - .visibilityOff - : MiscIconAssetPath - .visibleOn, + suffixIcon: IconButton( + icon: Image.asset( + _obscureConfirmPassword + ? MiscIconAssetPath + .visibilityOff + : MiscIconAssetPath + .visibleOn, - color: Color( - 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. - width: 24, - height: 24, + color: Color( + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + width: 24, + height: 24, + ), + onPressed: () { + setState(() { + _obscureConfirmPassword = + !_obscureConfirmPassword; + }); + }, ), - onPressed: () { - setState(() { - _obscureConfirmPassword = - !_obscureConfirmPassword; - }); - }, - ), - // border: OutlineInputBorder( - // borderSide: BorderSide(color: Colors.blue, width: 2), // Default border color - // ), - enabledBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFB68A34), - width: 1), - ), - focusedBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFB68A34), - width: 2), // Focused border - ), - errorBorder: OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFD83731), - width: 1), // Error border - ), - focusedErrorBorder: - OutlineInputBorder( - borderRadius: - BorderRadius.circular(10), - borderSide: BorderSide( - color: Color(0xFFD83731), - width: - 1), // Match the error color - ), - counterText: '', - hintStyle: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', + // border: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.blue, width: 2), // Default border color + // ), + enabledBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFB68A34), + width: 1), + ), + focusedBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFB68A34), + width: + 2), // Focused border + ), + errorBorder: OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFD83731), + width: 1), // Error border + ), + focusedErrorBorder: + OutlineInputBorder( + borderRadius: + BorderRadius.circular(10), + borderSide: BorderSide( + color: Color(0xFFD83731), + width: + 1), // Match the error color + ), + counterText: '', + hintStyle: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + color: + const Color(0xFFC3C6CB), + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 14 + : 16, ), - color: const Color(0xFFC3C6CB), - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 14 - : 16, ), + validator: + _validateConfirmPassword, + maxLength: 40, + maxLengthEnforcement: + MaxLengthEnforcement.enforced, + inputFormatters: [ + LengthLimitingTextInputFormatter( + 64), // Limit to 40 characters + ], ), - validator: _validateConfirmPassword, - maxLength: 40, - maxLengthEnforcement: - MaxLengthEnforcement.enforced, - inputFormatters: [ - LengthLimitingTextInputFormatter( - 64), // Limit to 40 characters - ], ), - ), - SizedBox(height: 10), + SizedBox(height: 10), + ], Padding( padding: const EdgeInsets.only( top: 0, @@ -1429,9 +1569,19 @@ class _RegisterScreenState extends ConsumerState { child: SizedBox( width: screenwidth / 1, child: ElevatedButton( - onPressed: isRegistering - ? null - : _registerUser, + // onPressed: isRegistering + // ? null + // : _registerUser? + onPressed: () { + if (isRegistering) { + _registerUser; + } else if (cameFromLinking) { + oAuthOIDCLogin(context, ref, + 'oidc'); //Open ID connect + } else { + null; + } + }, style: ElevatedButton.styleFrom( backgroundColor: Color( 0xFFB68A34), // Brownish color for Register @@ -1578,87 +1728,99 @@ class _RegisterScreenState extends ConsumerState { // ), // ), // ), - - SizedBox(height: 20), - Text( - AppLocalizations.of(context)! - .account_confirmation, - style: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontWeight: FontWeight.w500, - fontSize: - registerLocale?.languageCode == - 'ar' - ? 12 - : 14, - color: isDarkTheme - ? Color(0xFFFFFFFF) - : Color(0xFF898C81), - ), - ), - SizedBox(height: 5), - Padding( - padding: const EdgeInsets.only( - top: 5.0, - bottom: 0, - left: 30, - right: 30), - child: SizedBox( - width: screenwidth / 1, - child: ElevatedButton( - onPressed: () { - context.pop(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFFB68A34), // Blueish color for Login - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), - ), - padding: EdgeInsets.symmetric( - vertical: 16.5), + if (!cameFromLinking) ...[ + SizedBox(height: 20), + Text( + AppLocalizations.of(context)! + .account_confirmation, + style: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of( - context)! - .login_title, - style: TextStyle( - fontFamily: - context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: registerLocale - ?.languageCode == - 'ar' - ? 14 - : 16, - color: Colors.white), + fontWeight: FontWeight.w500, + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 12 + : 14, + color: isDarkTheme + ? Color(0xFFFFFFFF) + : Color(0xFF898C81), + ), + ), + SizedBox(height: 5), + Padding( + padding: const EdgeInsets.only( + top: 5.0, + bottom: 0, + left: 30, + right: 30), + child: SizedBox( + width: screenwidth / 1, + child: ElevatedButton( + onPressed: () { + context.pop(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color( + 0xFFB68A34), // Blueish color for Login + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular( + 10), ), - SizedBox(width: 8), - Icon( - Icons - .chevron_right_outlined, - color: Colors - .white, // Set your desired color here - ) - ], + padding: EdgeInsets.symmetric( + vertical: 16.5), + ), + child: Row( + mainAxisSize: + MainAxisSize.min, + children: [ + Text( + AppLocalizations.of( + context)! + .login_title, + style: TextStyle( + fontFamily: + context.translate( + 'Roboto', + 'NotoKufi', + ), + fontSize: registerLocale + ?.languageCode == + 'ar' + ? 14 + : 16, + color: Colors.white), + ), + SizedBox(width: 8), + Icon( + Icons + .chevron_right_outlined, + color: Colors + .white, // Set your desired color here + ) + ], + ), ), ), ), - ), - // Spacer(), + // Spacer(), - SizedBox( - height: 15, - ), + SizedBox( + height: MediaQuery.of(context) + .size + .height / + 1.2, + ), + ], + + if (cameFromLinking) ...[ + SizedBox( + height: 85, + ), + ], Padding( padding: const EdgeInsets.symmetric( horizontal: 70.0), diff --git a/lib/presentation/routes/auth_routes/fcsc_profile_linking.dart b/lib/presentation/routes/auth_routes/fcsc_profile_linking.dart index 0917076d..6357c257 100644 --- a/lib/presentation/routes/auth_routes/fcsc_profile_linking.dart +++ b/lib/presentation/routes/auth_routes/fcsc_profile_linking.dart @@ -4,17 +4,17 @@ import 'package:go_router/go_router.dart'; import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/config/theme/theme_provider.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; - import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart'; - class FcscProfileLinking extends ConsumerStatefulWidget { - final Map userInfo; +class FcscProfileLinking extends ConsumerStatefulWidget { + final Map userInfo; - const FcscProfileLinking({super.key, required this.userInfo}); + const FcscProfileLinking({super.key, required this.userInfo}); - @override - ConsumerState createState() => _FcscProfileLinkingState(); - } + @override + ConsumerState createState() => _FcscProfileLinkingState(); +} class _FcscProfileLinkingState extends ConsumerState { final _formKey = GlobalKey(); @@ -103,11 +103,11 @@ class _FcscProfileLinkingState extends ConsumerState { : Color(0xFF000000), ), ), - SizedBox( - height: isTablet - ? screenHeight * 0.12 // 12% of screen for tablet - : screenHeight * 0.08, // 8% for mobile - ), + SizedBox( + height: isTablet + ? screenHeight * 0.12 // 12% of screen for tablet + : screenHeight * 0.08, // 8% for mobile + ), // Subtitle Text( @@ -124,104 +124,128 @@ class _FcscProfileLinkingState extends ConsumerState { const SizedBox(height: 32), // Buttons Row - Padding( - padding: EdgeInsets.symmetric( - horizontal: isTablet ? 80 : 24, // ✅ responsive horizontal space - ), - child:Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // YES Button - Expanded( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: - const Color(0xFFB68A34), // gold tone - padding: EdgeInsets.symmetric( - vertical: isTablet ? 18 : 14, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onPressed: () { - GoRouter.of(context).go( - '/login', - extra: { - 'fromPage': 'fcscprofilelinking', - 'userInfo': widget.userInfo, // 👈 Pass full object/map - }, // 👈 pass parameter here - ); - }, - child: Text( - "Yes *", - style: TextStyle( - fontSize: 16, color: const Color(0xFFFFFFFF)), - ), - ), - ), - const SizedBox(width: 20), - - // NO Button - Expanded( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: - const Color(0xFFB68A34), // gold tone - padding: EdgeInsets.symmetric( - vertical: isTablet ? 18 : 14, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onPressed: () { - // Handle No - }, - child: Text( - "No **", - style: - TextStyle(fontSize: 16, color: const Color(0xFFFFFFFF)), - ), - ), - ), - ], - ), - ), - const SizedBox(height: 24), Padding( padding: EdgeInsets.symmetric( - horizontal: isTablet ? 80 : 24, // ✅ responsive horizontal space + horizontal: isTablet + ? 80 + : 24, // ✅ responsive horizontal space ), child: Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text('* ', - style: TextStyle(color: Color(0xFF898C81), fontWeight: FontWeight.bold)), + // YES Button Expanded( - child: Text( - 'Your UAE PASS account will be linked to your existing FCSC profile', - style: TextStyle( - fontSize: isTablet ? 16 : 14, - fontWeight: FontWeight.w500, - color: const Color(0xFF898C81), - height: 1.5, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: + const Color(0xFFB68A34), // gold tone + padding: EdgeInsets.symmetric( + vertical: isTablet ? 18 : 14, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () { + print( + 'YESfcscprofilelinking- ${widget.userInfo}'); + GoRouter.of(context).go( + '/login', + extra: { + 'fromPage': 'fcscprofilelinking', + 'userInfo': widget + .userInfo, // 👈 Pass full object/map + }, // 👈 pass parameter here + ); + }, + child: Text( + "Yes *", + style: TextStyle( + fontSize: 16, + color: const Color(0xFFFFFFFF)), + ), + ), + ), + const SizedBox(width: 20), + + // NO Button + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: + const Color(0xFFB68A34), // gold tone + padding: EdgeInsets.symmetric( + vertical: isTablet ? 18 : 14, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () { + print( + 'NOfcscprofilelinking- ${widget.userInfo}'); + // Handle No + GoRouter.of(context).go( + '/register', + extra: { + 'fromPage': 'fcscprofilelinking', + 'userInfo': widget + .userInfo, // 👈 Pass full object/map + }, // 👈 pass parameter here + ); + }, + child: Text( + "No **", + style: TextStyle( + fontSize: 16, + color: const Color(0xFFFFFFFF)), ), ), ), ], - ) + ), ), + const SizedBox(height: 24), + Padding( + padding: EdgeInsets.symmetric( + horizontal: isTablet + ? 80 + : 24, // ✅ responsive horizontal space + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('* ', + style: TextStyle( + color: Color(0xFF898C81), + fontWeight: FontWeight.bold)), + Expanded( + child: Text( + 'Your UAE PASS account will be linked to your existing FCSC profile', + style: TextStyle( + fontSize: isTablet ? 16 : 14, + fontWeight: FontWeight.w500, + color: const Color(0xFF898C81), + height: 1.5, + ), + ), + ), + ], + )), const SizedBox(height: 15), Padding( padding: EdgeInsets.symmetric( - horizontal: isTablet ? 80 : 24, // ✅ responsive horizontal space + horizontal: isTablet + ? 80 + : 24, // ✅ responsive horizontal space ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('** ', - style: TextStyle(color: Color(0xFF898C81), fontWeight: FontWeight.bold)), + style: TextStyle( + color: Color(0xFF898C81), + fontWeight: FontWeight.bold)), Expanded( child: Text( 'Your UAE Stat Mobile App profile will be established based on the UAE PASS account', @@ -234,19 +258,21 @@ class _FcscProfileLinkingState extends ConsumerState { ), ), ], - ) - ), + )), SizedBox(height: 40), // Note section Padding( padding: EdgeInsets.symmetric( - horizontal: isTablet ? 80 : 24, // ✅ responsive horizontal space + horizontal: isTablet + ? 80 + : 24, // ✅ responsive horizontal space ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Note: ', + Text( + 'Note: ', style: TextStyle( fontSize: isTablet ? 16 : 14, fontWeight: FontWeight.w700, @@ -266,8 +292,7 @@ class _FcscProfileLinkingState extends ConsumerState { ), ), ], - ) - ), + )), const SizedBox(height: 40), @@ -281,8 +306,7 @@ class _FcscProfileLinkingState extends ConsumerState { height: 30, ), ) - ] - ) + ]) ])), ]))); } diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart index 3e3cb3b8..18ee27aa 100644 --- a/lib/presentation/routes/auth_routes/login_route.dart +++ b/lib/presentation/routes/auth_routes/login_route.dart @@ -43,7 +43,6 @@ import '../../Screens/auth_verification/registration.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:uae_stat/config/api_config.dart'; - import '../../components/indicators/locale_provider.dart'; import '../../components/my_toggle.dart'; @@ -157,10 +156,9 @@ class LoginRoute extends HookConsumerWidget { // } Future getDeviceToken( - BuildContext context, String userId, WidgetRef ref,authtoken) async { - await updateDeviceToken(userId, 'fcmToken', ref,authtoken); + BuildContext context, String userId, WidgetRef ref, authtoken) async { + await updateDeviceToken(userId, 'fcmToken', ref, authtoken); try { - // await _firebaseMessaging.requestPermission(); // print("FCM Token Entry"); // String? token = await FirebaseMessaging.instance.getToken(); @@ -179,7 +177,7 @@ class LoginRoute extends HookConsumerWidget { } if (token != null) { - await updateDeviceToken(userId, token, ref,authtoken); + await updateDeviceToken(userId, token, ref, authtoken); } } else if (Platform.isAndroid) { // Get FCM token @@ -187,7 +185,7 @@ class LoginRoute extends HookConsumerWidget { print('🔥 FCM Token (Android): $fcmToken'); if (fcmToken != null) { - await updateDeviceToken(userId, fcmToken, ref,authtoken); + await updateDeviceToken(userId, fcmToken, ref, authtoken); } } @@ -232,7 +230,7 @@ class LoginRoute extends HookConsumerWidget { } Future updateDeviceToken( - String userId, String token, WidgetRef ref,authtoken) async { + String userId, String token, WidgetRef ref, authtoken) async { print('UUID'); final url = "${pb.baseUrl}api/collections/users/records/$userId"; @@ -260,11 +258,12 @@ class LoginRoute extends HookConsumerWidget { Uri.parse(url), headers: { 'Content-Type': 'application/json', // Add this - 'Authorization': 'Bearer $authtoken', // Correct way to send auth token + 'Authorization': + 'Bearer $authtoken', // Correct way to send auth token }, body: jsonEncode({ "device_token": token, - if(cameFromLinking) "emiratesid": userInfo?['uuid'], + if (cameFromLinking) "emiratesid": userInfo?['uuid'], }), ); @@ -376,8 +375,7 @@ class LoginRoute extends HookConsumerWidget { } void openAppLinkSettings() { - const packageName = - 'ae.gov.fcsc.stats'; // Replace with your app's package + const packageName = 'ae.gov.fcsc.stats'; // Replace with your app's package final intent = AndroidIntent( action: 'android.settings.APP_OPEN_BY_DEFAULT_SETTINGS', data: 'package:$packageName', @@ -397,30 +395,56 @@ class LoginRoute extends HookConsumerWidget { Future signInWithUAEPASS() async { try { + print('signInWithUAEPASS-1'); final authData = await pb.collection('users').authWithOAuth2( - 'uaepass-stg', - (url) async { - // Launch UAE PASS page - await launchUrl(Uri.parse(url as String), mode: LaunchMode.externalApplication); + // 'uaepass-stg', + 'oidc', + // (url) async { + // // Launch UAE PASS page + // await launchUrl(Uri.parse(url as String), + // mode: LaunchMode.externalApplication); + // }, + (uri) async { + // ✅ `uri` is already a Uri instance + await launchUrl(uri, mode: LaunchMode.externalApplication); }, + scopes: ['openid', 'profile', 'email'], // redirectUrl: 'uaepassdemo://callback', ); + // final authData = await pb.collection('users').authWithOAuth2( + // 'uaepass-stg', // 'google' or 'apple' + // (providerUrl) async { + // final Uri uri = Uri.parse(providerUrl.toString()); + // + // // Inject redirect_url so PocketBase will redirect to the app when done + // final newUri = uri.replace(queryParameters: { + // ...uri.queryParameters, + // 'redirect_url': deepLinkRedirect, + // }); + // + // // Open in external browser (ensures OS handles returning to app) + // if (!await launchUrl(newUri, mode: LaunchMode.externalApplication)) { + // throw 'Could not launch OAuth URL'; + // } + // }, + // ); + print('signInWithUAEPASS-2'); print('✅ Logged in user: ${authData}'); } catch (e) { print('❌ Error: $e'); } } - Future login(BuildContext context,ref) async { + Future login(BuildContext context, ref) async { final email = profileData?.email ?? 'surendarsuri3450@gmail.com'; final uuid = profileData?.uuid ?? 'eac45287-5e1b-4251-b338-6aa7f49464a0'; await checkUserWithUhid( email: email ?? '', uuid: uuid ?? '', context: context, - userInfo:profileData, + userInfo: profileData, ); authCode = null; accessToken = null; @@ -439,7 +463,7 @@ class LoginRoute extends HookConsumerWidget { email: email ?? '', uuid: uuid ?? '', context: context, - userInfo:profileData, + userInfo: profileData, ); } catch (e) { if (kDebugMode) { @@ -468,7 +492,7 @@ class LoginRoute extends HookConsumerWidget { print('platform $platform'); final authData = await pb.collection('users').authWithOAuth2(platform, (url) async { - await launchUrl(url); + await launchUrl(url); }); // final authData = await pb.collection('users').authWithOAuth2( // platform, // 'google' or 'apple' @@ -507,7 +531,6 @@ class LoginRoute extends HookConsumerWidget { print("Email: ${isProfileComplete}"); print("Email: ${loginCount}"); - final session = await context.loaderWithErrorDialog( () => ref .read( @@ -536,11 +559,10 @@ class LoginRoute extends HookConsumerWidget { print("sessionTST - $session"); - await loginCountApi(userId!); - await updateOAuthUserDetails(userId!, metaDetails, ref,token); + await updateOAuthUserDetails(userId!, metaDetails, ref, token); // await saveUserId(userId!, loginCount); - await getDeviceToken(context, userId,ref,token); + await getDeviceToken(context, userId, ref, token); await initializeTheme(context, ref, userId); // final se = _sessionEntityFromPocketbaseRecord(authData); @@ -603,7 +625,7 @@ class LoginRoute extends HookConsumerWidget { } Future updateOAuthUserDetails( - String userId, metaDetails, WidgetRef ref,token) async { + String userId, metaDetails, WidgetRef ref, token) async { print('Update token : ${token}'); // final url = "${pb.baseUrl}api/collections/users/records/$userId"; @@ -644,7 +666,7 @@ class LoginRoute extends HookConsumerWidget { "is_oauth_login": 1, }, ); -print('User response $response'); + print('User response $response'); // final response = await http.patch( // Uri.parse(url), // headers: { @@ -749,7 +771,7 @@ print('User response $response'); // } // } - Future checkUserWithUhid({ + Future checkUserWithUhid1({ required String email, required String uuid, required BuildContext context, @@ -774,7 +796,7 @@ print('User response $response'); final data = jsonDecode(response.body); print('✅ Success: $data'); // final Map userInfoDetails = userInfo; - final Map userInfoDetails = { + final Map userInfoDetails = { "sub": "eac45287-5e1b-4251-b338-6aa7f49464a0", "fullnameAR": "سوريندر سوري", "gender": "Male", @@ -793,7 +815,7 @@ print('User response $response'); "email": "surendarsuri30@gmail.com" }; - GoRouter.of(context).go('/fcscprofilelinking',extra: userInfoDetails); + GoRouter.of(context).go('/fcscprofilelinking', extra: userInfoDetails); } else { print('❌ Error: ${response.statusCode} - ${response.body}'); } @@ -802,6 +824,17 @@ print('User response $response'); } } + Future checkUserWithUhid({ + required String email, + required String uuid, + required BuildContext context, + required userInfo, + }) async { + print('checkUserWithUhid'); + + signInWithUAEPASS(); + } + @override Widget build(BuildContext context, WidgetRef ref) { double screenHeight = MediaQuery.of(context).size.height; @@ -1197,7 +1230,8 @@ print('User response $response'); } await saveUserId(userId, loginCount); - await getDeviceToken(context, userId, ref, PocketBaseService.authStore.token); + await getDeviceToken( + context, userId, ref, PocketBaseService.authStore.token); await initializeTheme(context, ref, userId); } try { @@ -1289,9 +1323,10 @@ print('User response $response'); child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - if(cameFromLinking)...[ + if (cameFromLinking) ...[ Text( - context.translate('Link account with UAE PASS','ربط الحساب مع بطاقة الهوية الإماراتية'), + context.translate('Link account with UAE PASS', + 'ربط الحساب مع بطاقة الهوية الإماراتية'), style: TextStyle( fontFamily: context.translate( 'Roboto', @@ -1319,7 +1354,6 @@ print('User response $response'); ), ), ], - 6.horizontalSpace, Icon( Icons.chevron_right_outlined, @@ -1434,7 +1468,7 @@ print('User response $response'); child: forgotPwBtn, ), ), - if(cameFromLinking)...[ + if (cameFromLinking) ...[ 11.verticalSpace, dontHaveAnAccountRegisterBtn, ], @@ -1445,7 +1479,7 @@ print('User response $response'); ); final helloAndPleaseLoginTexts = Column( children: [ - if(cameFromLinking)...[ + if (cameFromLinking) ...[ SizedBox(height: screenHeight / 60), // Title Text( @@ -1454,9 +1488,7 @@ print('User response $response'); style: TextStyle( fontSize: isTablet ? 36 : 30, fontWeight: FontWeight.w400, - color: isDarkTheme - ? Color(0xFFFFFFFF) - : Color(0xFF000000), + color: isDarkTheme ? Color(0xFFFFFFFF) : Color(0xFF000000), ), ), SizedBox( @@ -1470,9 +1502,7 @@ print('User response $response'); textAlign: TextAlign.center, style: TextStyle( fontSize: isTablet ? 18 : 16, - color: isDarkTheme - ? Color(0xFFFFFFFF) - : Color(0xFF000000), + color: isDarkTheme ? Color(0xFFFFFFFF) : Color(0xFF000000), fontWeight: FontWeight.w400, ), ), @@ -1685,55 +1715,53 @@ print('User response $response'); ), ); final signInWithUAEPassBtn = Padding( - padding: const EdgeInsets.only( - left: 60, - right: 60), + padding: const EdgeInsets.only(left: 60, right: 60), child: SizedBox( - width: double.infinity, - child: OutlinedButton( - onPressed: () async { - // signInWithUAEPASS(); - login(context, ref); - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => const UAEPassSignInPage()), - // ); - }, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: Color(0xFF000000)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.symmetric(vertical: 16.5), - backgroundColor: Colors.white, - foregroundColor: Colors.black, - textStyle: TextStyle( - fontFamily: context.translate('Roboto', 'NotoKufi'), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - MiscIconAssetPath - .signInWithUAEPass, // replace with your Google icon asset - height: 20, - ), - const SizedBox(width: 10), - Text( - 'Sign in with UAE PASS', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF000000), - fontWeight: FontWeight.w600, + width: double.infinity, + child: OutlinedButton( + onPressed: () async { + // signInWithUAEPASS(); + login(context, ref); + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const UAEPassSignInPage()), + // ); + }, + style: OutlinedButton.styleFrom( + side: const BorderSide(color: Color(0xFF000000)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric(vertical: 16.5), + backgroundColor: Colors.white, + foregroundColor: Colors.black, + textStyle: TextStyle( + fontFamily: context.translate('Roboto', 'NotoKufi'), + fontSize: 16, + fontWeight: FontWeight.w500, ), ), - ], - ), - ), - )); + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + MiscIconAssetPath + .signInWithUAEPass, // replace with your Google icon asset + height: 20, + ), + const SizedBox(width: 10), + Text( + 'Sign in with UAE PASS', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF000000), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + )); final fcscBanner = Padding( padding: const EdgeInsets.symmetric(horizontal: 50), child: Image.asset( @@ -1783,23 +1811,24 @@ print('User response $response'); ), 20.verticalSpace, helloAndPleaseLoginTexts, - if(cameFromLinking)...[ + if (cameFromLinking) ...[ 15.verticalSpace, - ] - else...[ + ] else ...[ 40.verticalSpace, ], form, - if(cameFromLinking)...[ + if (cameFromLinking) ...[ 25.verticalSpace, Padding( padding: EdgeInsets.symmetric( - horizontal: isTablet ? 80 : 24, // ✅ responsive horizontal space + horizontal: + isTablet ? 80 : 24, // ✅ responsive horizontal space ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Note: ', + Text( + 'Note: ', style: TextStyle( fontSize: isTablet ? 16 : 14, fontWeight: FontWeight.w700, @@ -1819,10 +1848,9 @@ print('User response $response'); ), ), ], - ) - ), + )), 30.verticalSpace, - ] else...[ + ] else ...[ 25.verticalSpace, dontHaveAnAccountRegisterBtn, // continueAsGuestBtn, @@ -1859,9 +1887,10 @@ print('User response $response'); }, child: Scaffold( backgroundColor: isDarkTheme ? Color(0xFF000000) : Colors.white, - body: SafeArea(child: isInit.value - ? scaffoldBody - : const CircularProgressIndicator()), + body: SafeArea( + child: isInit.value + ? scaffoldBody + : const CircularProgressIndicator()), ), ); } diff --git a/lib/presentation/routes/auth_routes/register_route.dart b/lib/presentation/routes/auth_routes/register_route.dart index dcd7d9fa..9c5d3a76 100644 --- a/lib/presentation/routes/auth_routes/register_route.dart +++ b/lib/presentation/routes/auth_routes/register_route.dart @@ -1,365 +1,365 @@ -import 'package:external_repos/external_repos.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:the_validator/the_validator.dart'; - -import 'package:uae_stat/config/my_theme.dart'; -import 'package:uae_stat/domain/use_cases/auth_use_case.dart'; -import 'package:uae_stat/domain/use_cases/language.dart'; -import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; -import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; -import 'package:uae_stat/presentation/components/dialogs.dart'; -import 'package:uae_stat/presentation/components/lang_toggle.dart'; -import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; -import 'package:uae_stat/presentation/components/space.dart'; -import 'package:uae_stat/presentation/components/themed_text_field.dart'; - -class RegisterRoute extends HookConsumerWidget { - const RegisterRoute({super.key}); - - static final formKey = GlobalKey(); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final nameCtl = useTextEditingController(); - final emailCtl = useTextEditingController(); - final pwCtl = useTextEditingController(); - final cpwCtl = useTextEditingController(); - final registerBtn = SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () async { - final isValid = formKey.currentState!.validate(); - if (!isValid) return; - await context.loaderWithErrorDialog( - () => ref - .read( - authUseCaseProvider.notifier, - ) - .register( - name: nameCtl.text, - email: emailCtl.text, - pw: pwCtl.text, - ), - errorDialogBuilder: ( - error, [ - StackTrace? stackTrace, - ]) { - if (error == RegisterError.emailAlreadyInUse) { - return context.simpleDialog( - title: context.translate( - 'Email already exists', - 'البريد الالكتروني موجود بالفعل', - ), - content: context.translate( - 'Choose another email address or use forgot my password.', - 'اختر عنوان بريد إلكتروني آخر أو استخدم نسيت كلمة المرور الخاصة بي.', - ), - extraAction: ElevatedButton( - onPressed: () async { - Navigator.of( - context, - rootNavigator: true, - ).pop(); - await context.loaderWithErrorDialog( - () => ref - .read(authUseCaseProvider.notifier) - .requestPwReset(emailCtl.text), - ); - if (!context.mounted) return; - context.simpleDialog( - title: 'Success', - content: - 'An email has been sent to ${emailCtl.text} with further details.', - ); - }, - child: Text( - context.translate( - 'Reset Password for ${emailCtl.text}', - 'إعادة تعيين كلمة المرور ل ${emailCtl.text}', - ), - ), - ), - ); - } - return context.simpleDialog( - error: error, - stackTrace: stackTrace, - ); - }, - ); - if (!context.mounted) return; - await context.simpleDialog( - title: context.translate( - 'Registration succeeded', - 'نجح التسجيل', - ), - content: context.translate( - 'Check your inbox for an email verification link before logging in.', - 'تحقق من صندوق الوارد الخاص بك للحصول على رابط التحقق من البريد الإلكتروني قبل تسجيل الدخول.', - ), - ); - if (!context.mounted) return; - context.go('/${context.language}/login'); - }, - style: ButtonStyle( - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.symmetric(vertical: 10.5), - ), - textStyle: WidgetStatePropertyAll( - TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - backgroundColor: WidgetStatePropertyAll( - MyTheme.topicColor(IndicatorTopic.social), - ), - foregroundColor: const WidgetStatePropertyAll( - Colors.white, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - context.translate( - 'Register', - 'يسجل', - ), - ), - 6.horizontalSpace, - const Icon(Icons.chevron_right_outlined), - ], - ), - ), - ); - final pwField = ThemedFormField( - validator: (text) { - if (text!.length < 10) { - return 'The password must be at least 10 characters'; - } - return FieldValidator.password(minLength: 10)(text); - }, - hintText: context.translate( - 'Password', - 'كلمة المرور', - ), - imgPath: MiscIconAssetPath.personLight, - controller: pwCtl, - isObscurable: true, - ); - final cpwField = ThemedFormField( - validator: (text) => - text != pwCtl.text ? 'The passwords do not match' : null, - hintText: context.translate( - 'Confirm Password', - 'كلمة المرور', - ), - imgPath: MiscIconAssetPath.personLight, - controller: cpwCtl, - isObscurable: true, - ); - final emailField = ThemedFormField( - hintText: context.translate( - 'Email', - 'اسم المستخدم', - ), - validator: FieldValidator.email(), - imgPath: MiscIconAssetPath.personLight, - controller: emailCtl, - ); - final nameField = ThemedFormField( - hintText: context.translate( - 'Name', - 'اسم', - ), - validator: (value) => - value!.isEmpty ? 'Name must be at least one character' : null, - imgPath: MiscIconAssetPath.personLight, - controller: nameCtl, - ); - final form = Form( - key: formKey, - child: Column( - children: [ - nameField, - 15.verticalSpace, - emailField, - 15.verticalSpace, - pwField, - 15.verticalSpace, - cpwField, - 10.verticalSpace, - registerBtn, - ], - ), - ); - final helloAndPleaseLoginTexts = Column( - children: [ - Text( - context.translate( - 'Welcome to UAE Stats!', - 'مرحبا بكم في إحصائيات دولة الإمارات العربية المتحدة!', - ), - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: 40, - fontWeight: FontWeight.w300, - ), - ), - 10.verticalSpace, - Text( - context.translate( - 'Register as a new user', - 'سجل كمستخدم جديد', - ), - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: 18, - color: const Color(0xff898C81), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - final alreadyHaveAnAccountLoginBtn = TextButton( - onPressed: () => context.go('/${context.language}/login'), - child: Text.rich( - textAlign: TextAlign.center, - TextSpan( - style: TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: 18, - fontWeight: FontWeight.bold, - ), - children: [ - TextSpan( - text: context.translate( - 'Already have an account?', - 'هل لديك حساب؟', - ), - style: const TextStyle( - color: Color(0xff898C81), - ), - ), - const TextSpan( - text: ' ', - ), - TextSpan( - text: context.translate( - 'Login', - 'تسجيل الدخول', - ), - style: TextStyle( - color: MyTheme.topicColor(IndicatorTopic.economy).shade600, - ), - ), - ], - ), - ), - ); - final continueAsGuestBtn = SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () => context - .go('/${context.language}/${BottomNavBarItem.home.routePath}'), - style: ButtonStyle( - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - padding: const WidgetStatePropertyAll( - EdgeInsets.symmetric(vertical: 10.5), - ), - textStyle: WidgetStatePropertyAll( - TextStyle( - fontFamily: context.translate( - 'Roboto', - 'NotoKufi', - ), - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - backgroundColor: WidgetStatePropertyAll( - MyTheme.topicColor(IndicatorTopic.environment), - ), - foregroundColor: const WidgetStatePropertyAll( - Colors.white, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - context.translate( - 'Continue as Guest', - 'استمر كضيف', - ), - ), - 6.horizontalSpace, - const Icon(Icons.chevron_right_outlined), - ], - ), - ), - ); - final fcscBanner = Image.asset( - BannerAssetPath.fcscLogoLight, - height: 56, - ); - final screenWidth = MediaQuery.of(context).size.width; - final listViewHorizontalPadding = - screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2; - final scaffoldBody = ListView( - padding: EdgeInsets.symmetric( - horizontal: listViewHorizontalPadding.toDouble(), - ), - children: [ - 36.verticalSpace, - const Align( - alignment: AlignmentDirectional.topEnd, - child: LangToggle(), - ), - 16.verticalSpace, - helloAndPleaseLoginTexts, - 42.verticalSpace, - form, - 20.verticalSpace, - alreadyHaveAnAccountLoginBtn, - 36.verticalSpace, - continueAsGuestBtn, - 72.verticalSpace, - fcscBanner, - ], - ); - final bgScaffold = Scaffold( - backgroundColor: Colors.white, - body: SafeArea(child: scaffoldBody), - ); - return bgScaffold; - } -} +// import 'package:external_repos/external_repos.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_hooks/flutter_hooks.dart'; +// import 'package:go_router/go_router.dart'; +// import 'package:hooks_riverpod/hooks_riverpod.dart'; +// import 'package:the_validator/the_validator.dart'; +// +// import 'package:uae_stat/config/my_theme.dart'; +// import 'package:uae_stat/domain/use_cases/auth_use_case.dart'; +// import 'package:uae_stat/domain/use_cases/language.dart'; +// import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; +// import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; +// import 'package:uae_stat/presentation/components/dialogs.dart'; +// import 'package:uae_stat/presentation/components/lang_toggle.dart'; +// import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; +// import 'package:uae_stat/presentation/components/space.dart'; +// import 'package:uae_stat/presentation/components/themed_text_field.dart'; +// +// class RegisterRoute extends HookConsumerWidget { +// const RegisterRoute({super.key}); +// +// static final formKey = GlobalKey(); +// +// @override +// Widget build(BuildContext context, WidgetRef ref) { +// final nameCtl = useTextEditingController(); +// final emailCtl = useTextEditingController(); +// final pwCtl = useTextEditingController(); +// final cpwCtl = useTextEditingController(); +// final registerBtn = SizedBox( +// width: double.infinity, +// child: ElevatedButton( +// onPressed: () async { +// final isValid = formKey.currentState!.validate(); +// if (!isValid) return; +// await context.loaderWithErrorDialog( +// () => ref +// .read( +// authUseCaseProvider.notifier, +// ) +// .register( +// name: nameCtl.text, +// email: emailCtl.text, +// pw: pwCtl.text, +// ), +// errorDialogBuilder: ( +// error, [ +// StackTrace? stackTrace, +// ]) { +// if (error == RegisterError.emailAlreadyInUse) { +// return context.simpleDialog( +// title: context.translate( +// 'Email already exists', +// 'البريد الالكتروني موجود بالفعل', +// ), +// content: context.translate( +// 'Choose another email address or use forgot my password.', +// 'اختر عنوان بريد إلكتروني آخر أو استخدم نسيت كلمة المرور الخاصة بي.', +// ), +// extraAction: ElevatedButton( +// onPressed: () async { +// Navigator.of( +// context, +// rootNavigator: true, +// ).pop(); +// await context.loaderWithErrorDialog( +// () => ref +// .read(authUseCaseProvider.notifier) +// .requestPwReset(emailCtl.text), +// ); +// if (!context.mounted) return; +// context.simpleDialog( +// title: 'Success', +// content: +// 'An email has been sent to ${emailCtl.text} with further details.', +// ); +// }, +// child: Text( +// context.translate( +// 'Reset Password for ${emailCtl.text}', +// 'إعادة تعيين كلمة المرور ل ${emailCtl.text}', +// ), +// ), +// ), +// ); +// } +// return context.simpleDialog( +// error: error, +// stackTrace: stackTrace, +// ); +// }, +// ); +// if (!context.mounted) return; +// await context.simpleDialog( +// title: context.translate( +// 'Registration succeeded', +// 'نجح التسجيل', +// ), +// content: context.translate( +// 'Check your inbox for an email verification link before logging in.', +// 'تحقق من صندوق الوارد الخاص بك للحصول على رابط التحقق من البريد الإلكتروني قبل تسجيل الدخول.', +// ), +// ); +// if (!context.mounted) return; +// context.go('/${context.language}/login'); +// }, +// style: ButtonStyle( +// shape: WidgetStatePropertyAll( +// RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(10), +// ), +// ), +// padding: const WidgetStatePropertyAll( +// EdgeInsets.symmetric(vertical: 10.5), +// ), +// textStyle: WidgetStatePropertyAll( +// TextStyle( +// fontFamily: context.translate( +// 'Roboto', +// 'NotoKufi', +// ), +// fontSize: 16, +// fontWeight: FontWeight.w600, +// ), +// ), +// backgroundColor: WidgetStatePropertyAll( +// MyTheme.topicColor(IndicatorTopic.social), +// ), +// foregroundColor: const WidgetStatePropertyAll( +// Colors.white, +// ), +// ), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Text( +// context.translate( +// 'Register', +// 'يسجل', +// ), +// ), +// 6.horizontalSpace, +// const Icon(Icons.chevron_right_outlined), +// ], +// ), +// ), +// ); +// final pwField = ThemedFormField( +// validator: (text) { +// if (text!.length < 10) { +// return 'The password must be at least 10 characters'; +// } +// return FieldValidator.password(minLength: 10)(text); +// }, +// hintText: context.translate( +// 'Password', +// 'كلمة المرور', +// ), +// imgPath: MiscIconAssetPath.personLight, +// controller: pwCtl, +// isObscurable: true, +// ); +// final cpwField = ThemedFormField( +// validator: (text) => +// text != pwCtl.text ? 'The passwords do not match' : null, +// hintText: context.translate( +// 'Confirm Password', +// 'كلمة المرور', +// ), +// imgPath: MiscIconAssetPath.personLight, +// controller: cpwCtl, +// isObscurable: true, +// ); +// final emailField = ThemedFormField( +// hintText: context.translate( +// 'Email', +// 'اسم المستخدم', +// ), +// validator: FieldValidator.email(), +// imgPath: MiscIconAssetPath.personLight, +// controller: emailCtl, +// ); +// final nameField = ThemedFormField( +// hintText: context.translate( +// 'Name', +// 'اسم', +// ), +// validator: (value) => +// value!.isEmpty ? 'Name must be at least one character' : null, +// imgPath: MiscIconAssetPath.personLight, +// controller: nameCtl, +// ); +// final form = Form( +// key: formKey, +// child: Column( +// children: [ +// nameField, +// 15.verticalSpace, +// emailField, +// 15.verticalSpace, +// pwField, +// 15.verticalSpace, +// cpwField, +// 10.verticalSpace, +// registerBtn, +// ], +// ), +// ); +// final helloAndPleaseLoginTexts = Column( +// children: [ +// Text( +// context.translate( +// 'Welcome to UAE Stats!', +// 'مرحبا بكم في إحصائيات دولة الإمارات العربية المتحدة!', +// ), +// textAlign: TextAlign.center, +// style: TextStyle( +// fontFamily: context.translate( +// 'Roboto', +// 'NotoKufi', +// ), +// fontSize: 40, +// fontWeight: FontWeight.w300, +// ), +// ), +// 10.verticalSpace, +// Text( +// context.translate( +// 'Register as a new user', +// 'سجل كمستخدم جديد', +// ), +// textAlign: TextAlign.center, +// style: TextStyle( +// fontFamily: context.translate( +// 'Roboto', +// 'NotoKufi', +// ), +// fontSize: 18, +// color: const Color(0xff898C81), +// fontWeight: FontWeight.bold, +// ), +// ), +// ], +// ); +// final alreadyHaveAnAccountLoginBtn = TextButton( +// onPressed: () => context.go('/${context.language}/login'), +// child: Text.rich( +// textAlign: TextAlign.center, +// TextSpan( +// style: TextStyle( +// fontFamily: context.translate( +// 'Roboto', +// 'NotoKufi', +// ), +// fontSize: 18, +// fontWeight: FontWeight.bold, +// ), +// children: [ +// TextSpan( +// text: context.translate( +// 'Already have an account?', +// 'هل لديك حساب؟', +// ), +// style: const TextStyle( +// color: Color(0xff898C81), +// ), +// ), +// const TextSpan( +// text: ' ', +// ), +// TextSpan( +// text: context.translate( +// 'Login', +// 'تسجيل الدخول', +// ), +// style: TextStyle( +// color: MyTheme.topicColor(IndicatorTopic.economy).shade600, +// ), +// ), +// ], +// ), +// ), +// ); +// final continueAsGuestBtn = SizedBox( +// width: double.infinity, +// child: ElevatedButton( +// onPressed: () => context +// .go('/${context.language}/${BottomNavBarItem.home.routePath}'), +// style: ButtonStyle( +// shape: WidgetStatePropertyAll( +// RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(10), +// ), +// ), +// padding: const WidgetStatePropertyAll( +// EdgeInsets.symmetric(vertical: 10.5), +// ), +// textStyle: WidgetStatePropertyAll( +// TextStyle( +// fontFamily: context.translate( +// 'Roboto', +// 'NotoKufi', +// ), +// fontSize: 16, +// fontWeight: FontWeight.w600, +// ), +// ), +// backgroundColor: WidgetStatePropertyAll( +// MyTheme.topicColor(IndicatorTopic.environment), +// ), +// foregroundColor: const WidgetStatePropertyAll( +// Colors.white, +// ), +// ), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Text( +// context.translate( +// 'Continue as Guest', +// 'استمر كضيف', +// ), +// ), +// 6.horizontalSpace, +// const Icon(Icons.chevron_right_outlined), +// ], +// ), +// ), +// ); +// final fcscBanner = Image.asset( +// BannerAssetPath.fcscLogoLight, +// height: 56, +// ); +// final screenWidth = MediaQuery.of(context).size.width; +// final listViewHorizontalPadding = +// screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2; +// final scaffoldBody = ListView( +// padding: EdgeInsets.symmetric( +// horizontal: listViewHorizontalPadding.toDouble(), +// ), +// children: [ +// 36.verticalSpace, +// const Align( +// alignment: AlignmentDirectional.topEnd, +// child: LangToggle(), +// ), +// 16.verticalSpace, +// helloAndPleaseLoginTexts, +// 42.verticalSpace, +// form, +// 20.verticalSpace, +// alreadyHaveAnAccountLoginBtn, +// 36.verticalSpace, +// continueAsGuestBtn, +// 72.verticalSpace, +// fcscBanner, +// ], +// ); +// final bgScaffold = Scaffold( +// backgroundColor: Colors.white, +// body: SafeArea(child: scaffoldBody), +// ); +// return bgScaffold; +// } +// } diff --git a/pubspec.lock b/pubspec.lock index 4fa21de1..f69ef45a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -401,14 +401,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.11" - desktop_webview_window: - dependency: transitive - description: - name: desktop_webview_window - sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0" - url: "https://pub.dev" - source: hosted - version: "0.2.3" device_info_plus: dependency: "direct main" description: @@ -759,22 +751,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - flutter_web_auth_2: - dependency: "direct main" - description: - name: flutter_web_auth_2 - sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696" - url: "https://pub.dev" - source: hosted - version: "4.1.0" - flutter_web_auth_2_platform_interface: - dependency: transitive - description: - name: flutter_web_auth_2_platform_interface - sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d - url: "https://pub.dev" - source: hosted - version: "4.1.0" flutter_web_plugins: dependency: transitive description: flutter @@ -1104,26 +1080,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.10" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.1" lints: dependency: transitive description: @@ -1635,10 +1611,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.4" the_validator: dependency: "direct main" description: @@ -1779,10 +1755,10 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.4" video_player: dependency: "direct main" description: @@ -1872,13 +1848,13 @@ packages: source: hosted version: "4.13.0" webview_flutter_android: - dependency: "direct main" + dependency: transitive description: name: webview_flutter_android - sha256: e5201c620eb2637dca88a756961fae4a7191bb30b4f2271e08b746405ffdf3fd + sha256: "9a25f6b4313978ba1c2cda03a242eea17848174912cfb4d2d8ee84a556f248e3" url: "https://pub.dev" source: hosted - version: "4.10.5" + version: "4.10.1" webview_flutter_platform_interface: dependency: transitive description: @@ -1888,13 +1864,13 @@ packages: source: hosted version: "2.14.0" webview_flutter_wkwebview: - dependency: "direct main" + dependency: transitive description: name: webview_flutter_wkwebview - sha256: fea63576b3b7e02b2df8b78ba92b48ed66caec2bb041e9a0b1cbd586d5d80bfd + sha256: fb46db8216131a3e55bcf44040ca808423539bc6732e7ed34fb6d8044e3d512f url: "https://pub.dev" source: hosted - version: "3.23.1" + version: "3.23.0" win32: dependency: transitive description: @@ -1911,14 +1887,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" - window_to_front: - dependency: transitive - description: - name: window_to_front - sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee" - url: "https://pub.dev" - source: hosted - version: "0.0.3" xdg_directories: dependency: transitive description: @@ -1944,5 +1912,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.9.0 <4.0.0" - flutter: ">=3.35.0" + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.29.0"