user guide

This commit is contained in:
Kalonkarthik 2024-12-19 15:07:59 +05:30
commit 73f1e2e62e
14 changed files with 477 additions and 351 deletions

View File

@ -294,6 +294,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../domain/use_cases/preferences_use_case.dart'; import '../domain/use_cases/preferences_use_case.dart';
@ -304,6 +305,7 @@ import '../presentation/Screens/auth_verification/otp_verification.dart';
import '../presentation/Screens/profilepage.dart'; import '../presentation/Screens/profilepage.dart';
import '../presentation/routes/auth_routes/login_route.dart'; import '../presentation/routes/auth_routes/login_route.dart';
import '../presentation/routes/bottom_bar_routes/tab_routes/home_route.dart'; import '../presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import '../presentation/routes/drawer_routes/Drawer Items/edit_profile.dart';
import '../presentation/routes/drawer_routes/Drawer Items/feedback.dart'; import '../presentation/routes/drawer_routes/Drawer Items/feedback.dart';
import '../presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart'; import '../presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart';
import '../presentation/routes/drawer_routes/Drawer Items/user_guide/user_guide.dart'; import '../presentation/routes/drawer_routes/Drawer Items/user_guide/user_guide.dart';
@ -314,12 +316,16 @@ final GoRouter router = GoRouter(
GoRoute( GoRoute(
path: '/', path: '/',
//builder: (context, state) => LoginRoute(), //builder: (context, state) => LoginRoute(),
builder: (context, state) => MyHomePage(), builder: (context, state) => LoginRoute(),
), ),
GoRoute( GoRoute(
path: '/myhomepage', path: '/myhomepage',
builder: (context, state) => MyHomePage(), builder: (context, state) => MyHomePage(),
), ),
GoRoute(
path: '/register',
builder: (context, state) => RegisterScreen(),
),
GoRoute( GoRoute(
path: '/mailverification', path: '/mailverification',
builder: (context, state) => EmailVerificationScreen( builder: (context, state) => EmailVerificationScreen(
@ -331,10 +337,11 @@ final GoRouter router = GoRouter(
), ),
), ),
GoRoute( GoRoute(
path: '/changepassword', path: '/changepassword/:userId',
builder: (context, state) => Changepassword( builder: (context, state) {
userId: '', final userId = state.pathParameters['userId']!;
), return Changepassword(userId: userId);
},
), ),
GoRoute( GoRoute(
path: '/createNewPw/:userId/:email', path: '/createNewPw/:userId/:email',
@ -359,10 +366,11 @@ final GoRouter router = GoRouter(
), ),
//Sub route //Sub route
GoRoute( GoRoute(
path: '/profile', path: '/profile/:userId',
builder: (context, state) => ProfileScreen( builder: (context, state) {
userId: '', final userId = state.pathParameters['userId']!;
), return ProfileScreen(userId: userId);
},
), ),
GoRoute( GoRoute(
path: '/user-guide', path: '/user-guide',
@ -382,10 +390,13 @@ final GoRouter router = GoRouter(
// return ManageUserRouter(title: title); // return ManageUserRouter(title: title);
// }, // },
// ), // ),
GoRoute(
path: '/editProfile',
builder: (context, state) => EditProfile(),
),
GoRoute( GoRoute(
path: '/manageuser', path: '/manageuser',
builder: (context, state) => ManageUserRouter(), builder: (context, state) => ManageUserRouter(),
), ),
], ],
); );

View File

@ -58,7 +58,7 @@ class _ResetPasswordScreenState extends State<Changepassword> {
//print('userDetails ->: $userData'); //print('userDetails ->: $userData');
if (userData['items'].isNotEmpty) { if (userData['items'].isNotEmpty) {
// Email exists; retrieve user ID // Email exists; retrieve user ID
final userId = userData['items'][0]['id']; // final userId = userData['items'][0]['id'];
// Proceed with OTP request // Proceed with OTP request
final otpResponse = await http.post( final otpResponse = await http.post(
@ -87,17 +87,15 @@ class _ResetPasswordScreenState extends State<Changepassword> {
); );
// Navigate to the Email Verification screen // Navigate to the Email Verification screen
Navigator.push( context.go(
context, '/mailverification',
MaterialPageRoute( extra: {
builder: (context) => EmailVerificationScreen( 'email': email,
email: email, 'userId': widget.userId, // Pass user ID to the next screen
userId: widget.userId, // Pass user ID to the next screen 'otp': otp,
otp: otp, 'otpId': otpId,
otpId: otpId, 'sendVerificationCode': sendVerificationCode,
sendVerificationCode: sendVerificationCode, },
),
),
); );
} else { } else {
final error = final error =
@ -132,6 +130,12 @@ class _ResetPasswordScreenState extends State<Changepassword> {
} }
} }
@override
void initState() {
super.initState();
print(widget.userId);
}
@override @override
void dispose() { void dispose() {
_emailController.dispose(); _emailController.dispose();

View File

@ -156,8 +156,8 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscurePassword _obscurePassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {
@ -184,8 +184,8 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureConfirmPassword _obscureConfirmPassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {

View File

@ -38,13 +38,50 @@ class _CreateNewPwState extends State<CreateNewPw> {
} }
String? _validateNewPassword(String? value) { String? _validateNewPassword(String? value) {
// Define the regular expression for allowed characters
final regex = RegExp(
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
// Define regular expressions for password complexity requirements
final hasUppercase = RegExp(r'[A-Z]');
final hasLowercase = RegExp(r'[a-z]');
final hasDigit = RegExp(r'\d');
final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]');
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'New password is required'; return 'New password is required';
} else if (value.length < 6) { } else if (value.length < 8 || value.length > 64) {
return 'Password must be at least 6 characters'; return 'Password must be between 8 and 64 characters';
} else if (value == _oldPassword) { } else if (value == _oldPassword) {
return 'New password must not be the same as the old password'; return 'New password must not be the same as the old password';
} }
// Check the regular expression for allowed characters
if (!regex.hasMatch(value)) {
return 'Password contains invalid characters';
}
// Track missing constraints
List<String> missingConstraints = [];
if (!hasUppercase.hasMatch(value)) {
missingConstraints.add('uppercase letter');
}
if (!hasLowercase.hasMatch(value)) {
missingConstraints.add('lowercase letter');
}
if (!hasDigit.hasMatch(value)) {
missingConstraints.add('numeric digit');
}
if (!hasSpecialCharacter.hasMatch(value)) {
missingConstraints.add('special character');
}
// If there are missing constraints, return a consolidated message
if (missingConstraints.isNotEmpty) {
return 'At least one ${missingConstraints.join(', ')}';
}
_newPassword = value; // Store for validation _newPassword = value; // Store for validation
return null; return null;
} }
@ -184,8 +221,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureOldPassword _obscureOldPassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {
@ -208,8 +245,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureNewPassword _obscureNewPassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {
@ -231,8 +268,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureConfirmPassword _obscureConfirmPassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {

View File

@ -6,6 +6,7 @@ import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart';
import '../../../infrastructure/services/pocketbase_service.dart';
import '../../routes/auth_routes/login_route.dart'; import '../../routes/auth_routes/login_route.dart';
class RegisterScreen extends StatefulWidget { class RegisterScreen extends StatefulWidget {
@ -135,27 +136,77 @@ class _RegisterScreenState extends State<RegisterScreen> {
return null; return null;
} }
// String? _validatePassword(String? value) {
// // Define the regular expression for allowed characters
// final regex = RegExp(
// r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
//
// if (value == null || value.isEmpty) {
// return 'Required';
// } else if (value.length < 8) {
// return 'Password must be at least 8characters';
// }
//
// // Check the length constraint
// if (value.length < 8 || value.length > 40) {
// return 'Password must be between 8 and 64 characters';
// }
//
// // Check the regular expression
// if (!regex.hasMatch(value)) {
// return 'Password contains invalid characters';
// }
//
// _password = value; // Store the password for confirm password validation
// return null;
// }
String? _validatePassword(String? value) { String? _validatePassword(String? value) {
// Define the regular expression for allowed characters // Define the regular expression for allowed characters
final regex = RegExp( final regex = RegExp(
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$'); r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
// Define regular expressions for password complexity requirements
final hasUppercase = RegExp(r'[A-Z]');
final hasLowercase = RegExp(r'[a-z]');
final hasDigit = RegExp(r'\d');
final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]');
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return 'Required';
} else if (value.length < 8) {
return 'Password must be at least 8characters';
} }
// Check the length constraint // Check the length constraint
if (value.length < 8 || value.length > 40) { if (value.length < 8 || value.length > 64) {
return 'Password must be between 8 and 64 characters'; return 'Password must be between 8 and 64 characters';
} }
// Check the regular expression // Check the regular expression for allowed characters
if (!regex.hasMatch(value)) { if (!regex.hasMatch(value)) {
return 'Password contains invalid characters'; return 'Password contains invalid characters';
} }
// Track missing constraints
List<String> missingConstraints = [];
if (!hasUppercase.hasMatch(value)) {
missingConstraints.add('uppercase letter');
}
if (!hasLowercase.hasMatch(value)) {
missingConstraints.add('lowercase letter');
}
if (!hasDigit.hasMatch(value)) {
missingConstraints.add('numeric digit');
}
if (!hasSpecialCharacter.hasMatch(value)) {
missingConstraints.add('special character');
}
// If there are missing constraints, return a consolidated message
if (missingConstraints.isNotEmpty) {
return 'At least one ${missingConstraints.join(', ')}';
}
_password = value; // Store the password for confirm password validation _password = value; // Store the password for confirm password validation
return null; return null;
} }
@ -182,6 +233,30 @@ class _RegisterScreenState extends State<RegisterScreen> {
if (_formKey.currentState?.validate() ?? false) { if (_formKey.currentState?.validate() ?? false) {
if (isChecked) { if (isChecked) {
try { try {
final existingUsers = await pb.collection('users').getList(
filter: 'email="${_emailController.text}"',
);
if (existingUsers.items.isNotEmpty) {
// Email already exists
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Email Exists'),
content: Text(
'Email ID already exists. Please use a different email.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('OK'),
),
],
);
},
);
return; // Stop registration process
}
final adminAuth = await pb.admins final adminAuth = await pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
@ -194,6 +269,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
'password': _passwordController.text, 'password': _passwordController.text,
'passwordConfirm': _passwordController.text, 'passwordConfirm': _passwordController.text,
'status': 'Pending', 'status': 'Pending',
'role': 'user',
}, headers: { }, headers: {
'Authorization': adminToken 'Authorization': adminToken
}); });
@ -207,13 +283,6 @@ class _RegisterScreenState extends State<RegisterScreen> {
registrationSuccess = true; registrationSuccess = true;
registrationFailed = false; // Show success message on success registrationFailed = false; // Show success message on success
}); });
// Navigate to ProfileScreen after successful registration
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(
// builder: (context) => ProfileScreen(userId: response.id)),
// );
} else { } else {
throw Exception('User registration failed: missing user ID'); throw Exception('User registration failed: missing user ID');
} }
@ -275,7 +344,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
buildIconContainer(Icons.report, Color(0xFF7DAFBC)), buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
SizedBox(height: 20), SizedBox(height: 20),
Text( Text(
"Your registration is pending for Admin Approval.", "Your registration is pending for verification",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
@ -284,7 +353,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
"Access will be granted once your account is approved.", "Kindly verify your mail to proceed further.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
@ -293,14 +362,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
ElevatedButton( ElevatedButton(
onPressed: () => { onPressed: () {
Navigator.pushReplacement( context.go('/');
context,
MaterialPageRoute(builder: (context) => LoginRoute()
//ProfileScreen(userId: userID)
),
),
}, },
child: Text( child: Text(
'Go to Login', 'Go to Login',
@ -455,8 +518,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscurePassword _obscurePassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {
@ -487,8 +550,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureConfirmPassword _obscureConfirmPassword
? Icons.visibility ? Icons.visibility_off
: Icons.visibility_off, : Icons.visibility,
color: Colors.blue, color: Colors.blue,
), ),
onPressed: () { onPressed: () {
@ -628,12 +691,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
// Navigate to LoginRoute // Navigate to LoginRoute
Navigator.push( context.go('/');
context,
MaterialPageRoute(
builder: (context) => LoginRoute()),
// MaterialPageRoute(builder: (context) => LoginRoute(userId: userID)),
);
}, },
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@ -53,6 +53,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
final TextEditingController _emailController = TextEditingController(); final TextEditingController _emailController = TextEditingController();
// To keep track of the selected date // To keep track of the selected date
DateTime? _selectedDate; DateTime? _selectedDate;
String? role;
// Date format for the display // Date format for the display
final DateFormat _dateFormat = DateFormat('yyyy-MM-dd'); final DateFormat _dateFormat = DateFormat('yyyy-MM-dd');
@ -148,6 +149,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
setState(() { setState(() {
_usernameController.text = userDetailsResponse.data['username'] ?? ''; _usernameController.text = userDetailsResponse.data['username'] ?? '';
_emailController.text = userDetailsResponse.data['email'] ?? ''; _emailController.text = userDetailsResponse.data['email'] ?? '';
role = userDetailsResponse.data['role'] ?? '';
}); });
} catch (e) { } catch (e) {
print('Error fetching user details: $e'); print('Error fetching user details: $e');
@ -271,7 +273,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
_resetFormFields(); _resetFormFields();
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile updated successfully!"))); SnackBar(content: Text("Profile updated successfully!")));
context.go('/myhomepage'); if (role == 'admin') {
context.go('/manageuser');
} else {
context.go('/myhomepage');
}
} catch (error) { } catch (error) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to update profile: $error"))); SnackBar(content: Text("Failed to update profile: $error")));
@ -306,7 +312,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
leading: IconButton( leading: IconButton(
icon: Icon(Icons.arrow_back_ios_new, color: Colors.black), icon: Icon(Icons.arrow_back_ios_new, color: Colors.black),
onPressed: () { onPressed: () {
context.go('/myhomepage'); context.go('/');
}, },
), ),
title: Text( title: Text(
@ -315,7 +321,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () {}, onPressed: () {
context.go('/');
},
child: Text( child: Text(
'Logout', 'Logout',
style: TextStyle(color: Colors.orange), style: TextStyle(color: Colors.orange),
@ -425,8 +433,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
} }
//RegExp(r"^[a-zA-Z\s]+$"); //RegExp(r"^[a-zA-Z\s]+$");
final nameRegex = final nameRegex = RegExp(
RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$"); r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
if (!nameRegex.hasMatch(value)) { if (!nameRegex.hasMatch(value)) {
return 'Invalid Characters'; return 'Invalid Characters';
} }
@ -698,7 +707,7 @@ class ConfirmationDialog extends StatelessWidget {
), ),
children: [ children: [
TextSpan( TextSpan(
text: "name", text: "Name",
style: style:
TextStyle(fontWeight: FontWeight.w700), // Bold for "name" TextStyle(fontWeight: FontWeight.w700), // Bold for "name"
), ),
@ -706,7 +715,7 @@ class ConfirmationDialog extends StatelessWidget {
text: " or ", text: " or ",
), ),
TextSpan( TextSpan(
text: "date of birth", text: "Date of birth",
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w700), // Bold for "date of birth" fontWeight: FontWeight.w700), // Bold for "date of birth"
), ),

View File

@ -1,4 +1,3 @@
import 'package:external_repos/external_repos.dart'; import 'package:external_repos/external_repos.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
@ -38,8 +37,8 @@ class ThemedFormField extends HookWidget {
onPressed: () => isObscured.value = !isObscured.value, onPressed: () => isObscured.value = !isObscured.value,
icon: Icon( icon: Icon(
isObscured.value isObscured.value
? Icons.visibility_outlined ? Icons.visibility_off_outlined
: Icons.visibility_off_outlined, : Icons.visibility_outlined,
color: const Color(0xff9EA2A9), color: const Color(0xff9EA2A9),
), ),
); );

View File

@ -740,206 +740,206 @@ class _LoginRouteState extends State<LoginRoute> {
), ),
), ),
); );
// <<<<<<< HEAD <<<<<<< HEAD
// ======= =======
// final form = Form( final form = Form(
// key: formKey, key: formKey,
// child: Column( child: Column(
// children: [ children: [
// ThemedFormField( ThemedFormField(
// hintText: context.translate( hintText: context.translate(
// 'Email', 'Email',
// 'بريد إلكتروني', 'بريد إلكتروني',
// ), ),
// validator: FieldValidator.email(), validator: FieldValidator.email(),
// imgPath: MiscIconAssetPath.person, imgPath: MiscIconAssetPath.person,
// controller: emailCtl, controller: emailCtl,
// ), ),
// 15.verticalSpace, 15.verticalSpace,
// ThemedFormField( ThemedFormField(
// validator: (text) { validator: (text) {
// if (text!.length < 8) { if (text!.length < 8) {
// return 'The password must be at least 8 characters'; return 'The password must be at least 8 characters';
// } }
// return FieldValidator.password(minLength: 8)(text); return FieldValidator.password(minLength: 8)(text);
// }, },
// hintText: context.translate( hintText: context.translate(
// 'Password', 'Password',
// 'كلمة المرور', 'كلمة المرور',
// ), ),
// imgPath: MiscIconAssetPath.lock, imgPath: MiscIconAssetPath.lock,
// controller: pwCtl, controller: pwCtl,
// isObscurable: true, isObscurable: true,
// ), ),
// // 6.verticalSpace, // 6.verticalSpace,
// Align( Align(
// alignment: AlignmentDirectional.topEnd, alignment: AlignmentDirectional.topEnd,
// child: forgotPwBtn, child: forgotPwBtn,
// ), ),
// 10.verticalSpace, 10.verticalSpace,
// loginBtn, loginBtn,
// ], ],
// ), ),
// ); );
// final helloAndPleaseLoginTexts = Column( final helloAndPleaseLoginTexts = Column(
// children: [ children: [
// Text( Text(
// context.translate( context.translate(
// 'Hello Again!', 'Hello Again!',
// 'مرحبا مجددا!', 'مرحبا مجددا!',
// ), ),
// style: TextStyle( style: TextStyle(
// fontFamily: context.translate( fontFamily: context.translate(
// 'Roboto', 'Roboto',
// 'NotoKufi', 'NotoKufi',
// ), ),
// fontSize: 40, fontSize: 40,
// fontWeight: FontWeight.w300, fontWeight: FontWeight.w300,
// ), ),
// ), ),
// 10.verticalSpace, 10.verticalSpace,
// Text( Text(
// context.translate( context.translate(
// 'Please login to access UAEs key official statistics', 'Please login to access UAEs key official statistics',
// 'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة', 'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة',
// ), ),
// textAlign: TextAlign.center, textAlign: TextAlign.center,
// style: TextStyle( style: TextStyle(
// fontFamily: context.translate( fontFamily: context.translate(
// 'Roboto', 'Roboto',
// 'NotoKufi', 'NotoKufi',
// ), ),
// fontSize: 18, fontSize: 18,
// color: const Color(0xff898C81), color: const Color(0xff898C81),
// fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
// ), ),
// ), ),
// ], ],
// ); );
// final dontHaveAnAccountRegisterBtn = TextButton( final dontHaveAnAccountRegisterBtn = TextButton(
// onPressed: () => { onPressed: () => {
// Navigator.push( Navigator.push(
// context, context,
// MaterialPageRoute(builder: (context) => RegisterScreen()), MaterialPageRoute(builder: (context) => RegisterScreen()),
// ), ),
// }, },
// child: Text.rich( child: Text.rich(
// textAlign: TextAlign.center, textAlign: TextAlign.center,
// TextSpan( TextSpan(
// style: TextStyle( style: TextStyle(
// fontFamily: context.translate( fontFamily: context.translate(
// 'Roboto', 'Roboto',
// 'NotoKufi', 'NotoKufi',
// ), ),
// fontSize: 18, fontSize: 18,
// fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
// ), ),
// children: [ children: [
// TextSpan( TextSpan(
// text: context.translate( text: context.translate(
// 'Don\'t have an account? ', 'Don\'t have an account? ',
// 'ليس لديك حساب؟', 'ليس لديك حساب؟',
// ), ),
// style: const TextStyle( style: const TextStyle(
// color: Color(0xff898C81), color: Color(0xff898C81),
// ), ),
// ), ),
// const TextSpan( const TextSpan(
// text: ' ', text: ' ',
// ), ),
// TextSpan( TextSpan(
// text: context.translate( text: context.translate(
// 'Register Now', 'Register Now',
// 'سجل الان', 'سجل الان',
// ), ),
// style: TextStyle( style: TextStyle(
// color: MyTheme.topicColor(IndicatorTopic.economy).shade600, color: MyTheme.topicColor(IndicatorTopic.economy).shade600,
// ), ),
// ), ),
// ], ],
// ), ),
// ), ),
// ); );
// final continueAsGuestBtn = SizedBox( final continueAsGuestBtn = SizedBox(
// width: double.infinity, width: double.infinity,
// child: ElevatedButton( child: ElevatedButton(
// onPressed: () => context onPressed: () => context
// .go('/${context.language}/${BottomNavBarItem.home.routePath}'), .go('/${context.language}/${BottomNavBarItem.home.routePath}'),
// style: ButtonStyle( style: ButtonStyle(
// shape: WidgetStatePropertyAll( shape: WidgetStatePropertyAll(
// RoundedRectangleBorder( RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
// ), ),
// ), ),
// padding: const WidgetStatePropertyAll( padding: const WidgetStatePropertyAll(
// EdgeInsets.symmetric(vertical: 10.5), EdgeInsets.symmetric(vertical: 10.5),
// ), ),
// textStyle: WidgetStatePropertyAll( textStyle: WidgetStatePropertyAll(
// TextStyle( TextStyle(
// fontFamily: context.translate( fontFamily: context.translate(
// 'Roboto', 'Roboto',
// 'NotoKufi', 'NotoKufi',
// ), ),
// fontSize: 16, fontSize: 16,
// fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
// ), ),
// ), ),
// backgroundColor: WidgetStatePropertyAll( backgroundColor: WidgetStatePropertyAll(
// MyTheme.topicColor(IndicatorTopic.environment), MyTheme.topicColor(IndicatorTopic.environment),
// ), ),
// foregroundColor: const WidgetStatePropertyAll( foregroundColor: const WidgetStatePropertyAll(
// Colors.white, Colors.white,
// ), ),
// ), ),
// child: Row( child: Row(
// mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
// children: [ children: [
// Text( Text(
// context.translate( context.translate(
// 'Continue as Guest', 'Continue as Guest',
// 'استمر كضيف', 'استمر كضيف',
// ), ),
// ), ),
// 6.horizontalSpace, 6.horizontalSpace,
// const Icon(Icons.chevron_right_outlined), const Icon(Icons.chevron_right_outlined),
// ], ],
// ), ),
// ), ),
// ); );
// final fcscBanner = Image.asset( final fcscBanner = Image.asset(
// BannerAssetPath.fcsc, BannerAssetPath.fcsc,
// height: 56, height: 56,
// ); );
// final screenWidth = MediaQuery.of(context).size.width; final screenWidth = MediaQuery.of(context).size.width;
// final listViewHorizontalPadding = final listViewHorizontalPadding =
// screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2; screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2;
// final scaffoldBody = ListView( final scaffoldBody = ListView(
// padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
// horizontal: listViewHorizontalPadding.toDouble(), horizontal: listViewHorizontalPadding.toDouble(),
// ), ),
// children: [ children: [
// 36.verticalSpace, 36.verticalSpace,
// const Align( const Align(
// alignment: AlignmentDirectional.topEnd, alignment: AlignmentDirectional.topEnd,
// child: LangToggle(), child: LangToggle(),
// ), ),
// 16.verticalSpace, 16.verticalSpace,
// helloAndPleaseLoginTexts, helloAndPleaseLoginTexts,
// 42.verticalSpace, 42.verticalSpace,
// form, form,
// 20.verticalSpace, 20.verticalSpace,
// dontHaveAnAccountRegisterBtn, dontHaveAnAccountRegisterBtn,
// 36.verticalSpace, 36.verticalSpace,
// continueAsGuestBtn, continueAsGuestBtn,
// 72.verticalSpace, 72.verticalSpace,
// fcscBanner, fcscBanner,
// ], ],
// ); );
// final bgScaffold = Scaffold( final bgScaffold = Scaffold(
// backgroundColor: Colors.white, backgroundColor: Colors.white,
// body: SafeArea(child: scaffoldBody), body: SafeArea(child: scaffoldBody),
// ); );
// return bgScaffold; return bgScaffold;
// >>>>>>> b0c5ebce3deb7da2aa24b0ea5ffe684df7dfb7bf >>>>>>> b0c5ebce3deb7da2aa24b0ea5ffe684df7dfb7bf
} }
} }

