routing changes

This commit is contained in:
VINISTAN 2024-12-04 10:55:06 +05:30
commit 3ab1010409
9 changed files with 496 additions and 259 deletions

View File

@ -56,7 +56,7 @@ class AuthUseCase extends _$AuthUseCase {
); );
} }
Future<void> login(String email, String pw) async { Future<SessionEntity> login(String email, String pw) async {
final session = await _repo.login(email, pw); final session = await _repo.login(email, pw);
final localPrefs = await getIt.call<TLocalPreferencesRepo>().get(); final localPrefs = await getIt.call<TLocalPreferencesRepo>().get();
if (localPrefs != null) { if (localPrefs != null) {
@ -66,6 +66,7 @@ class AuthUseCase extends _$AuthUseCase {
); );
} }
state = AsyncData(session); state = AsyncData(session);
return session; // Return the session with user details.
} }
Future<void> logout() async { Future<void> logout() async {

View File

@ -16,34 +16,25 @@ void main() async {
// await (await SharedPreferences.getInstance()).clear(); // await (await SharedPreferences.getInstance()).clear();
configureDependencies(); configureDependencies();
runApp( runApp(
ProviderScope( const ProviderScope(
child: MainApp(), child: MainApp(),
), ),
); );
} }
class MainApp extends StatelessWidget { class MainApp extends StatelessWidget {
const MainApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp.router( return MaterialApp(
routerConfig: router, // Use the GoRouter configuration home: RegisterScreen(),
//home: ProfileScreen(),
debugShowCheckedModeBanner: false,
); );
} }
} }
// class MainApp extends StatelessWidget {
// const MainApp({super.key});
//
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// home: RegisterScreen(),
// //home: ProfileScreen(),
// debugShowCheckedModeBanner: false,
// );
// }
// }
// class MainApp extends ConsumerWidget { // class MainApp extends ConsumerWidget {
// const MainApp({super.key}); // const MainApp({super.key});
@ -103,5 +94,3 @@ class MainApp extends StatelessWidget {
// return authFinalizedWidget; // return authFinalizedWidget;
// } // }
// } // }

View File

@ -1,12 +1,16 @@
import 'dart:math';
import 'dart:convert'; import 'dart:convert';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
//import 'otp_verification.dart'; import 'otp_verification.dart';
class Changepassword extends StatefulWidget { class Changepassword extends StatefulWidget {
const Changepassword({Key? key}) : super(key: key); // final String email;
final String userId;
const Changepassword({Key? key, required this.userId});
@override @override
State<Changepassword> createState() => _ResetPasswordScreenState(); State<Changepassword> createState() => _ResetPasswordScreenState();
@ -76,42 +80,39 @@ class _ResetPasswordScreenState extends State<Changepassword> {
final otp = otpData['otp']; // OTP value from the response final otp = otpData['otp']; // OTP value from the response
final otpId = otpData['id']; final otpId = otpData['id'];
_otpId = otpData['id']; _otpId = otpData['id'];
//print('OTP: $otp, ID: $otpId, '); //print('OTP: $otp, ID: $otpId, ');
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Verification code sent to $email")), SnackBar(content: Text("Verification code sent to $email")),
); );
// Navigate to the Email Verification screen // Navigate to the Email Verification screen
// Navigator.push( Navigator.push(
// context, context,
// MaterialPageRoute( MaterialPageRoute(
// builder: (context) => EmailVerificationScreen( builder: (context) => EmailVerificationScreen(
// email: email, email: email,
// userId: 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 {
context.go('/Profile');
final error = final error =
jsonDecode(otpResponse.body)['error'] ?? "Unknown error"; jsonDecode(otpResponse.body)['error'] ?? "Unknown error";
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error: $error")), SnackBar(content: Text("Error: $error")),
); );
} }
} } else {
else {
// Email not found // Email not found
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Please Enter Registered Mail ID")), SnackBar(content: Text("Please Enter Registered Mail ID")),
); );
} }
} } else {
else {
// Error in user collection request // Error in user collection request
final error = final error =
jsonDecode(userCheckResponse.body)['error'] ?? "Unknown error"; jsonDecode(userCheckResponse.body)['error'] ?? "Unknown error";
@ -119,13 +120,11 @@ class _ResetPasswordScreenState extends State<Changepassword> {
SnackBar(content: Text("Error: $error")), SnackBar(content: Text("Error: $error")),
); );
} }
} } catch (e) {
catch (e) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to process request: $e")), SnackBar(content: Text("Failed to process request: $e")),
); );
} } finally {
finally {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
@ -238,15 +237,12 @@ class _ResetPasswordScreenState extends State<Changepassword> {
width: double.infinity, width: double.infinity,
height: 48, height: 48,
child: ElevatedButton( child: ElevatedButton(
onPressed: (){ onPressed: _isLoading
context.go('/mailverification'); ? null
}, : () {
// _isLoading final email = _emailController.text.trim();
// ? null sendVerificationCode(email);
// : () { },
// final email = _emailController.text.trim();
// sendVerificationCode(email);
// },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8B7355), backgroundColor: const Color(0xFF8B7355),
foregroundColor: Colors.white, foregroundColor: Colors.white,

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart';
@ -72,10 +71,14 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
} }
// Update password // Update password
await _pb.collection('users').update( await pb.collection('users').update(
userId, // User ID userId, // User ID
body: {'password': newPassword}, // Updated password body: {
); 'password': newPassword,
'passwordConfirm': newPassword,
}, // Updated password
headers: headers,
);
// Show success Snackbar // Show success Snackbar
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -202,22 +205,18 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
SizedBox( SizedBox(
width: screenwidth / 1.1, width: screenwidth / 1.1,
child: ElevatedButton( child: ElevatedButton(
onPressed: () onPressed: () async {
{ if ((_formKey.currentState?.validate() ?? false)) {
context.go('/myhomepage'); //String userId = '4hai9cbn4lg6jt4'; // Replace with the actual user ID
String newPassword = _password ??
''; // Replace with the new password
//print("Confirm Passwd- $widget.userId, $newPassword");
await updatePassword(widget.userId, newPassword);
}
// Add verification logic here
}, },
// async {
// if ((_formKey.currentState?.validate() ?? false)) {
// //String userId = '4hai9cbn4lg6jt4'; // Replace with the actual user ID
// String newPassword = _password ??
// ''; // Replace with the new password
//
// //print("Confirm Passwd- $widget.userId, $newPassword");
//
// await updatePassword(widget.userId, newPassword);
// }
// // Add verification logic here
// },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.brown[300], backgroundColor: Colors.brown[300],
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:uae_stat/domain/use_cases/language.dart';
import '../components/my_drawer.dart';
class DemoHome extends StatefulWidget {
@override
State<DemoHome> createState() => _DemoHomeState();
}
class _DemoHomeState extends State<DemoHome> {
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: const MyDrawer(),
appBar: AppBar(
backgroundColor: const Color(0xFFf8f9ff),
title: Text(context.translate('Home', 'نموذج الملاحظات')),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text('Home Page'),
)),
);
}
}

View File

@ -1,9 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/config/my_router.dart';
import 'confirm_password.dart'; import 'confirm_password.dart';
@ -216,20 +214,17 @@ class _EmailVerificationScreenState extends State<EmailVerificationScreen> {
SizedBox( SizedBox(
width: screenwidth / 1.2, width: screenwidth / 1.2,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () async {
context.go('/confirmpasswd');
},
//async {
// Combine the entered OTP // Combine the entered OTP
// String enteredOTP = _otpControllers String enteredOTP = _otpControllers
// .map((controller) => controller.text) .map((controller) => controller.text)
// .join(); .join();
//
// verify( verify(
// context, widget.email, enteredOTP, widget.userId); context, widget.email, enteredOTP, widget.userId);
//
// // Add verification logic here // Add verification logic here
// }, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.brown[300], backgroundColor: Colors.brown[300],
padding: padding:

View File

@ -1,18 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
//import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import '../../domain/use_cases/preferences_use_case.dart';
import '../routes/bottom_bar_routes/tab_routes/home_route.dart';
import 'changepassword.dart'; import 'changepassword.dart';
class ProfileScreen extends StatefulWidget { class ProfileScreen extends StatefulWidget {
@ -24,8 +20,7 @@ class ProfileScreen extends StatefulWidget {
} }
class _ProfileScreenState extends State<ProfileScreen> { class _ProfileScreenState extends State<ProfileScreen> {
final defaultLanguage = PreferencesUseCase.defaultPrefs.language.name; final _pb = PocketBase('https://pb.venbait.in');
//final _pb = PocketBase('https://pb.venbait.in');
// final _pb = PocketBase('http://127.0.0.1:8090'); // final _pb = PocketBase('http://127.0.0.1:8090');
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final TextEditingController _fullNameController = TextEditingController(); final TextEditingController _fullNameController = TextEditingController();
@ -51,42 +46,42 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Regular expression to validate Full Name (no special characters) // Regular expression to validate Full Name (no special characters)
final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$"); final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$");
//late Future<RecordModel> userDetails; late Future<RecordModel> userDetails;
@override @override
// void initState() { void initState() {
// super.initState(); super.initState();
// print(widget.userId); print(widget.userId);
// _fetchUserData(); // Call the function to fetch user data _fetchUserData(); // Call the function to fetch user data
// } }
@override @override
// void dispose() { void dispose() {
// _fullNameController.dispose(); _fullNameController.dispose();
// _dateController.dispose(); _dateController.dispose();
// super.dispose(); super.dispose();
// } }
// Future<void> _fetchUserData() async { Future<void> _fetchUserData() async {
// try { try {
// final adminAuth = await _pb.admins final adminAuth = await _pb.admins
// .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
// final adminToken = adminAuth.token; final adminToken = adminAuth.token;
// final userDetailsResponse = await _pb.collection('users').getOne( final userDetailsResponse = await _pb.collection('users').getOne(
// widget.userId, widget.userId,
// headers: { headers: {
// 'Authorization': 'Bearer $adminToken', 'Authorization': 'Bearer $adminToken',
// }, },
// ); );
// print('userDetails: $userDetailsResponse'); print('userDetails: $userDetailsResponse');
// setState(() { setState(() {
// _usernameController.text = userDetailsResponse.data['username'] ?? ''; _usernameController.text = userDetailsResponse.data['username'] ?? '';
// _emailController.text = userDetailsResponse.data['email'] ?? ''; _emailController.text = userDetailsResponse.data['email'] ?? '';
// }); });
// } catch (e) { } catch (e) {
// print('Error fetching user details: $e'); print('Error fetching user details: $e');
// } }
// } }
void _pickImage() async { void _pickImage() async {
final XFile? pickedFile = final XFile? pickedFile =
@ -178,30 +173,30 @@ class _ProfileScreenState extends State<ProfileScreen> {
String formattedDob = DateFormat('yyyy-MM-dd').format(dob); String formattedDob = DateFormat('yyyy-MM-dd').format(dob);
// 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 other fields // Add other fields
// request.fields['full_name'] = fullName; request.fields['full_name'] = fullName;
// request.fields['dob'] = formattedDob; request.fields['dob'] = formattedDob;
// request.fields['country_region'] = countryRegion; request.fields['country_region'] = countryRegion;
// request.fields['is_profile_completed'] = 'True'; request.fields['is_profile_completed'] = 'True';
// Add the file, if available // Add the file, if available
// 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 (if required, e.g., authorization) // Add headers (if required, 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);
_resetFormFields(); _resetFormFields();
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile updated successfully!"))); SnackBar(content: Text("Profile updated successfully!")));
@ -520,7 +515,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
Center( Center(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
context.go('/changepass'); Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Changepassword()),
);
}, },
child: Text( child: Text(
"Change Password", "Change Password",
@ -533,18 +532,16 @@ class _ProfileScreenState extends State<ProfileScreen> {
SizedBox(height: 20), SizedBox(height: 20),
ElevatedButton.icon( ElevatedButton.icon(
onPressed: () { onPressed: () {
context.go('/myhomepage'); if ((_formKey.currentState?.validate() ?? false) &&
// if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
// (isChecked)) { _formKey.currentState?.save();
// _formKey.currentState?.save(); showConfirmationDialog(context);
// showConfirmationDialog(context); } else {
// } else { setState(() {
// setState(() { showError =
// showError = !isChecked; // Show error if the checkbox is not checked
// !isChecked; // Show error if the checkbox is not checked });
// }); }
// }
},
// if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
// _formKey.currentState?.save(); // _formKey.currentState?.save();
// showConfirmationDialog(context); // showConfirmationDialog(context);
@ -563,7 +560,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
// ); // );
//} //}
//} //}
//}, },
icon: Icon( icon: Icon(
Icons.save, Icons.save,
color: Colors.white, color: Colors.white,
@ -668,8 +665,7 @@ class ConfirmationDialog extends StatelessWidget {
), ),
), ),
ElevatedButton( ElevatedButton(
onPressed: () => context.go('/home'), onPressed: () => Navigator.of(context).pop(true),
//Navigator.of(context).pop(true),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF92722A), // Brown color backgroundColor: const Color(0xFF92722A), // Brown color
foregroundColor: Colors.white, foregroundColor: Colors.white,

View File

@ -1,3 +1,4 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -6,6 +7,7 @@ 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 '../../infrastructure/services/pocketbase_service.dart';
import '../routes/auth_routes/login_route.dart';
class RegisterScreen extends StatefulWidget { class RegisterScreen extends StatefulWidget {
@override @override
@ -17,6 +19,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
final _usernameController = TextEditingController(); final _usernameController = TextEditingController();
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _passwordController = TextEditingController(); final _passwordController = TextEditingController();
final _confirmpasswordController = TextEditingController();
bool _obscurePassword = true; bool _obscurePassword = true;
bool _obscureConfirmPassword = true; bool _obscureConfirmPassword = true;
bool isChecked = false; bool isChecked = false;
@ -25,56 +29,153 @@ class _RegisterScreenState extends State<RegisterScreen> {
bool registrationSuccess = false; bool registrationSuccess = false;
bool registrationFailed = false; bool registrationFailed = false;
dynamic userID; dynamic userID;
final pb = PocketBase('https://pb.venbait.in'); final pb = PocketBase('https://pb.venbait.in');
// final pb = PocketBase('http://127.0.0.1:8090'); // final pb = PocketBase('http://127.0.0.1:8090');
// Add focus nodes and hint states
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
final List<bool> _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 _passwordController.text;
if (index == 3) return _confirmpasswordController.text;
return '';
}
@override @override
void initState() { void initState() {
super.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 == 2) {
_passwordController.addListener(() {
setState(() {
_showHints[i] =
!_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
});
});
} else if (i == 3) {
_confirmpasswordController.addListener(() {
setState(() {
_showHints[i] =
!_focusNodes[i].hasFocus && (_getControllerText(i).isEmpty);
});
});
}
}
} }
@override @override
void dispose() { void dispose() {
for (var focusNode in _focusNodes) {
focusNode.dispose();
}
_usernameController.dispose(); _usernameController.dispose();
_emailController.dispose(); _emailController.dispose();
_passwordController.dispose(); _passwordController.dispose();
_confirmpasswordController.dispose();
super.dispose(); super.dispose();
} }
String? _validateUsername(String? value) { String? _validateUsername(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return 'Required';
} else if (RegExp(r'[^a-zA-Z0-9]').hasMatch(value)) { } else if (value.length > 40) {
return 'Must not exceed 40 characters';
} else if (!RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$")
.hasMatch(value)) {
return 'Invalid Characters'; return 'Invalid Characters';
} }
return null; return null;
} }
//else if (RegExp(r'[^a-zA-Z0-9]').hasMatch(value))
String? _validateEmail(String? value) { String? _validateEmail(String? value) {
// Regex to allow special characters, accented characters, and alphanumeric characters
final emailRegex =
r'^[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+@[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+\.[a-zA-Z]{2,}$';
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return 'Required';
} else if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) { } else if (!RegExp(emailRegex).hasMatch(value)) {
return 'Invalid Email'; return 'Invalid Email';
} }
return null; return null;
} }
String? _validatePassword(String? value) { String? _validatePassword(String? value) {
// Define the regular expression for allowed characters
final regex = RegExp(
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return 'Required';
} else if (value.length < 6) { } else if (value.length < 8) {
return 'Password must be at least 6 characters'; 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 _password = value; // Store the password for confirm password validation
return null; return null;
} }
String? _validateConfirmPassword(String? value) { String? _validateConfirmPassword(String? value) {
// Define the regular expression for allowed characters
final regex = RegExp(
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return 'Required';
} else if (value.length < 8 || value.length > 40) {
return 'Password must be at least 8characters';
} else if (!regex.hasMatch(value)) {
return 'Password contains invalid characters';
} else if (value != _password) { } else if (value != _password) {
return 'Passwords do not match'; return 'Passwords do not match';
} }
return null; return null;
} }
@ -84,14 +185,16 @@ class _RegisterScreenState extends State<RegisterScreen> {
try { try {
final adminAuth = await pb.admins final adminAuth = await pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token; final adminToken = adminAuth.token;
print('adminToken- ${adminToken}');
// Create user in PocketBase // Create user in PocketBase
final response = await pb.collection('users').create(body: { final response = await pb.collection('users').create(body: {
'username': _usernameController.text, 'username': _usernameController.text,
'email': _emailController.text, 'email': _emailController.text,
'password': _passwordController.text, 'password': _passwordController.text,
'passwordConfirm': _passwordController 'passwordConfirm': _passwordController.text,
.text, // PocketBase requires password confirmation // 'verified': true,
}, headers: { }, headers: {
'Authorization': adminToken 'Authorization': adminToken
}); });
@ -194,9 +297,10 @@ class _RegisterScreenState extends State<RegisterScreen> {
onPressed: () => { onPressed: () => {
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute( MaterialPageRoute(builder: (context) => LoginRoute()
builder: (context) =>
ProfileScreen(userId: userID)), //ProfileScreen(userId: userID)
),
), ),
}, },
child: Text( child: Text(
@ -247,9 +351,17 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
ElevatedButton( ElevatedButton(
onPressed: () => context.go( onPressed: () => {
'/${context.language}/login', setState(() {
), registrationFailed = false;
registrationSuccess = false;
_usernameController.clear();
_emailController.clear();
_passwordController.clear();
_confirmpasswordController.clear();
isChecked = false;
})
},
child: Text( child: Text(
'Retry', 'Retry',
), ),
@ -286,12 +398,14 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text('Please enter your details'), Text('Please enter your details'),
SizedBox(height: 20), SizedBox(height: 20),
// Display this if registration is pending approval // Display this if registration is pending approval
TextFormField( TextFormField(
controller: _usernameController, controller: _usernameController,
focusNode: _focusNodes[0],
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Username', hintText: _showHints[0] ? 'Username' : null,
prefixIcon: Icon( prefixIcon: Icon(
Icons.person, Icons.person,
color: Colors.blue, color: Colors.blue,
@ -307,22 +421,34 @@ class _RegisterScreenState extends State<RegisterScreen> {
SizedBox(height: 15), SizedBox(height: 15),
TextFormField( TextFormField(
controller: _emailController, controller: _emailController,
focusNode: _focusNodes[1],
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Enter your email', // hintText: 'Enter your email',
hintText:
_showHints[1] ? 'Enter your email' : null,
prefixIcon: Icon( prefixIcon: Icon(
Icons.email, Icons.email,
color: Colors.blue, color: Colors.blue,
), ),
border: OutlineInputBorder(), border: OutlineInputBorder(),
counterText: '',
), ),
validator: _validateEmail, validator: _validateEmail,
maxLength: 320,
maxLengthEnforcement: MaxLengthEnforcement.enforced,
inputFormatters: [
LengthLimitingTextInputFormatter(
320), // Limit to 320 characters
],
), ),
SizedBox(height: 15), SizedBox(height: 15),
TextFormField( TextFormField(
controller: _passwordController, controller: _passwordController,
focusNode: _focusNodes[2],
obscureText: _obscurePassword, obscureText: _obscurePassword,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Enter your password', hintText:
_showHints[2] ? 'Enter your password' : null,
prefixIcon: Icon( prefixIcon: Icon(
Icons.lock, Icons.lock,
color: Colors.blue, color: Colors.blue,
@ -341,14 +467,20 @@ class _RegisterScreenState extends State<RegisterScreen> {
}, },
), ),
border: OutlineInputBorder(), border: OutlineInputBorder(),
counterText: '',
), ),
validator: _validatePassword, validator: _validatePassword,
maxLength: 40,
maxLengthEnforcement: MaxLengthEnforcement.enforced,
), ),
SizedBox(height: 15), SizedBox(height: 15),
TextFormField( TextFormField(
controller: _confirmpasswordController,
focusNode: _focusNodes[3],
obscureText: _obscureConfirmPassword, obscureText: _obscureConfirmPassword,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Confirm password', hintText:
_showHints[3] ? 'Confirm password' : null,
prefixIcon: Icon( prefixIcon: Icon(
Icons.lock, Icons.lock,
color: Colors.blue, color: Colors.blue,
@ -368,8 +500,15 @@ class _RegisterScreenState extends State<RegisterScreen> {
}, },
), ),
border: OutlineInputBorder(), border: OutlineInputBorder(),
counterText: '',
), ),
validator: _validateConfirmPassword, validator: _validateConfirmPassword,
maxLength: 40,
maxLengthEnforcement: MaxLengthEnforcement.enforced,
inputFormatters: [
LengthLimitingTextInputFormatter(
64), // Limit to 40 characters
],
), ),
SizedBox(height: 10), SizedBox(height: 10),
Row( Row(
@ -414,7 +553,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: Text( child: Text(
'Required', 'Please agree to terms and conditions.',
style: TextStyle( style: TextStyle(
color: Colors.red[700], color: Colors.red[700],
fontSize: 12, fontSize: 12,
@ -470,18 +609,48 @@ class _RegisterScreenState extends State<RegisterScreen> {
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
), ),
child: Row( // child: Row(
mainAxisSize: MainAxisSize.min, // mainAxisSize: MainAxisSize.min,
children: [ // children: [
Text( // Text(
"Login", // "Login",
style: TextStyle( // style: TextStyle(
fontSize: 16, color: Colors.white), // fontSize: 16, color: Colors.white
), // ),
SizedBox(width: 8), //
Icon(Icons.arrow_forward, //
color: Colors.white), // ),
], // SizedBox(width: 8),
// Icon(Icons.arrow_forward,
// color: Colors.white),
// ],
// ),
child: GestureDetector(
onTap: () {
// Navigate to LoginRoute
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginRoute()),
// MaterialPageRoute(builder: (context) => LoginRoute(userId: userID)),
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Login",
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
SizedBox(width: 8),
Icon(Icons.arrow_forward,
color: Colors.white),
],
),
), ),
), ),
), ),

View File

@ -9,18 +9,57 @@ import 'package:uae_stat/domain/use_cases/auth_use_case.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart';
import 'package:uae_stat/presentation/Screens/demo_home.dart';
import 'package:uae_stat/presentation/components/dialogs.dart'; import 'package:uae_stat/presentation/components/dialogs.dart';
import 'package:uae_stat/presentation/components/lang_toggle.dart'; import 'package:uae_stat/presentation/components/lang_toggle.dart';
import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart';
import 'package:uae_stat/presentation/components/space.dart'; import 'package:uae_stat/presentation/components/space.dart';
import 'package:uae_stat/presentation/components/themed_text_field.dart'; import 'package:uae_stat/presentation/components/themed_text_field.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/profile/profile_route.dart'; import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import '../../Screens/profilepage.dart';
import '../../Screens/registration.dart';
import 'package:pocketbase/pocketbase.dart';
class LoginRoute extends HookConsumerWidget { class LoginRoute extends HookConsumerWidget {
const LoginRoute({super.key}); final pb = PocketBase('https://pb.venbait.in');
// final _pb = PocketBase('http://127.0.0.1:8090');
LoginRoute({super.key});
static final formKey = GlobalKey<FormState>(); static final formKey = GlobalKey<FormState>();
Future<bool> profileStatus(String userId) async {
try {
// Authenticate admin
final adminAuth = await pb.admins.authWithPassword(
'pb@venbainfotech.com',
'pb@venbainfotech.com',
);
final String adminToken = adminAuth.token;
print('adminToken: $adminToken');
// Fetch user details
final userDetailsResponse = await pb.collection('users').getOne(
userId,
headers: {
'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
}
} catch (e) {
print('Error fetching user details: $e');
return false; // Return false on error
}
}
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final emailCtl = useTextEditingController(); final emailCtl = useTextEditingController();
@ -119,76 +158,95 @@ class LoginRoute extends HookConsumerWidget {
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
// final isValid = formKey.currentState!.validate(); final isValid = formKey.currentState!.validate();
// if (!isValid) return; if (!isValid) return;
// await context.loaderWithErrorDialog( final session = await context.loaderWithErrorDialog(
// () => ref () => ref
// .read( .read(
// authUseCaseProvider.notifier, authUseCaseProvider.notifier,
// ) )
// .login( .login(
// emailCtl.text, emailCtl.text,
// pwCtl.text, pwCtl.text,
// ), ),
// errorDialogBuilder: ( errorDialogBuilder: (
// error, [ error, [
// StackTrace? stackTrace, StackTrace? stackTrace,
// ]) { ]) {
// if (error == LoginError.invalidEmailPw) { if (error == LoginError.invalidEmailPw) {
// return context.simpleDialog( return context.simpleDialog(
// title: context.translate( title: context.translate(
// 'Incorrect credentials', 'Incorrect credentials',
// 'أوراق غير صحيحة', 'أوراق غير صحيحة',
// ), ),
// content: context.translate( content: context.translate(
// 'Your email or password is invalid. Please try again.', 'Your email or password is invalid. Please try again.',
// 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.', 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.',
// ), ),
// ); );
// } }
// if (error == LoginError.emailAddressNotVerified) { if (error == LoginError.emailAddressNotVerified) {
// return context.simpleDialog( return context.simpleDialog(
// title: context.translate( title: context.translate(
// 'Verification Error', 'Verification Error',
// 'خطأ التحقق', 'خطأ التحقق',
// ), ),
// content: context.translate( content: context.translate(
// '${emailCtl.text} is not a verified email address. Please check your email for a verification link.', '${emailCtl.text} is not a verified email address. Please check your email for a verification link.',
// '${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.', '${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.',
// ), ),
// extraAction: ElevatedButton( extraAction: ElevatedButton(
// onPressed: () async { onPressed: () async {
// Navigator.of( Navigator.of(
// context, context,
// rootNavigator: true, rootNavigator: true,
// ).pop(); ).pop();
// await context.loaderWithErrorDialog( await context.loaderWithErrorDialog(
// () => ref () => ref
// .read(authUseCaseProvider.notifier) .read(authUseCaseProvider.notifier)
// .requestVerificationEmail(emailCtl.text), .requestVerificationEmail(emailCtl.text),
// ); );
// if (!context.mounted) return; if (!context.mounted) return;
// context.simpleDialog( context.simpleDialog(
// title: 'Email Re-sent', title: 'Email Re-sent',
// content: content:
// 'We\'ve sent you the verification email at ${emailCtl.text} again.', 'We\'ve sent you the verification email at ${emailCtl.text} again.',
// ); );
// }, },
// child: Text( child: Text(
// context.translate( context.translate(
// 'I did not receive an email', 'I did not receive an email',
// 'لم أتلق بريدًا إلكترونيًا', 'لم أتلق بريدًا إلكترونيًا',
// ), ),
// ), ),
// ), ),
// ); );
// } }
// return context.simpleDialog(); return context.simpleDialog();
// }, },
// ); );
// if (!context.mounted) return; 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}'); // context.go('/${context.language}/${BottomNavBarItem.home.routePath}');
context.go('/Profile');
}, },
style: ButtonStyle( style: ButtonStyle(
shape: WidgetStatePropertyAll( shape: WidgetStatePropertyAll(
@ -224,7 +282,7 @@ class LoginRoute extends HookConsumerWidget {
children: [ children: [
Text( Text(
context.translate( context.translate(
'Login log', 'Login',
'تسجيل الدخول', 'تسجيل الدخول',
), ),
), ),
@ -309,7 +367,12 @@ class LoginRoute extends HookConsumerWidget {
], ],
); );
final dontHaveAnAccountRegisterBtn = TextButton( final dontHaveAnAccountRegisterBtn = TextButton(
onPressed: () => context.go('/${context.language}/register'), onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => RegisterScreen()),
),
},
child: Text.rich( child: Text.rich(
textAlign: TextAlign.center, textAlign: TextAlign.center,
TextSpan( TextSpan(