uaestats_fe/lib/presentation/routes/auth_routes/login_route.dart
2025-01-17 15:46:29 +05:30

551 lines
18 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:external_repos/external_repos.dart';
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';
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/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/lang_toggle.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/themed_text_field.dart';
import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import '../../Screens/auth_verification/registration.dart';
import 'package:pocketbase/pocketbase.dart';
import '../../components/indicators/locale_provider.dart';
import '../../components/my_toggle.dart';
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;
String? role;
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 user is verified
role = userDetailsResponse.data['role'];
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');
rethrow;
}
}
Future<void> 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 locale = ref.watch(localeProvider);
final emailCtl = useTextEditingController();
final pwCtl = useTextEditingController();
final forgotPwBtn = TextButton(
onPressed: () async {
final forgotPwFormKey = GlobalKey<FormState>();
final email = await showDialog<String>(
context: context,
builder: (dialogCtx) => AlertDialog(
title: Text(
context.translate(
'Reset Password',
'إعادة تعيين كلمة المرور',
),
),
content: Form(
key: forgotPwFormKey,
child: TextFormField(
validator: FieldValidator.email(),
controller: emailCtl,
decoration: InputDecoration(
labelText: context.translate(
'Email address',
'عنوان البريد الإلكتروني',
),
),
),
),
actions: [
TextButton(
onPressed: Navigator.of(dialogCtx, rootNavigator: true).pop,
child: Text(
context.translate(
'Return',
'يعود',
),
),
),
ElevatedButton(
onPressed: () {
final isValid = forgotPwFormKey.currentState!.validate();
if (!isValid) return;
Navigator.of(dialogCtx, rootNavigator: true).pop(
emailCtl.text,
);
},
child: Text(
context.translate(
'Send Reset Email',
'إرسال إعادة تعيين البريد الإلكتروني',
),
),
),
],
),
);
if (email == null) return;
if (!context.mounted) return;
await context.loaderWithErrorDialog(
() => ref
.read(
authUseCaseProvider.notifier,
)
.requestPwReset(email),
);
if (!context.mounted) return;
context.simpleDialog(
title: context.translate(
'Success!',
'نجاح',
),
content: context.translate(
'An email has been sent to $email with further details.',
'تم إرسال بريد إلكتروني إلى $email يتضمن المزيد من التفاصيل.',
),
);
},
child: Text(
context.translate(
'Forgot Password?',
'هل نسيت كلمة السر؟',
),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontWeight: FontWeight.bold,
fontSize: 14,
color: MyTheme.topicColor(IndicatorTopic.economy).shade600,
),
),
);
final loginBtn = SizedBox(
width: double.infinity,
child: ElevatedButton(
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');
// if (role == 'admin') {
// context.go('/myhomepage');
// } else {
// context.go('/myhomepage');
// }
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}');
},
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),
],
),
),
);
final form = Form(
key: formKey,
child: Column(
children: [
ThemedFormField(
hintText: context.translate(
'Email',
'بريد إلكتروني',
),
validator: FieldValidator.email(),
imgPath: MiscIconAssetPath.person,
controller: emailCtl,
),
15.verticalSpace,
ThemedFormField(
validator: (text) {
if (text!.length < 8) {
return 'The password must be at least 8 characters';
}
return FieldValidator.password(minLength: 8)(text);
},
hintText: context.translate(
'Password',
'كلمة المرور',
),
imgPath: MiscIconAssetPath.lock,
controller: pwCtl,
isObscurable: true,
),
// 6.verticalSpace,
Align(
alignment: AlignmentDirectional.topEnd,
child: forgotPwBtn,
),
10.verticalSpace,
loginBtn,
],
),
);
final helloAndPleaseLoginTexts = Column(
children: [
Text(
context.translate(
'Hello Again!',
'مرحبا مجددا!',
),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 40,
fontWeight: FontWeight.w300,
),
),
10.verticalSpace,
Text(
context.translate(
'Please login to access UAEs key official statistics',
'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة',
),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 18,
color: const Color(0xff898C81),
fontWeight: FontWeight.w700,
),
),
],
);
final dontHaveAnAccountRegisterBtn = TextButton(
onPressed: () => {context.go('/register')},
child: Text.rich(
textAlign: TextAlign.center,
TextSpan(
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 18,
fontWeight: FontWeight.bold,
),
children: [
TextSpan(
text: context.translate(
'Don\'t have an account? ',
'ليس لديك حساب؟',
),
style: const TextStyle(
color: Color(0xff898C81),
),
),
const TextSpan(
text: ' ',
),
TextSpan(
text: context.translate(
'Register Now',
'سجل الان',
),
style: TextStyle(
color: MyTheme.topicColor(IndicatorTopic.economy).shade600,
),
),
],
),
),
);
final continueAsGuestBtn = SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () =>
context.go('/myhomepage'),
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 10.5),
),
textStyle: WidgetStatePropertyAll(
TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
backgroundColor: WidgetStatePropertyAll(
MyTheme.topicColor(IndicatorTopic.environment),
),
foregroundColor: const WidgetStatePropertyAll(
Colors.white,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.translate(
'Continue as Guest',
'استمر كضيف',
),
),
6.horizontalSpace,
const Icon(Icons.chevron_right_outlined),
],
),
),
);
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
);
final screenWidth = MediaQuery.of(context).size.width;
final listViewHorizontalPadding =
screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2;
final scaffoldBody = ListView(
padding: EdgeInsets.symmetric(
horizontal: listViewHorizontalPadding.toDouble(),
),
children: [
36.verticalSpace,
Align(
alignment: AlignmentDirectional.topEnd,
child: MyToggle(isOn: locale?.languageCode == 'en',
knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300,
onTap: (){
ref.read(localeProvider.notifier).toggleLocale();
},),
),
16.verticalSpace,
helloAndPleaseLoginTexts,
42.verticalSpace,
form,
20.verticalSpace,
dontHaveAnAccountRegisterBtn,
36.verticalSpace,
continueAsGuestBtn,
72.verticalSpace,
fcscBanner,
],
);
final bgScaffold = Scaffold(
backgroundColor: Colors.white,
body: SafeArea(child: scaffoldBody),
);
return bgScaffold;
}
}