diff --git a/.run/main.dart.run.xml b/.run/main.dart.run.xml index 4767aff8..4a58a7c9 100644 --- a/.run/main.dart.run.xml +++ b/.run/main.dart.run.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index 62b87e6f..cdfe3b13 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -299,6 +299,7 @@ import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes. import '../domain/use_cases/preferences_use_case.dart'; import '../presentation/Screens/auth_verification/changepassword.dart'; import '../presentation/Screens/auth_verification/confirm_password.dart'; +import '../presentation/Screens/auth_verification/create_new_pw.dart'; import '../presentation/Screens/auth_verification/otp_verification.dart'; import '../presentation/Screens/profilepage.dart'; import '../presentation/routes/auth_routes/login_route.dart'; @@ -333,6 +334,14 @@ final GoRouter router = GoRouter( userId: '', ), ), + GoRoute( + path: '/createNewPw/:userId/:email', + builder: (context, state) { + final userId = state.pathParameters['userId']!; + final email = state.pathParameters['email']!; + return CreateNewPw(userId: userId, email: email); + }, + ), GoRoute( path: '/confirmpasswd', builder: (context, state) => ConfirmPassword( diff --git a/lib/presentation/Screens/auth_verification/create_new_pw.dart b/lib/presentation/Screens/auth_verification/create_new_pw.dart new file mode 100644 index 00000000..196b760c --- /dev/null +++ b/lib/presentation/Screens/auth_verification/create_new_pw.dart @@ -0,0 +1,387 @@ +import 'package:external_repos/external_repos.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:pocketbase/pocketbase.dart'; +import 'package:uae_stat/config/my_router.dart'; +import 'package:uae_stat/domain/use_cases/language.dart'; +import 'package:uae_stat/presentation/Screens/profilepage.dart'; +import 'package:uae_stat/presentation/components/space.dart'; + +import '../../../config/my_theme.dart'; + +class CreateNewPw extends StatefulWidget { + final String userId; + final String email; + const CreateNewPw({Key? key, required this.userId, required this.email}); + + @override + State createState() => _CreateNewPwState(); +} + +class _CreateNewPwState extends State { + final _pb = PocketBase('https://pb.venbait.in'); + final _formKey = GlobalKey(); + bool _obscureOldPassword = true; + bool _obscureNewPassword = true; + bool _obscureConfirmPassword = true; + bool _isPasswordUpdated = false; // Variable to toggle UI + + String? _oldPassword; + String? _newPassword; + String? _confirmPassword; + + String? _validateOldPassword(String? value) { + if (value == null || value.isEmpty) { + return 'Old password is required'; + } + return null; + } + + String? _validateNewPassword(String? value) { + if (value == null || value.isEmpty) { + return 'New password is required'; + } else if (value.length < 6) { + return 'Password must be at least 6 characters'; + } else if (value == _oldPassword) { + return 'New password must not be the same as the old password'; + } + _newPassword = value; // Store for validation + return null; + } + + String? _validateConfirmPassword(String? value) { + if (value == null || value.isEmpty) { + return 'Confirm password is required'; + } else if (value != _newPassword) { + return 'Passwords do not match'; + } + _confirmPassword = value; + return null; + } + + Future verifyUserPassword(String email, String password) async { + try { + // Attempt to authenticate the user with email and password + final authResponse = + await _pb.collection('users').authWithPassword(email, password); + + if (authResponse != null) { + print('Password match successful for email: $email'); + return true; // Password matches + } + } catch (e) { + // Authentication failed, password does not match + print('Error verifying password: $e'); + } + + return false; // Password does not match + } + + Future updatePassword( + String userId, String oldPassword, String newPassword) async { + try { + // Authenticate as admin + final adminAuth = await _pb.admins + .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); + final token = adminAuth.token; + + final headers = { + 'Authorization': 'Bearer $token', + }; + + bool isPasswordValid = + await verifyUserPassword(widget.email, oldPassword); + + print(isPasswordValid); + + if (isPasswordValid) { + // Update password + await _pb.collection('users').update( + userId, + body: { + 'password': newPassword, + 'passwordConfirm': newPassword, + }, + headers: headers, + ); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Password updated successfully.'), + backgroundColor: Colors.green, + ), + ); + + setState(() { + _isPasswordUpdated = true; // Toggle UI on success + }); + + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => ProfileScreen(userId: userId)), + // ); + } else { + setState(() { + _formKey.currentState?.validate(); + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Your old password is incorrect.'), + backgroundColor: Colors.red, + ), + ); + return; + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to update password: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + @override + Widget build(BuildContext context) { + double screenHeight = MediaQuery.of(context).size.height; + double screenWidth = MediaQuery.of(context).size.width; + + return Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: SafeArea( + child: _isPasswordUpdated + ? _buildSuccessContent(screenHeight, screenWidth) + : _buildPasswordForm(screenHeight, screenWidth), + ), + ), + ); + } + + Widget _buildPasswordForm(double screenHeight, double screenWidth) { + return Form( + key: _formKey, + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + children: [ + SizedBox(height: screenHeight / 6), + Text( + "Create New Password", + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: screenHeight / 35), + TextFormField( + obscureText: _obscureOldPassword, + decoration: InputDecoration( + hintText: 'Enter old password', + prefixIcon: Icon(Icons.lock, color: Colors.blue), + suffixIcon: IconButton( + icon: Icon( + _obscureOldPassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscureOldPassword = !_obscureOldPassword; + }); + }, + ), + border: OutlineInputBorder(), + ), + validator: _validateOldPassword, + onChanged: (value) => _oldPassword = value, + ), + SizedBox(height: screenHeight / 35), + TextFormField( + obscureText: _obscureNewPassword, + decoration: InputDecoration( + hintText: 'Enter new password', + prefixIcon: Icon(Icons.lock, color: Colors.blue), + suffixIcon: IconButton( + icon: Icon( + _obscureNewPassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscureNewPassword = !_obscureNewPassword; + }); + }, + ), + border: OutlineInputBorder(), + ), + validator: _validateNewPassword, + ), + SizedBox(height: screenHeight / 35), + TextFormField( + obscureText: _obscureConfirmPassword, + decoration: InputDecoration( + hintText: 'Confirm new password', + prefixIcon: Icon(Icons.lock, color: Colors.blue), + suffixIcon: IconButton( + icon: Icon( + _obscureConfirmPassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscureConfirmPassword = !_obscureConfirmPassword; + }); + }, + ), + border: OutlineInputBorder(), + ), + validator: _validateConfirmPassword, + ), + SizedBox(height: screenHeight / 35), + SizedBox( + width: screenWidth / 1.1, + child: ElevatedButton( + onPressed: () async { + if ((_formKey.currentState?.validate() ?? false)) { + await updatePassword( + widget.userId, + _oldPassword ?? '', + _newPassword ?? '', + ); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.brown[300], + padding: EdgeInsets.symmetric(horizontal: 80, vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Save", + style: TextStyle(fontSize: 18, color: Colors.white), + ), + SizedBox(width: 2), + Icon( + Icons.arrow_forward_ios, + color: Colors.white38, + size: 18, + ), + ], + ), + ), + ), + SizedBox(height: screenHeight / 5), + Center( + child: Container( + height: screenHeight / 8, + width: screenWidth / 2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/splash_screen/logo.png"), + fit: BoxFit.fill, + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildSuccessContent(double screenHeight, double screenWidth) { + return Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenHeight / 8), + Icon(Icons.check_circle_outlined, color: Color(0xFF8AC681), size: 80), + SizedBox(height: 20), + Text( + "Password Changed Successfully", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFF414042), + ), + ), + SizedBox(height: 10), + ElevatedButton( + onPressed: () async { + context.go('/'); + }, + 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), + ), + // surfaceTintColor: MaterialStatePropertyAll( + // MyTheme.economy[800], + // ), + foregroundColor: const WidgetStatePropertyAll( + Colors.white, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + context.translate( + 'Login', + 'تسجيل الدخول', + ), + ), + 6.horizontalSpace, + const Icon(Icons.chevron_right_outlined), + ], + ), + ), + SizedBox(height: screenHeight / 5), + Center( + child: Container( + height: screenHeight / 8, + width: screenWidth / 2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/splash_screen/logo.png"), + fit: BoxFit.fill, + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index 46339c76..97204028 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -207,7 +207,6 @@ class _RegisterScreenState extends State { registrationSuccess = true; registrationFailed = false; // Show success message on success }); - context.go('/profile'); // Navigate to ProfileScreen after successful registration // Navigator.pushReplacement( @@ -241,414 +240,8 @@ class _RegisterScreenState extends State { double screenheight = MediaQuery.of(context).size.height; double screenwidth = MediaQuery.of(context).size.width; - - return Scaffold( - backgroundColor: Colors.white, - body: registrationSuccess - ? registration_success(context) - : registrationFailed - ? registration_failed(context) - : Scaffold( - body: Padding( - padding: const EdgeInsets.all(20.0), - child: Form( - key: _formKey, - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 6), - Text( - 'Register', - style: TextStyle( - fontSize: 32, fontWeight: FontWeight.w400), - ), - SizedBox(height: 10), - Text('Please enter your details'), - - SizedBox(height: 20), - // Display this if registration is pending approval - TextFormField( - controller: _usernameController, - focusNode: _focusNodes[0], - decoration: InputDecoration( - hintText: _showHints[0] ? 'Username' : null, - prefixIcon: Icon( - Icons.person, - color: Colors.blue, - ), - border: OutlineInputBorder(), - counterText: '', - ), - validator: _validateUsername, - maxLength: - 40, // Set the maximum length to 20 characters - maxLengthEnforcement: MaxLengthEnforcement.enforced, - ), - SizedBox(height: 15), - TextFormField( - controller: _emailController, - focusNode: _focusNodes[1], - decoration: InputDecoration( - // hintText: 'Enter your email', - hintText: - _showHints[1] ? 'Enter your email' : null, - prefixIcon: Icon( - Icons.email, - color: Colors.blue, - ), - border: OutlineInputBorder(), - counterText: '', - ), - validator: _validateEmail, - maxLength: 320, - maxLengthEnforcement: MaxLengthEnforcement.enforced, - inputFormatters: [ - LengthLimitingTextInputFormatter( - 320), // Limit to 320 characters - ], - ), - SizedBox(height: 15), - TextFormField( - controller: _passwordController, - focusNode: _focusNodes[2], - obscureText: _obscurePassword, - decoration: InputDecoration( - hintText: - _showHints[2] ? 'Enter your password' : null, - prefixIcon: Icon( - Icons.lock, - color: Colors.blue, - ), - suffixIcon: IconButton( - icon: Icon( - _obscurePassword - ? Icons.visibility - : Icons.visibility_off, - color: Colors.blue, - ), - onPressed: () { - setState(() { - _obscurePassword = !_obscurePassword; - }); - }, - ), - border: OutlineInputBorder(), - counterText: '', - ), - validator: _validatePassword, - maxLength: 40, - maxLengthEnforcement: MaxLengthEnforcement.enforced, - ), - SizedBox(height: 15), - TextFormField( - controller: _confirmpasswordController, - focusNode: _focusNodes[3], - obscureText: _obscureConfirmPassword, - decoration: InputDecoration( - hintText: - _showHints[3] ? 'Confirm password' : null, - prefixIcon: Icon( - Icons.lock, - color: Colors.blue, - ), - suffixIcon: IconButton( - icon: Icon( - _obscureConfirmPassword - ? Icons.visibility - : Icons.visibility_off, - color: Colors.blue, - ), - onPressed: () { - setState(() { - _obscureConfirmPassword = - !_obscureConfirmPassword; - }); - }, - ), - border: OutlineInputBorder(), - counterText: '', - ), - validator: _validateConfirmPassword, - maxLength: 40, - maxLengthEnforcement: MaxLengthEnforcement.enforced, - inputFormatters: [ - LengthLimitingTextInputFormatter( - 64), // Limit to 40 characters - ], - ), - SizedBox(height: 10), - Row( - children: [ - Checkbox( - value: isChecked, - onChanged: (value) { - setState(() { - isChecked = value ?? false; - showError = false; - }); - }, - side: BorderSide( - color: showError ? Colors.red : Colors.grey, - width: 1.5, - ), - ), - Expanded( - child: Text.rich( - TextSpan( - text: 'I agree to ', - children: [ - TextSpan( - text: 'Terms & Conditions', - style: TextStyle(color: Colors.blue), - ), - TextSpan(text: ' and '), - TextSpan( - text: 'Privacy Policy', - style: TextStyle(color: Colors.blue), - ), - ], - ), - ), - ), - ], - ), - if (showError) - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 10.0), - child: Text( - 'Please agree to terms and conditions.', - style: TextStyle( - color: Colors.red[700], - fontSize: 12, - ), - ), - ), - ], - ), - SizedBox(height: 20), - SizedBox( - width: screenwidth / 1.3, - child: ElevatedButton( - onPressed: _registerUser, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFFA7887A), // Brownish color for Register - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Register", - style: TextStyle( - fontSize: 16, color: Colors.white), - ), - SizedBox(width: 8), - Icon(Icons.arrow_forward, - color: Colors.white), - ], - ), - ), - ), - SizedBox(height: 10), - Text( - "Already have an account?", - style: TextStyle( - fontSize: 16, color: Colors.grey[600]), - ), - SizedBox(height: 10), - SizedBox( - width: screenwidth / 1.3, - child: ElevatedButton( - onPressed: () { - // Add your login logic here - context.go('/login'); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Color( - 0xFF82AFCB), // Blueish color for Login - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Login", - style: TextStyle( - fontSize: 16, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.arrow_forward, - color: Colors.white), - ], - ), - ), - ), - SizedBox( - height: 10, - ), - Center( - child: Container( - height: screenheight / 8, - width: screenwidth / 2, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - "assets/splash_screen/logo.png"), // Background image asset - fit: BoxFit.fill, - ), - ), - )) - ], - ), - ), - ), - ), - ), - ); - } - - Widget registration_failed (BuildContext context) { - double screenheight = MediaQuery.of(context).size.height; - double screenwidth = MediaQuery.of(context).size.width; - return Scaffold( - body: Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 8), - buildIconContainer(Icons.report, Colors.red), - SizedBox(height: 20), - Text( - "Sorry ${_usernameController.text}!", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF414042)), - ), - SizedBox(height: 10), - Text( - "Your registration process failed. For further assistance, please contact support.", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xFF898C81), - ), - ), - SizedBox(height: 10), - ElevatedButton( - onPressed: () => { - setState(() { - registrationFailed = false; - registrationSuccess = false; - _usernameController.clear(); - _emailController.clear(); - _passwordController.clear(); - _confirmpasswordController.clear(); - isChecked = false; - }) - }, - child: Text( - 'Retry', - ), - ), - SizedBox(height: screenheight / 5), - Center( - child: Container( - height: screenheight / 8, - width: screenwidth / 2, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - "assets/splash_screen/logo.png"), // Background image asset - fit: BoxFit.fill, - ), - ), - )) - ], - ), - ), - ); - } - - Widget registration_success (BuildContext context) { - double screenheight = MediaQuery.of(context).size.height; - double screenwidth = MediaQuery.of(context).size.width; - return Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: screenheight / 8), - buildIconContainer(Icons.report, Color(0xFF7DAFBC)), - SizedBox(height: 20), - Text( - "Your registration is pending for Admin Approval.", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF414042)), - ), - SizedBox(height: 10), - Text( - "Access will be granted once your account is approved.", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xFF898C81), - ), - ), - SizedBox(height: 10), - ElevatedButton( - onPressed: () => { - context.go('/login') - // Navigator.pushReplacement( - // context, - // MaterialPageRoute(builder: (context) => LoginRoute() - // - // //ProfileScreen(userId: userID) - // ), - // ), - }, - child: Text( - 'Go to Login', - ), - ), - SizedBox(height: screenheight / 5), - Center( - child: Container( - height: screenheight / 8, - width: screenwidth / 2, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - "assets/splash_screen/logo.png"), // Background image asset - fit: BoxFit.fill, - ), - ), - )) - ], - ), - ); - } - - Widget buildIconContainer(IconData icon, Color iconColor) { - return Scaffold( - body: Container( + Widget buildIconContainer(IconData icon, Color iconColor) { + return Container( width: 60, height: 60, decoration: BoxDecoration( @@ -667,8 +260,419 @@ class _RegisterScreenState extends State { color: iconColor, size: 30, ), - ), + ); + } + + return Scaffold( + backgroundColor: Colors.white, + body: registrationSuccess + ? Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 8), + buildIconContainer(Icons.report, Color(0xFF7DAFBC)), + SizedBox(height: 20), + Text( + "Your registration is pending for Admin Approval.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFF414042)), + ), + SizedBox(height: 10), + Text( + "Access will be granted once your account is approved.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xFF898C81), + ), + ), + SizedBox(height: 10), + ElevatedButton( + onPressed: () => { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => LoginRoute() + + //ProfileScreen(userId: userID) + ), + ), + }, + child: Text( + 'Go to Login', + ), + ), + SizedBox(height: screenheight / 5), + Center( + child: Container( + height: screenheight / 8, + width: screenwidth / 2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ) + : registrationFailed + ? Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 8), + buildIconContainer(Icons.report, Colors.red), + SizedBox(height: 20), + Text( + "Sorry ${_usernameController.text}!", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFF414042)), + ), + SizedBox(height: 10), + Text( + "Your registration process failed. For further assistance, please contact support.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xFF898C81), + ), + ), + SizedBox(height: 10), + ElevatedButton( + onPressed: () => { + setState(() { + registrationFailed = false; + registrationSuccess = false; + _usernameController.clear(); + _emailController.clear(); + _passwordController.clear(); + _confirmpasswordController.clear(); + isChecked = false; + }) + }, + child: Text( + 'Retry', + ), + ), + SizedBox(height: screenheight / 5), + Center( + child: Container( + height: screenheight / 8, + width: screenwidth / 2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ) + : Padding( + padding: const EdgeInsets.all(20.0), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: screenheight / 6), + Text( + 'Register', + style: TextStyle( + fontSize: 32, fontWeight: FontWeight.w400), + ), + SizedBox(height: 10), + Text('Please enter your details'), + + SizedBox(height: 20), + // Display this if registration is pending approval + TextFormField( + controller: _usernameController, + focusNode: _focusNodes[0], + decoration: InputDecoration( + hintText: _showHints[0] ? 'Username' : null, + prefixIcon: Icon( + Icons.person, + color: Colors.blue, + ), + border: OutlineInputBorder(), + counterText: '', + ), + validator: _validateUsername, + maxLength: + 40, // Set the maximum length to 20 characters + maxLengthEnforcement: MaxLengthEnforcement.enforced, + ), + SizedBox(height: 15), + TextFormField( + controller: _emailController, + focusNode: _focusNodes[1], + decoration: InputDecoration( + // hintText: 'Enter your email', + hintText: + _showHints[1] ? 'Enter your email' : null, + prefixIcon: Icon( + Icons.email, + color: Colors.blue, + ), + border: OutlineInputBorder(), + counterText: '', + ), + validator: _validateEmail, + maxLength: 320, + maxLengthEnforcement: MaxLengthEnforcement.enforced, + inputFormatters: [ + LengthLimitingTextInputFormatter( + 320), // Limit to 320 characters + ], + ), + SizedBox(height: 15), + TextFormField( + controller: _passwordController, + focusNode: _focusNodes[2], + obscureText: _obscurePassword, + decoration: InputDecoration( + hintText: + _showHints[2] ? 'Enter your password' : null, + prefixIcon: Icon( + Icons.lock, + color: Colors.blue, + ), + suffixIcon: IconButton( + icon: Icon( + _obscurePassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscurePassword = !_obscurePassword; + }); + }, + ), + border: OutlineInputBorder(), + counterText: '', + ), + validator: _validatePassword, + maxLength: 40, + maxLengthEnforcement: MaxLengthEnforcement.enforced, + ), + SizedBox(height: 15), + TextFormField( + controller: _confirmpasswordController, + focusNode: _focusNodes[3], + obscureText: _obscureConfirmPassword, + decoration: InputDecoration( + hintText: + _showHints[3] ? 'Confirm password' : null, + prefixIcon: Icon( + Icons.lock, + color: Colors.blue, + ), + suffixIcon: IconButton( + icon: Icon( + _obscureConfirmPassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscureConfirmPassword = + !_obscureConfirmPassword; + }); + }, + ), + border: OutlineInputBorder(), + counterText: '', + ), + validator: _validateConfirmPassword, + maxLength: 40, + maxLengthEnforcement: MaxLengthEnforcement.enforced, + inputFormatters: [ + LengthLimitingTextInputFormatter( + 64), // Limit to 40 characters + ], + ), + SizedBox(height: 10), + Row( + children: [ + Checkbox( + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value ?? false; + showError = false; + }); + }, + side: BorderSide( + color: showError ? Colors.red : Colors.grey, + width: 1.5, + ), + ), + Expanded( + child: Text.rich( + TextSpan( + text: 'I agree to ', + children: [ + TextSpan( + text: 'Terms & Conditions', + style: TextStyle(color: Colors.blue), + ), + TextSpan(text: ' and '), + TextSpan( + text: 'Privacy Policy', + style: TextStyle(color: Colors.blue), + ), + ], + ), + ), + ), + ], + ), + if (showError) + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 10.0), + child: Text( + 'Please agree to terms and conditions.', + style: TextStyle( + color: Colors.red[700], + fontSize: 12, + ), + ), + ), + ], + ), + SizedBox(height: 20), + SizedBox( + width: screenwidth / 1.3, + child: ElevatedButton( + onPressed: _registerUser, + style: ElevatedButton.styleFrom( + backgroundColor: Color( + 0xFFA7887A), // Brownish color for Register + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Register", + style: TextStyle( + fontSize: 16, color: Colors.white), + ), + SizedBox(width: 8), + Icon(Icons.arrow_forward, + color: Colors.white), + ], + ), + ), + ), + SizedBox(height: 10), + Text( + "Already have an account?", + style: TextStyle( + fontSize: 16, color: Colors.grey[600]), + ), + SizedBox(height: 10), + SizedBox( + width: screenwidth / 1.3, + child: ElevatedButton( + onPressed: () { + // Add your login logic here + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color( + 0xFF82AFCB), // Blueish color for Login + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + // child: Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Login", + // style: TextStyle( + // fontSize: 16, color: Colors.white + // ), + // + // + // ), + // SizedBox(width: 8), + // Icon(Icons.arrow_forward, + // color: Colors.white), + // ], + // ), + + child: GestureDetector( + onTap: () { + // Navigate to LoginRoute + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LoginRoute()), + // MaterialPageRoute(builder: (context) => LoginRoute(userId: userID)), + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Login", + style: TextStyle( + fontSize: 16, + color: Colors.white, + ), + ), + SizedBox(width: 8), + Icon(Icons.arrow_forward, + color: Colors.white), + ], + ), + ), + ), + ), + SizedBox( + height: 10, + ), + Center( + child: Container( + height: screenheight / 8, + width: screenwidth / 2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ), + ), + ), ); } } - diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index fd2b0e34..c155b517 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -597,12 +597,10 @@ class _ProfileScreenState extends State { Center( child: GestureDetector( onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - Changepassword(userId: widget.userId)), - ); + final userId = widget.userId; + final email = _emailController.text; + + context.go('/createNewPw/$userId/$email'); }, child: Text( "Change Password", diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart index 989e799d..cbf28f0a 100644 --- a/lib/presentation/routes/auth_routes/login_route.dart +++ b/lib/presentation/routes/auth_routes/login_route.dart @@ -740,5 +740,206 @@ class _LoginRouteState extends State { ), ), ); +<<<<<<< HEAD +======= + final form = Form( + key: formKey, + child: Column( + children: [ + ThemedFormField( + hintText: context.translate( + 'Email', + 'بريد إلكتروني', + ), + validator: FieldValidator.email(), + imgPath: MiscIconAssetPath.person, + controller: emailCtl, + ), + 15.verticalSpace, + ThemedFormField( + validator: (text) { + if (text!.length < 8) { + return 'The password must be at least 8 characters'; + } + return FieldValidator.password(minLength: 8)(text); + }, + hintText: context.translate( + 'Password', + 'كلمة المرور', + ), + imgPath: MiscIconAssetPath.lock, + controller: pwCtl, + isObscurable: true, + ), + // 6.verticalSpace, + Align( + alignment: AlignmentDirectional.topEnd, + child: forgotPwBtn, + ), + 10.verticalSpace, + loginBtn, + ], + ), + ); + final helloAndPleaseLoginTexts = Column( + children: [ + Text( + context.translate( + 'Hello Again!', + 'مرحبا مجددا!', + ), + style: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + fontSize: 40, + fontWeight: FontWeight.w300, + ), + ), + 10.verticalSpace, + Text( + context.translate( + 'Please login to access UAE’s key official statistics', + 'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة', + ), + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + fontSize: 18, + color: const Color(0xff898C81), + fontWeight: FontWeight.w700, + ), + ), + ], + ); + final dontHaveAnAccountRegisterBtn = TextButton( + onPressed: () => { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => RegisterScreen()), + ), + }, + child: Text.rich( + textAlign: TextAlign.center, + TextSpan( + style: TextStyle( + fontFamily: context.translate( + 'Roboto', + 'NotoKufi', + ), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + children: [ + TextSpan( + text: context.translate( + 'Don\'t have an account? ', + 'ليس لديك حساب؟', + ), + style: const TextStyle( + color: Color(0xff898C81), + ), + ), + const TextSpan( + text: ' ', + ), + TextSpan( + text: context.translate( + 'Register Now', + 'سجل الان', + ), + 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.fcsc, + 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, + dontHaveAnAccountRegisterBtn, + 36.verticalSpace, + continueAsGuestBtn, + 72.verticalSpace, + fcscBanner, + ], + ); + final bgScaffold = Scaffold( + backgroundColor: Colors.white, + body: SafeArea(child: scaffoldBody), + ); + return bgScaffold; +>>>>>>> b0c5ebce3deb7da2aa24b0ea5ffe684df7dfb7bf } } diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index 3d74ef02..080be24f 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -135,7 +135,6 @@ class _EditProfileState extends State { Future checkUserId() async { userId = await getUserId(); - //userId = 'tplu4by67phkfoq'; if (userId != null && userId.isNotEmpty) { print('User ID: $userId'); _fetchUserData(); @@ -189,25 +188,6 @@ class _EditProfileState extends State { } else { _avatarUrl = ''; // Reset to default or empty } - - // String avatarFilename = userDetailsResponse.data['avatar'] ?? ''; - // //print("PROFILE AVAILABLE -$avatarFilename"); - // String recordId = userId; - // //String recordId = userDetailsResponse.data['id'] ?? ""; - // print("PROFILE AVAILABLE -${userDetailsResponse.data['id']}"); - // //print("User ID: $recordId"); - - //String collectionId = userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_'; - - // Ensure recordId and avatarFilename are valid - // if (avatarFilename.isNotEmpty && recordId.isNotEmpty) { - // print("PROFILE AVAILABLE"); - // String _avatarUrl = 'https://pb.venbait.in/api/files/$collectionId/$recordId/$avatarFilename'; - // print("PROFILE AVAILABLE1- $_avatarUrl"); - // //_avatarUrl = File(imageUrl); // This won't work directly for a URL, you need to download the image first - // } else { - // print("PROFILE NOT AVAILABLE"); - // } }); } catch (e) { print('Error fetching user details: $e'); @@ -672,12 +652,8 @@ class _EditProfileState extends State { Center( child: GestureDetector( onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - Changepassword(userId: userId)), - ); + final email = _emailController.text; + context.go('/createNewPw/$userId/$email'); }, child: Text( "Change Password", @@ -691,16 +667,6 @@ class _EditProfileState extends State { ElevatedButton.icon( onPressed: () { showConfirmationDialog(context); - - // if (_formKey.currentState?.validate() ?? false){ - // _formKey.currentState?.save(); - // showConfirmationDialog(context); - // } else { - // setState(() { - // showError = - // !isChecked; // Show error if the checkbox is not checked - // }); - // } }, icon: Icon( Icons.save, diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart index 7d87d47a..79c919c0 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart @@ -92,9 +92,11 @@ class _ManageUserRouterState extends State { filteredUserData.sort((a, b) { final aValue = getField(a); final bValue = getField(b); - if (aValue == null || bValue == null) { - return 0; // Handle null-safe sorting if needed - } + // Handle null values + if (aValue == null && bValue == null) return 0; + if (aValue == null) return ascending ? -1 : 1; + if (bValue == null) return ascending ? 1 : -1; + // Compare values return ascending ? Comparable.compare(aValue, bValue) : Comparable.compare(bValue, aValue); @@ -248,20 +250,24 @@ class _ManageUserRouterState extends State { columns: [ DataColumn( label: const Text('User Name'), - onSort: (columnIndex, ascending) => _sort( - (user) => user.userName, columnIndex, ascending), + onSort: (columnIndex, ascending) { + _sort((user) => user.userName.toLowerCase(), + columnIndex, ascending); + }, ), DataColumn( label: const Text('Email ID'), - onSort: (columnIndex, ascending) => _sort( - (user) => user.emailId, columnIndex, ascending), + onSort: (columnIndex, ascending) { + _sort((user) => user.emailId.toLowerCase(), + columnIndex, ascending); + }, ), DataColumn( label: const Text('Registration Date'), onSort: (columnIndex, ascending) { _sort( - (user) => DateTime.tryParse( - user.registrationDate), // Convert to DateTime + (user) => DateFormat('dd/MM/yyyy') + .parse(user.registrationDate), columnIndex, ascending, ); @@ -269,8 +275,10 @@ class _ManageUserRouterState extends State { ), DataColumn( label: const Text('Status'), - onSort: (columnIndex, ascending) => _sort( - (user) => user.status, columnIndex, ascending), + onSort: (columnIndex, ascending) { + _sort((user) => user.status.toLowerCase(), + columnIndex, ascending); + }, ), ], rows: filteredUserData.isEmpty