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 806ed3e4..f413c71d 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';
@@ -335,6 +336,14 @@ final GoRouter router = GoRouter(
return Changepassword(userId: 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 97204028..41c6d0e1 100644
--- a/lib/presentation/Screens/auth_verification/registration.dart
+++ b/lib/presentation/Screens/auth_verification/registration.dart
@@ -275,7 +275,7 @@ class _RegisterScreenState extends State {
buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
SizedBox(height: 20),
Text(
- "Your registration is pending for Admin Approval.",
+ "Your registration is pending for verification",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
@@ -284,7 +284,7 @@ class _RegisterScreenState extends State {
),
SizedBox(height: 10),
Text(
- "Access will be granted once your account is approved.",
+ "Kindly verify your mail to proceed further.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
@@ -293,14 +293,11 @@ class _RegisterScreenState extends State {
),
SizedBox(height: 10),
ElevatedButton(
- onPressed: () => {
+ onPressed: () {
Navigator.pushReplacement(
context,
- MaterialPageRoute(builder: (context) => LoginRoute()
-
- //ProfileScreen(userId: userID)
- ),
- ),
+ MaterialPageRoute(builder: (context) => LoginRoute()),
+ );
},
child: Text(
'Go to Login',
@@ -455,8 +452,8 @@ class _RegisterScreenState extends State {
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
- ? Icons.visibility
- : Icons.visibility_off,
+ ? Icons.visibility_off
+ : Icons.visibility,
color: Colors.blue,
),
onPressed: () {
@@ -487,8 +484,8 @@ class _RegisterScreenState extends State {
suffixIcon: IconButton(
icon: Icon(
_obscureConfirmPassword
- ? Icons.visibility
- : Icons.visibility_off,
+ ? Icons.visibility_off
+ : Icons.visibility,
color: Colors.blue,
),
onPressed: () {
diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart
index 76b9622b..48ce4ac6 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 a0ea8df4..5ebb61e0 100644
--- a/lib/presentation/routes/auth_routes/login_route.dart
+++ b/lib/presentation/routes/auth_routes/login_route.dart
@@ -350,10 +350,10 @@ class LoginRoute extends HookConsumerWidget {
15.verticalSpace,
ThemedFormField(
validator: (text) {
- if (text!.length < 10) {
- return 'The password must be at least 10 characters';
+ if (text!.length < 8) {
+ return 'The password must be at least 8 characters';
}
- return FieldValidator.password(minLength: 10)(text);
+ return FieldValidator.password(minLength: 8)(text);
},
hintText: context.translate(
'Password',
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