551 lines
18 KiB
Dart
551 lines
18 KiB
Dart
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 UAE’s 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;
|
||
}
|
||
}
|