diff --git a/.run/main.dart.run.xml b/.run/main.dart.run.xml
new file mode 100644
index 00000000..4767aff8
--- /dev/null
+++ b/.run/main.dart.run.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart
index 62b87e6f..806ed3e4 100644
--- a/lib/config/my_router.dart
+++ b/lib/config/my_router.dart
@@ -303,6 +303,7 @@ import '../presentation/Screens/auth_verification/otp_verification.dart';
import '../presentation/Screens/profilepage.dart';
import '../presentation/routes/auth_routes/login_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/manage_users.dart';
@@ -311,7 +312,7 @@ final GoRouter router = GoRouter(
GoRoute(
path: '/',
//builder: (context, state) => LoginRoute(),
- builder: (context, state) => MyHomePage(),
+ builder: (context, state) => LoginRoute(),
),
GoRoute(
path: '/myhomepage',
@@ -328,10 +329,11 @@ final GoRouter router = GoRouter(
),
),
GoRoute(
- path: '/changepassword',
- builder: (context, state) => Changepassword(
- userId: '',
- ),
+ path: '/changepassword/:userId',
+ builder: (context, state) {
+ final userId = state.pathParameters['userId']!;
+ return Changepassword(userId: userId);
+ },
),
GoRoute(
path: '/confirmpasswd',
@@ -347,10 +349,11 @@ final GoRouter router = GoRouter(
builder: (context, state) => FeedbackForm(),
),
GoRoute(
- path: '/profile',
- builder: (context, state) => ProfileScreen(
- userId: '',
- ),
+ path: '/profile/:userId',
+ builder: (context, state) {
+ final userId = state.pathParameters['userId']!;
+ return ProfileScreen(userId: userId);
+ },
),
// GoRoute(
// path: '/manageuser',
@@ -360,10 +363,13 @@ final GoRouter router = GoRouter(
// return ManageUserRouter(title: title);
// },
// ),
+ GoRoute(
+ path: '/editProfile',
+ builder: (context, state) => EditProfile(),
+ ),
GoRoute(
path: '/manageuser',
builder: (context, state) => ManageUserRouter(),
),
],
);
-
diff --git a/lib/presentation/Screens/auth_verification/changepassword.dart b/lib/presentation/Screens/auth_verification/changepassword.dart
index 702da9a2..9b86c2e1 100644
--- a/lib/presentation/Screens/auth_verification/changepassword.dart
+++ b/lib/presentation/Screens/auth_verification/changepassword.dart
@@ -58,7 +58,7 @@ class _ResetPasswordScreenState extends State {
//print('userDetails ->: $userData');
if (userData['items'].isNotEmpty) {
// Email exists; retrieve user ID
- final userId = userData['items'][0]['id'];
+ // final userId = userData['items'][0]['id'];
// Proceed with OTP request
final otpResponse = await http.post(
@@ -87,17 +87,15 @@ class _ResetPasswordScreenState extends State {
);
// Navigate to the Email Verification screen
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => EmailVerificationScreen(
- email: email,
- userId: widget.userId, // Pass user ID to the next screen
- otp: otp,
- otpId: otpId,
- sendVerificationCode: sendVerificationCode,
- ),
- ),
+ context.go(
+ '/mailverification',
+ extra: {
+ 'email': email,
+ 'userId': widget.userId, // Pass user ID to the next screen
+ 'otp': otp,
+ 'otpId': otpId,
+ 'sendVerificationCode': sendVerificationCode,
+ },
);
} else {
final error =
@@ -132,6 +130,12 @@ class _ResetPasswordScreenState extends State {
}
}
+ @override
+ void initState() {
+ super.initState();
+ print(widget.userId);
+ }
+
@override
void dispose() {
_emailController.dispose();
diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart
index 66689b16..97204028 100644
--- a/lib/presentation/Screens/auth_verification/registration.dart
+++ b/lib/presentation/Screens/auth_verification/registration.dart
@@ -6,7 +6,6 @@ import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/Screens/profilepage.dart';
-import '../../../infrastructure/services/pocketbase_service.dart';
import '../../routes/auth_routes/login_route.dart';
class RegisterScreen extends StatefulWidget {
@@ -194,7 +193,7 @@ class _RegisterScreenState extends State {
'email': _emailController.text,
'password': _passwordController.text,
'passwordConfirm': _passwordController.text,
- // 'verified': true,
+ 'status': 'Pending',
}, headers: {
'Authorization': adminToken
});
diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart
index b5eae4ff..76b9622b 100644
--- a/lib/presentation/Screens/profilepage.dart
+++ b/lib/presentation/Screens/profilepage.dart
@@ -9,8 +9,12 @@ import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart';
+import 'package:uae_stat/domain/use_cases/language.dart';
+import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
+import '../components/my_bottom_nav_bar.dart';
import 'auth_verification/changepassword.dart';
+import 'demo_home.dart';
class ProfileScreen extends StatefulWidget {
final String userId; // Add this field to hold the user ID
@@ -23,6 +27,25 @@ class ProfileScreen extends StatefulWidget {
class _ProfileScreenState extends State {
final _pb = PocketBase('https://pb.venbait.in');
// final _pb = PocketBase('http://127.0.0.1:8090');
+
+ // Add focus nodes and hint states
+ final List _focusNodes = List.generate(4, (_) => FocusNode());
+ final List _showHints = [
+ true,
+ true,
+ true,
+ true
+ ]; // One for each TextField
+
+ String _getControllerText(int index) {
+ if (index == 0) return _usernameController.text;
+ if (index == 1) return _emailController.text;
+ if (index == 2) return _fullNameController.text;
+ if (index == 3) return _dateController.text;
+
+ return '';
+ }
+
final _formKey = GlobalKey();
final TextEditingController _fullNameController = TextEditingController();
final TextEditingController _dateController = TextEditingController();
@@ -52,12 +75,58 @@ class _ProfileScreenState extends State {
@override
void initState() {
super.initState();
- print(widget.userId);
+ // print(widget.userId);
+
+ // Add listeners for focus nodes
+ for (int i = 0; i < _focusNodes.length; i++) {
+ _focusNodes[i].addListener(() {
+ setState(() {
+ // Hide hint when focused and text is not empty
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+
+ // Listen to text changes
+ if (i == 0) {
+ _usernameController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 1) {
+ _emailController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 1) {
+ _fullNameController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 2) {
+ _dateController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ }
+ }
+
_fetchUserData(); // Call the function to fetch user data
}
@override
void dispose() {
+ for (var focusNode in _focusNodes) {
+ focusNode.dispose();
+ }
_fullNameController.dispose();
_dateController.dispose();
super.dispose();
@@ -68,6 +137,7 @@ class _ProfileScreenState extends State {
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token;
+ print('adminToken- ${adminToken}');
final userDetailsResponse = await _pb.collection('users').getOne(
widget.userId,
headers: {
@@ -125,7 +195,7 @@ class _ProfileScreenState extends State {
// Function to validate the DOB field
String? _validateDob(String? value) {
if (value == null || value.isEmpty) {
- return 'Please select your date of birth';
+ return 'Required';
}
final DateTime selectedDate = _selectedDate!;
@@ -140,7 +210,7 @@ class _ProfileScreenState extends State {
String? _validateDropdown(String? value) {
if (value == null || value.isEmpty) {
- return 'Please select an option';
+ return 'Required';
}
return null;
}
@@ -201,6 +271,7 @@ class _ProfileScreenState extends State {
_resetFormFields();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile updated successfully!")));
+ context.go('/myhomepage');
} catch (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to update profile: $error")));
@@ -299,8 +370,9 @@ class _ProfileScreenState extends State {
SizedBox(height: 10),
TextFormField(
controller: _usernameController,
+ focusNode: _focusNodes[0],
decoration: InputDecoration(
- hintText: 'Mohammad Hassan',
+ hintText: _showHints[0] ? 'Mohammad Hassan' : null,
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
@@ -322,8 +394,10 @@ class _ProfileScreenState extends State {
SizedBox(height: 10),
TextFormField(
controller: _emailController,
+ focusNode: _focusNodes[1],
decoration: InputDecoration(
- hintText: 'mohammad.hassan@fcsc.gov.ae',
+ hintText:
+ _showHints[1] ? 'mohammad.hassan@fcsc.gov.ae' : null,
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
@@ -349,15 +423,19 @@ class _ProfileScreenState extends State {
if (value == null || value.isEmpty) {
return 'Required';
}
- final nameRegex = RegExp(r"^[a-zA-Z\s]+$");
+
+ //RegExp(r"^[a-zA-Z\s]+$");
+ final nameRegex =
+ RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$");
if (!nameRegex.hasMatch(value)) {
return 'Invalid Characters';
}
return null;
},
controller: _fullNameController,
+ focusNode: _focusNodes[2],
decoration: InputDecoration(
- hintText: "Mohammad",
+ hintText: _showHints[2] ? 'Enter the Full Name' : null,
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
@@ -381,11 +459,14 @@ class _ProfileScreenState extends State {
SizedBox(height: 10),
TextFormField(
controller: _dateController,
+ focusNode: _focusNodes[3],
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
- hintText: 'Select your Date of Birth',
+ hintText:
+ _showHints[3] ? 'Select your Date of Birth' : null,
+ //hintText: 'Select your Date of Birth',
suffixIcon: const Icon(Icons.arrow_drop_down_sharp),
),
readOnly: true,
@@ -503,7 +584,7 @@ class _ProfileScreenState extends State {
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
- 'Required',
+ 'Please agree to terms and conditions',
style: TextStyle(
color: Colors.red[700],
fontSize: 12,
@@ -516,15 +597,13 @@ class _ProfileScreenState extends State {
Center(
child: GestureDetector(
onTap: () {
- context.go('/confirmpasswd');
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Changepassword(userId: widget.userId)),
+ );
},
- // {
- // Navigator.push(
- // context,
- // MaterialPageRoute(
- // builder: (context) => Changepassword(userId: '',)),
- // );
- // },
child: Text(
"Change Password",
style: TextStyle(
@@ -536,38 +615,35 @@ class _ProfileScreenState extends State {
SizedBox(height: 20),
ElevatedButton.icon(
onPressed: () {
- context.go('/myhomepage');
+ if ((_formKey.currentState?.validate() ?? false) &&
+ (isChecked)) {
+ _formKey.currentState?.save();
+ showConfirmationDialog(context);
+ } else {
+ setState(() {
+ showError =
+ !isChecked; // Show error if the checkbox is not checked
+ });
+ }
+ // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
+ // _formKey.currentState?.save();
+ // showConfirmationDialog(context);
+ // // if (isChecked) {
+ // // _formKey.currentState?.save();
+ // // // _confirmSaveProfile();
+ // // showConfirmationDialog(context);
+ // // }
+ // else {
+ // setState(() {
+ // showError = !isChecked; // Show error if the checkbox is not checked
+ // });
+
+ // ScaffoldMessenger.of(context).showSnackBar(
+ // SnackBar(content: Text('Please accept the terms and conditions.',style: TextStyle(color: Colors.white),)),
+ // );
+ //}
+ //}
},
- // {
- // if ((_formKey.currentState?.validate() ?? false) &&
- // (isChecked)) {
- // _formKey.currentState?.save();
- // showConfirmationDialog(context);
- // } else {
- // setState(() {
- // showError =
- // !isChecked; // Show error if the checkbox is not checked
- // });
- // }
- // // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
- // // _formKey.currentState?.save();
- // // showConfirmationDialog(context);
- // // // if (isChecked) {
- // // // _formKey.currentState?.save();
- // // // // _confirmSaveProfile();
- // // // showConfirmationDialog(context);
- // // // }
- // // else {
- // // setState(() {
- // // showError = !isChecked; // Show error if the checkbox is not checked
- // // });
- //
- // // ScaffoldMessenger.of(context).showSnackBar(
- // // SnackBar(content: Text('Please accept the terms and conditions.',style: TextStyle(color: Colors.white),)),
- // // );
- // //}
- // //}
- // },
icon: Icon(
Icons.save,
color: Colors.white,
diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart
index ecbf1200..a0ea8df4 100644
--- a/lib/presentation/routes/auth_routes/login_route.dart
+++ b/lib/presentation/routes/auth_routes/login_route.dart
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:shared_preferences/shared_preferences.dart';
import 'package:the_validator/the_validator.dart';
import 'package:uae_stat/config/my_theme.dart';
import 'package:uae_stat/domain/use_cases/auth_use_case.dart';
@@ -17,7 +18,6 @@ import 'package:uae_stat/presentation/components/space.dart';
import 'package:uae_stat/presentation/components/themed_text_field.dart';
import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
-import '../../Screens/profilepage.dart';
import '../../Screens/auth_verification/registration.dart';
import 'package:pocketbase/pocketbase.dart';
@@ -25,6 +25,7 @@ class LoginRoute extends HookConsumerWidget {
final pb = PocketBase('https://pb.venbait.in');
// final _pb = PocketBase('http://127.0.0.1:8090');
LoginRoute({super.key});
+ dynamic userData;
static final formKey = GlobalKey();
@@ -45,21 +46,38 @@ class LoginRoute extends HookConsumerWidget {
'Authorization': 'Bearer $adminToken',
},
);
+
print('userDetailsLogin: $userDetailsResponse');
- // Check if 'is_profile_completed' is true or false
- if (userDetailsResponse != null &&
- userDetailsResponse.data['is_profile_completed'] != null) {
- return userDetailsResponse.data['is_profile_completed'];
- } else {
- return false; // Default to false if the field is missing or response is null
+ // Check if user is verified
+ final bool? isVerified = userDetailsResponse.data['verified'];
+ final bool? isUserMailVerified =
+ userDetailsResponse.data['user_mail_verify'];
+
+ // Check admin and email verification statuses
+ if (isVerified == false) {
+ throw Exception('Admin not approved');
}
+ if (isUserMailVerified == false) {
+ throw Exception('Email not verified');
+ }
+ userData = userDetailsResponse;
+ // Check if 'is_profile_completed' is true
+ final bool isProfileCompleted =
+ userDetailsResponse.data['is_profile_completed'] ?? false;
+
+ return isProfileCompleted;
} catch (e) {
print('Error fetching user details: $e');
- return false; // Return false on error
+ rethrow;
}
}
+ Future saveUserId(String userId) async {
+ final prefs = await SharedPreferences.getInstance();
+ await prefs.setString('userId', userId); // Save userId locally
+ }
+
@override
Widget build(BuildContext context, WidgetRef ref) {
final emailCtl = useTextEditingController();
@@ -157,105 +175,121 @@ class LoginRoute extends HookConsumerWidget {
final loginBtn = SizedBox(
width: double.infinity,
child: ElevatedButton(
- onPressed: () {
- context.go('/profile');
+ onPressed: () async {
+ final isValid = formKey.currentState!.validate();
+ if (!isValid) return;
+ final session = await context.loaderWithErrorDialog(
+ () => ref
+ .read(
+ authUseCaseProvider.notifier,
+ )
+ .login(
+ emailCtl.text,
+ pwCtl.text,
+ ),
+ errorDialogBuilder: (
+ error, [
+ StackTrace? stackTrace,
+ ]) {
+ if (error == LoginError.invalidEmailPw) {
+ return context.simpleDialog(
+ title: context.translate(
+ 'Incorrect credentials',
+ 'أوراق غير صحيحة',
+ ),
+ content: context.translate(
+ 'Your email or password is invalid. Please try again.',
+ 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.',
+ ),
+ );
+ }
+ // if (error == LoginError.emailAddressNotVerified) {
+ // return context.simpleDialog(
+ // title: context.translate(
+ // 'Verification Error',
+ // 'خطأ التحقق',
+ // ),
+ // content: context.translate(
+ // '${emailCtl.text} is not a verified email address. Please check your email for a verification link.',
+ // '${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.',
+ // ),
+ // extraAction: ElevatedButton(
+ // onPressed: () async {
+ // Navigator.of(
+ // context,
+ // rootNavigator: true,
+ // ).pop();
+ // await context.loaderWithErrorDialog(
+ // () => ref
+ // .read(authUseCaseProvider.notifier)
+ // .requestVerificationEmail(emailCtl.text),
+ // );
+ // if (!context.mounted) return;
+ // context.simpleDialog(
+ // title: 'Email Re-sent',
+ // content:
+ // 'We\'ve sent you the verification email at ${emailCtl.text} again.',
+ // );
+ // },
+ // child: Text(
+ // context.translate(
+ // 'I did not receive an email',
+ // 'لم أتلق بريدًا إلكترونيًا',
+ // ),
+ // ),
+ // ),
+ // );
+ // }
+ return context.simpleDialog();
+ },
+ );
+
+ if (!context.mounted || session == null) return;
+ final userId = session.id;
+ if (userId.isNotEmpty) {
+ await saveUserId(userId);
+ }
+ try {
+ final bool isProfileComplete = await profileStatus(userId);
+ print(isProfileComplete);
+ if (isProfileComplete) {
+ print('home');
+ context.go('/myhomepage');
+ } else {
+ print('profile');
+ if (userId != null && userId.isNotEmpty) {
+ context.go('/profile/$userId');
+ } else {
+ print('Error: userId is null or empty.');
+ }
+ }
+ } catch (e) {
+ // Handle specific errors based on their message
+ if (e.toString().contains('Admin not approved')) {
+ context.simpleDialog(
+ title: context.translate(
+ 'Admin Approval Required', 'موافقة المسؤول مطلوبة'),
+ content: context.translate(
+ 'Your account has not been approved by the admin.',
+ 'لم تتم الموافقة على حسابك من قبل المسؤول.',
+ ),
+ );
+ } else if (e.toString().contains('Email not verified')) {
+ context.simpleDialog(
+ title: context.translate(
+ 'Email Not Verified', 'البريد الإلكتروني غير مُحقق'),
+ content: context.translate(
+ 'Your email address is not verified. Please check your email.',
+ 'عنوان بريدك الإلكتروني غير مُحقق. يرجى التحقق من بريدك الإلكتروني.',
+ ),
+ );
+ } else {
+ print('Unexpected error: $e');
+ }
+ }
+
+ // context.go('/${context.language}/${BottomNavBarItem.home.routePath}');
},
- // async {
- // final isValid = formKey.currentState!.validate();
- // if (!isValid) return;
- // final session = await context.loaderWithErrorDialog(
- // () => ref
- // .read(
- // authUseCaseProvider.notifier,
- // )
- // .login(
- // emailCtl.text,
- // pwCtl.text,
- // ),
- // errorDialogBuilder: (
- // error, [
- // StackTrace? stackTrace,
- // ]) {
- // if (error == LoginError.invalidEmailPw) {
- // return context.simpleDialog(
- // title: context.translate(
- // 'Incorrect credentials',
- // 'أوراق غير صحيحة',
- // ),
- // content: context.translate(
- // 'Your email or password is invalid. Please try again.',
- // 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.',
- // ),
- // );
- // }
- // if (error == LoginError.emailAddressNotVerified) {
- // return context.simpleDialog(
- // title: context.translate(
- // 'Verification Error',
- // 'خطأ التحقق',
- // ),
- // content: context.translate(
- // '${emailCtl.text} is not a verified email address. Please check your email for a verification link.',
- // '${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.',
- // ),
- // extraAction: ElevatedButton(
- // onPressed: () {
- // context.go('/profile');
- // },
- // // async {
- // // Navigator.of(
- // // context,
- // // rootNavigator: true,
- // // ).pop();
- // // await context.loaderWithErrorDialog(
- // // () => ref
- // // .read(authUseCaseProvider.notifier)
- // // .requestVerificationEmail(emailCtl.text),
- // // );
- // // if (!context.mounted) return;
- // // context.simpleDialog(
- // // title: 'Email Re-sent',
- // // content:
- // // 'We\'ve sent you the verification email at ${emailCtl.text} again.',
- // // );
- // // },
- // child: Text(
- // context.translate(
- // 'I did not receive an email',
- // 'لم أتلق بريدًا إلكترونيًا',
- // ),
- // ),
- // ),
- // );
- // }
- // return context.simpleDialog();
- // },
- // );
- // // if (!context.mounted || session == null) return;
- // // Extract userId from the session
- // // final userId = session.id;
- // //
- // // final bool isUpdate = await profileStatus(userId);
- // //
- // // print('Is profile completed: $isUpdate');
- //
- // // if (isUpdate) {
- // // Navigator.pushReplacement(
- // // context,
- // // MaterialPageRoute(builder: (context) => DemoHome()),
- // // );
- // // }
- // // else {
- //
- // // Navigator.pushReplacement(
- // // context,
- // // MaterialPageRoute(
- // // builder: (context) => ProfileScreen(userId: userId)),
- // // );
- // //}
- //
- // // context.go('/${context.language}/${BottomNavBarItem.home.routePath}');
- // },
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart
new file mode 100644
index 00000000..3d74ef02
--- /dev/null
+++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart
@@ -0,0 +1,837 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:go_router/go_router.dart';
+import 'package:http/http.dart' as http;
+import 'package:image_picker/image_picker.dart';
+import 'package:intl/intl.dart';
+import 'package:pocketbase/pocketbase.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+import '../../../Screens/auth_verification/changepassword.dart';
+import '../custom_drawer_routes.dart';
+
+class EditProfile extends StatefulWidget {
+ @override
+ State createState() => _EditProfileState();
+}
+
+class _EditProfileState extends State {
+ final _pb = PocketBase('https://pb.venbait.in');
+ // final _pb = PocketBase('http://127.0.0.1:8090');
+ bool _isProfileCompleted = false;
+
+ // Add focus nodes and hint states
+ final List _focusNodes = List.generate(4, (_) => FocusNode());
+ final List _showHints = [
+ true,
+ true,
+ true,
+ true
+ ]; // One for each TextField
+
+ String _getControllerText(int index) {
+ if (index == 0) return _usernameController.text;
+ if (index == 1) return _emailController.text;
+ if (index == 2) return _fullNameController.text;
+ if (index == 3) return _dateController.text;
+
+ return '';
+ }
+
+ final _formKey = GlobalKey();
+ final TextEditingController _fullNameController = TextEditingController();
+ final TextEditingController _dateController = TextEditingController();
+ final TextEditingController _usernameController = TextEditingController();
+ final TextEditingController _emailController = TextEditingController();
+ // To keep track of the selected date
+ DateTime? _selectedDate;
+
+ // Date format for the display
+ final DateFormat _dateFormat = DateFormat('yyyy-MM-dd');
+ final List _countries = [
+ 'United Arab Emirates',
+ 'United States',
+ 'India',
+ 'Canada'
+ ];
+ String? _selectedCountry;
+ bool isChecked = false;
+ bool showError = false;
+ final _picker = ImagePicker();
+ File? _profileImage;
+ String _avatarUrl = '';
+
+ // Regular expression to validate Full Name (no special characters)
+ final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$");
+ late Future userDetails;
+ dynamic userId;
+
+ @override
+ void initState() {
+ super.initState();
+
+ // Add listeners for focus nodes
+ for (int i = 0; i < _focusNodes.length; i++) {
+ _focusNodes[i].addListener(() {
+ setState(() {
+ // Hide hint when focused and text is not empty
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+
+ // Listen to text changes
+ if (i == 0) {
+ _usernameController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 1) {
+ _emailController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 1) {
+ _fullNameController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ } else if (i == 2) {
+ _dateController.addListener(() {
+ setState(() {
+ _showHints[i] =
+ !_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
+ });
+ });
+ }
+ }
+ checkUserId();
+ }
+
+ @override
+ void dispose() {
+ for (var focusNode in _focusNodes) {
+ focusNode.dispose();
+ }
+ _fullNameController.dispose();
+ _dateController.dispose();
+ super.dispose();
+ }
+
+ Future getUserId() async {
+ final prefs = await SharedPreferences.getInstance();
+ return prefs.getString('userId'); // Retrieve the userId
+ }
+
+ Future checkUserId() async {
+ userId = await getUserId();
+ //userId = 'tplu4by67phkfoq';
+ if (userId != null && userId.isNotEmpty) {
+ print('User ID: $userId');
+ _fetchUserData();
+ } else {
+ print('No userId found');
+ // Handle case where userId is not available
+ }
+ }
+
+ Future _fetchUserData() async {
+ try {
+ final adminAuth = await _pb.admins
+ .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
+ final adminToken = adminAuth.token;
+ print('adminToken- ${adminToken}');
+ final userDetailsResponse = await _pb.collection('users').getOne(
+ userId,
+ headers: {
+ 'Authorization': 'Bearer $adminToken',
+ },
+ );
+ print('userDetails: $userDetailsResponse');
+ setState(() {
+ _usernameController.text = userDetailsResponse.data['username'] ?? '';
+ _emailController.text = userDetailsResponse.data['email'] ?? '';
+ _fullNameController.text = userDetailsResponse.data['full_name'] ?? '';
+ _selectedCountry = userDetailsResponse.data['country_region'] ?? '';
+ _isProfileCompleted =
+ userDetailsResponse.data['is_profile_completed'] ?? false;
+ //_isProfileCompleted = true ;
+
+ // Parse and format the date
+ String dateString = userDetailsResponse.data['dob'] ?? '';
+ if (dateString.isNotEmpty) {
+ DateTime dob = DateTime.parse(dateString);
+ _dateController.text =
+ DateFormat('dd/MM/yyyy').format(dob); // Format to dd/mm/yyyy
+ } else {
+ _dateController.text = '';
+ }
+
+ // Set the avatar URL
+ String avatarFilename = userDetailsResponse.data['avatar'] ?? '';
+ String recordId = userId;
+ String collectionId =
+ userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_';
+
+ if (avatarFilename.isNotEmpty && recordId.isNotEmpty) {
+ _avatarUrl =
+ 'https://pb.venbait.in/api/files/$collectionId/$recordId/$avatarFilename';
+ } 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');
+ }
+ }
+
+ void _pickImage() async {
+ final XFile? pickedFile =
+ await _picker.pickImage(source: ImageSource.gallery);
+ if (pickedFile != null) {
+ setState(() {
+ _profileImage = File(pickedFile.path);
+ });
+ }
+ }
+
+ // Function to open the date picker
+ Future _pickDate() async {
+ final DateTime today = DateTime.now();
+ final DateTime initialDate = _selectedDate ??
+ today.subtract(
+ const Duration(days: 365 * 18)); // Default to 18 years ago
+ final DateTime firstDate = today.subtract(const Duration(
+ days: 365 * 100)); // Allow picking dates back to 100 years ago
+ final DateTime lastDate = today; // Allow picking dates up to today
+
+ // Updated Date format to DD/MM/YYYY
+ final DateFormat _dateFormat = DateFormat('dd/MM/yyyy');
+
+ final DateTime? pickedDate = await showDatePicker(
+ context: context,
+ initialDate: initialDate,
+ firstDate: firstDate,
+ lastDate: lastDate,
+ );
+
+ if (pickedDate != null && pickedDate != _selectedDate) {
+ setState(() {
+ _selectedDate = pickedDate;
+ _dateController.text = _dateFormat.format(pickedDate);
+ });
+ }
+ }
+
+ // Function to validate the DOB field
+ String? _validateDob(String? value) {
+ if (value == null || value.isEmpty) {
+ return 'Required';
+ }
+
+ final DateTime selectedDate = _selectedDate!;
+ final DateTime today = DateTime.now();
+
+ // Check if the selected date is in the future
+ if (selectedDate.isAfter(today)) {
+ return 'Date of birth cannot be in the future';
+ }
+ return null;
+ }
+
+ String? _validateDropdown(String? value) {
+ if (value == null || value.isEmpty) {
+ return 'Required';
+ }
+ return null;
+ }
+
+ void _toggleCheckbox(bool? value) {
+ setState(() {
+ isChecked = value ?? false;
+ });
+ }
+
+ void showConfirmationDialog(BuildContext context) async {
+ final result = await showDialog(
+ context: context,
+ builder: (context) => const ConfirmationDialog(),
+ );
+
+ if (result == true) {
+ // Validate only the country field
+ if (_validateDropdown(_selectedCountry) == null) {
+ try {
+ String userID = userId;
+
+ print("ShowConfirmationuserID - $userID ");
+ // Retrieve data from the country/region field
+ String countryRegion =
+ _selectedCountry ?? ''; // Ensure the country is selected
+
+ // Create a multipart request
+ final uri =
+ Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
+ final request = http.MultipartRequest('PATCH', uri);
+
+ // Add fields to the request
+ request.fields['country_region'] =
+ countryRegion; // Only update country here
+
+ // If profile image exists, add it
+ if (_profileImage != null) {
+ request.files.add(await http.MultipartFile.fromPath(
+ 'avatar',
+ _profileImage!.path,
+ ));
+ }
+
+ // Add headers (e.g., authorization)
+ request.headers['Authorization'] = 'Bearer ${_pb.authStore.token}';
+
+ // Send the request
+ final response = await request.send();
+ print(response);
+
+ // Handle response
+ if (response.statusCode == 200) {
+ _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(
+ SnackBar(content: Text("Failed to update profile: $error")),
+ );
+ }
+ } else {
+ // Show an error if the country is invalid
+ setState(() {
+ showError = true;
+ });
+ }
+ }
+ }
+
+ void _resetFormFields() {
+ print('reset');
+ setState(() {
+ // Reset all text controllers
+ _fullNameController.clear();
+ _dateController.clear();
+ _selectedCountry = null;
+ isChecked = false;
+
+ // Reset profile image
+ _profileImage = null;
+
+ // Reset form validation state
+ _formKey.currentState?.reset();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return BaseScaffold(
+ title: Text("Profile"),
+ body: SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ child: Form(
+ key: _formKey,
+ child: Padding(
+ padding: const EdgeInsets.all(20.0),
+ child: Column(
+ children: [
+ CircleAvatar(
+ radius: 50,
+ backgroundImage: _profileImage != null
+ ? FileImage(
+ _profileImage!) // If a local file is selected
+ : _avatarUrl.isNotEmpty
+ ? NetworkImage(_avatarUrl) // Load from URL
+ : AssetImage(
+ "assets/edit_profile/profile.png")
+ as ImageProvider,
+
+ //backgroundImage: NetworkImage(_avatarUrl) as ImageProvider,
+ child: Align(
+ alignment: Alignment.bottomRight,
+ child: GestureDetector(
+ onTap: _pickImage, // Call `_pickImage` on tap
+ child: CircleAvatar(
+ radius: 15,
+ backgroundColor: Colors.white,
+ child: Icon(
+ Icons.camera_alt,
+ size: 15,
+ color: Colors.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ SizedBox(height: 20),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "User Name",
+ style: TextStyle(
+ fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ SizedBox(height: 10),
+ TextFormField(
+ controller: _usernameController,
+ focusNode: _focusNodes[0],
+ decoration: InputDecoration(
+ hintText: _showHints[0] ? 'Mohammad Hassan' : null,
+ hintStyle: TextStyle(color: Colors.grey),
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ enabled: false,
+ ),
+ ),
+ SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "E-mail",
+ style: TextStyle(
+ fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ SizedBox(height: 10),
+ TextFormField(
+ controller: _emailController,
+ focusNode: _focusNodes[1],
+ decoration: InputDecoration(
+ hintText: _showHints[1]
+ ? 'mohammad.hassan@fcsc.gov.ae'
+ : null,
+ hintStyle: TextStyle(color: Colors.grey),
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ enabled: false,
+ ),
+ ),
+ SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "Full Name",
+ style: TextStyle(
+ fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ SizedBox(height: 10),
+ TextFormField(
+ enabled: false,
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ return 'Required';
+ }
+
+ //RegExp(r"^[a-zA-Z\s]+$");
+ final nameRegex = RegExp(
+ r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$");
+ if (!nameRegex.hasMatch(value)) {
+ return 'Invalid Characters';
+ }
+ return null;
+ },
+ controller: _fullNameController,
+ focusNode: _focusNodes[2],
+ decoration: InputDecoration(
+ hintText: _showHints[2] ? 'Mohammad' : null,
+ hintStyle: TextStyle(color: Colors.grey),
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ // counterText: '',
+ enabled: !_isProfileCompleted,
+ ),
+ maxLength:
+ 40, // Set the maximum length to 20 characters
+ maxLengthEnforcement: MaxLengthEnforcement.enforced,
+ ),
+ SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "Date of Birth*",
+ style: TextStyle(
+ fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ SizedBox(height: 10),
+ TextFormField(
+ controller: _dateController,
+ focusNode: _focusNodes[3],
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ hintText: _showHints[3]
+ ? 'Select your Date of Birth'
+ : null,
+ //hintText: 'Select your Date of Birth',
+ suffixIcon: const Icon(Icons.arrow_drop_down_sharp),
+ enabled: !_isProfileCompleted,
+ ),
+ readOnly: true,
+ onTap: _pickDate,
+ validator: _validateDob,
+ ),
+ SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "Country/Region*",
+ style: TextStyle(
+ fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ SizedBox(height: 10),
+ DropdownButtonFormField(
+ value: _selectedCountry,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ labelText: 'Select',
+ ),
+ items: _countries
+ .map((item) => DropdownMenuItem(
+ value: item,
+ child: Text(item),
+ ))
+ .toList(),
+ onChanged: (String? newValue) {
+ setState(() {
+ _selectedCountry = newValue;
+ });
+ },
+ validator: _validateDropdown,
+ ),
+ SizedBox(height: 20),
+ if (!_isProfileCompleted) // Conditional rendering
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 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: Column(
+ mainAxisAlignment:
+ MainAxisAlignment.start,
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 10),
+ Text.rich(
+ TextSpan(
+ text: 'I agree to the ',
+ style:
+ TextStyle(color: Colors.black),
+ children: [
+ TextSpan(
+ text: 'Terms & Conditions',
+ style: TextStyle(
+ color: Colors.blue,
+ decoration:
+ TextDecoration.underline,
+ ),
+ recognizer:
+ TapGestureRecognizer()
+ ..onTap = () {
+ // Add action for Terms & Conditions tap
+ },
+ ),
+ TextSpan(
+ text: ' and ',
+ style: TextStyle(
+ color: Colors.black),
+ ),
+ TextSpan(
+ text: 'Privacy Policy',
+ style: TextStyle(
+ color: Colors.blue,
+ decoration:
+ TextDecoration.underline,
+ ),
+ recognizer:
+ TapGestureRecognizer()
+ ..onTap = () {
+ // Add action for Privacy Policy tap
+ },
+ ),
+ TextSpan(
+ text: ' of FCSC.',
+ style: TextStyle(
+ color: Colors.black),
+ ),
+ ],
+ ),
+ textAlign: TextAlign.start,
+ maxLines: 2,
+ overflow: TextOverflow.visible,
+ softWrap: true,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ 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),
+ Center(
+ child: GestureDetector(
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Changepassword(userId: userId)),
+ );
+ },
+ child: Text(
+ "Change Password",
+ style: TextStyle(
+ color: Colors.blue,
+ decoration: TextDecoration.underline),
+ ),
+ ),
+ ),
+ SizedBox(height: 20),
+ 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,
+ color: Colors.white,
+ ),
+ label: Text(
+ 'Save',
+ style: TextStyle(color: Colors.white),
+ ),
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Color(0xFF92722A),
+ minimumSize: Size(double.infinity, 50),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ //bottomNavigationBar: MyBottomNavBar(),
+ );
+ }
+}
+
+class ConfirmationDialog extends StatelessWidget {
+ const ConfirmationDialog({Key? key}) : super(key: key);
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Are you sure you want to save this page?",
+ style: const TextStyle(
+ fontSize: 14,
+ color: Color(0xFF898C81),
+ fontFamily: 'Roboto',
+ fontWeight: FontWeight.w400,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ SizedBox(height: 8),
+ Text.rich(
+ TextSpan(
+ text: "Once saved, you will not be able to change your ",
+ style: TextStyle(
+ fontSize: 14,
+ color: Color(0xFF898C81),
+ fontFamily: 'Roboto',
+ fontWeight: FontWeight.w400,
+ ),
+ children: [
+ TextSpan(
+ text: "Country",
+ style:
+ TextStyle(fontWeight: FontWeight.w700), // Bold for "name"
+ ),
+ TextSpan(
+ text: " or ",
+ ),
+ TextSpan(
+ text: "Profile Image",
+ style: TextStyle(
+ fontWeight: FontWeight.w700), // Bold for "date of birth"
+ ),
+ TextSpan(
+ text: ".",
+ ),
+ ],
+ ),
+ textAlign: TextAlign.center,
+ )
+ ],
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0),
+ actionsPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
+ actions: [
+ Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ OutlinedButton(
+ onPressed: () {
+ Navigator.of(context).pop(false);
+ },
+ style: OutlinedButton.styleFrom(
+ side: BorderSide(color: Color(0xFF92722A)),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(7)),
+ ), // Set the border color here
+ ),
+ child: Text(
+ "Cancel",
+ style: TextStyle(color: Color(0xFF92722A)),
+ ),
+ ),
+ ElevatedButton(
+ onPressed: () => Navigator.of(context).pop(true),
+ style: ElevatedButton.styleFrom(
+ backgroundColor: const Color(0xFF92722A), // Brown color
+ foregroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(8),
+ ),
+ ),
+ child: const Text(
+ 'Confirm',
+ style: TextStyle(
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ SizedBox(
+ height: 5,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart
index 5d4ce688..7934ed17 100644
--- a/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart
+++ b/lib/presentation/routes/drawer_routes/Drawer Items/feedback.dart
@@ -17,7 +17,6 @@ import '../../../../config/my_theme.dart';
import '../../../../domain/use_cases/preferences_use_case.dart';
import '../../../components/my_toggle.dart';
-
class FeedbackForm extends StatefulWidget {
const FeedbackForm({super.key});
@@ -28,7 +27,7 @@ class FeedbackForm extends StatefulWidget {
class _FeedbackFormState extends State
with WidgetsBindingObserver {
final _pb =
- PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
+ PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
// final _pb =
// PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
@@ -43,34 +42,35 @@ class _FeedbackFormState extends State
bool _isFeedbackFailed = false; // New flag for failed submission
bool _isSmileySelected = true; // Track if smiley is selected
dynamic configEmail;
+ dynamic userId;
List