View File

@ -262,72 +262,72 @@ class _EditProfileState extends State<EditProfile> {
} }
void showConfirmationDialog(BuildContext context) async { void showConfirmationDialog(BuildContext context) async {
final result = await showDialog<bool>( // final result = await showDialog<bool>(
context: context, // context: context,
builder: (context) => const ConfirmationDialog(), // builder: (context) => const ConfirmationDialog(),
); // );
if (result == true) { // if (result == true) {
// Validate only the country field // Validate only the country field
if (_validateDropdown(_selectedCountry) == null) { if (_validateDropdown(_selectedCountry) == null) {
try { try {
String userID = userId; String userID = userId;
print("ShowConfirmationuserID - $userID "); print("ShowConfirmationuserID - $userID ");
// Retrieve data from the country/region field // Retrieve data from the country/region field
String countryRegion = String countryRegion =
_selectedCountry ?? ''; // Ensure the country is selected _selectedCountry ?? ''; // Ensure the country is selected
// Create a multipart request // Create a multipart request
final uri = final uri =
Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID'); Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
final request = http.MultipartRequest('PATCH', uri); final request = http.MultipartRequest('PATCH', uri);
// Add fields to the request // Add fields to the request
request.fields['country_region'] = request.fields['country_region'] =
countryRegion; // Only update country here countryRegion; // Only update country here
// If profile image exists, add it // If profile image exists, add it
if (_profileImage != null) { if (_profileImage != null) {
request.files.add(await http.MultipartFile.fromPath( request.files.add(await http.MultipartFile.fromPath(
'avatar', 'avatar',
_profileImage!.path, _profileImage!.path,
)); ));
} }
// Add headers (e.g., authorization) // Add headers (e.g., authorization)
request.headers['Authorization'] = 'Bearer ${_pb.authStore.token}'; request.headers['Authorization'] = 'Bearer ${_pb.authStore.token}';
// Send the request // Send the request
final response = await request.send(); final response = await request.send();
print(response); print(response);
// Handle response // Handle response
if (response.statusCode == 200) { if (response.statusCode == 200) {
_resetFormFields(); _resetFormFields();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile updated successfully!")),
);
context.go('/myhomepage');
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("Failed to update profile: ${response.statusCode}")),
);
}
} catch (error) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to update profile: $error")), SnackBar(content: Text("Profile updated successfully!")),
);
context.go('/myhomepage');
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("Failed to update profile: ${response.statusCode}")),
); );
} }
} else { } catch (error) {
// Show an error if the country is invalid ScaffoldMessenger.of(context).showSnackBar(
setState(() { SnackBar(content: Text("Failed to update profile: $error")),
showError = true; );
});
} }
} else {
// Show an error if the country is invalid
setState(() {
showError = true;
});
} }
// }
} }
void _resetFormFields() { void _resetFormFields() {
@ -462,7 +462,7 @@ class _EditProfileState extends State<EditProfile> {
//RegExp(r"^[a-zA-Z\s]+$"); //RegExp(r"^[a-zA-Z\s]+$");
final nameRegex = RegExp( final nameRegex = RegExp(
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$"); r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
if (!nameRegex.hasMatch(value)) { if (!nameRegex.hasMatch(value)) {
return 'Invalid Characters'; return 'Invalid Characters';
} }

View File

@ -177,6 +177,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
body: { body: {
'status': newStatus, // Update status 'status': newStatus, // Update status
'verified': newStatus == 'Approved' ? true : false, 'verified': newStatus == 'Approved' ? true : false,
'reviewed': true,
}, },
); );

View File

@ -25,7 +25,7 @@ class BaseScaffold extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: AppBar(title: title, actions: [ appBar: AppBar(title: title, actions: [
IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)), IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)),
],), ]),
drawer: Drawer( drawer: Drawer(
child: ListView( child: ListView(
children: [ children: [
@ -39,19 +39,19 @@ class BaseScaffold extends StatelessWidget {
SizedBox( SizedBox(
width: mywidth / 8, width: mywidth / 8,
child: Image( child: Image(
image: AssetImage('assets/logos/fcsc.png'),),), image: AssetImage('assets/logos/fcsc.png'))),
], ],
), ),
Divider(), Divider(),
InkWell( InkWell(
onTap: () => context.go('/profile'), onTap: () => context.go('/editProfile'),
child: Row( child: Row(
children: [ children: [
SizedBox( SizedBox(
width: mywidth / 8, width: mywidth / 8,
child: Image( child: Image(
image: AssetImage( image: AssetImage(
'assets/edit_profile/profile.png',),),), 'assets/edit_profile/profile.png'))),
SizedBox( SizedBox(
width: mywidth / 20, width: mywidth / 20,
), ),
@ -59,12 +59,12 @@ class BaseScaffold extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Mohammad'), Text('Mohammad'),
Text('Mohammad@fcsc.com'), Text('Mohammad@fcsc.com')
], ],
), )
], ],
), ),
), )
], ],
), ),
), ),
@ -73,20 +73,10 @@ class BaseScaffold extends StatelessWidget {
height: myheight / 15, height: myheight / 15,
width: mywidth / 15, width: mywidth / 15,
child: Image( child: Image(
image: AssetImage('assets/icons/drawer/message.png'),),), image: AssetImage('assets/icons/drawer/message.png'))),
title: Text('Feedback'), title: Text('Feedback'),
onTap: () => context.go('/feedback'), onTap: () => context.go('/feedback'),
), ),
//user Guide
ListTile(
leading: SizedBox(
height: myheight / 15,
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/drawer/book.png'),),),
title: Text('User Guide'),
onTap: () => context.go('/user-guide'),
),
ListTile( ListTile(
leading: SizedBox( leading: SizedBox(
height: myheight / 15, height: myheight / 15,

View File

@ -27,7 +27,7 @@ class ResetPwRoute extends HookConsumerWidget {
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () => doObscureOld.value = !doObscureOld.value, onPressed: () => doObscureOld.value = !doObscureOld.value,
icon: Icon( icon: Icon(
doObscureOld.value ? Icons.visibility : Icons.visibility_off, doObscureOld.value ? Icons.visibility_off : Icons.visibility,
), ),
), ),
), ),
@ -51,7 +51,7 @@ class ResetPwRoute extends HookConsumerWidget {
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () => doObscureNew.value = !doObscureNew.value, onPressed: () => doObscureNew.value = !doObscureNew.value,
icon: Icon( icon: Icon(
doObscureNew.value ? Icons.visibility : Icons.visibility_off, doObscureNew.value ? Icons.visibility_off : Icons.visibility,
), ),
), ),
), ),
@ -72,7 +72,7 @@ class ResetPwRoute extends HookConsumerWidget {
onPressed: () => onPressed: () =>
doObscureConfirmNew.value = !doObscureConfirmNew.value, doObscureConfirmNew.value = !doObscureConfirmNew.value,
icon: Icon( icon: Icon(
doObscureConfirmNew.value ? Icons.visibility : Icons.visibility_off, doObscureConfirmNew.value ? Icons.visibility_off : Icons.visibility,
), ),
), ),
), ),

View File

@ -1244,6 +1244,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
syncfusion_flutter_charts:
dependency: "direct main"
description:
name: syncfusion_flutter_charts
sha256: b2a9f0fd585ef96c081c37697b46d48d3b0f3fe6bddc5011a3542962814fafa8
url: "https://pub.dev"
source: hosted
version: "28.1.33"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: b1071c698b502e7d55f91352a8b82d42f49f4c96e523d43b6fade5d5af710048
url: "https://pub.dev"
source: hosted
version: "28.1.33"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:

View File

@ -54,6 +54,7 @@ dependencies:
provider: ^6.1.2 provider: ^6.1.2
mailer: ^6.2.0 mailer: ^6.2.0
image_picker: ^1.1.2 image_picker: ^1.1.2
syncfusion_flutter_charts: ^28.1.33
dependency_overrides: dependency_overrides:
fading_edge_scrollview: ^4.1.1 fading_edge_scrollview: ^4.1.1