1489 lines
57 KiB
Dart
1489 lines
57 KiB
Dart
import 'dart:convert';
|
||
import 'dart:io';
|
||
|
||
import 'package:firebase_auth/firebase_auth.dart';
|
||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||
import 'package:flutter/gestures.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:google_fonts/google_fonts.dart';
|
||
import 'package:http/http.dart' as http;
|
||
import 'package:jwt_decode/jwt_decode.dart';
|
||
import 'package:nhance_partner/core/config/env.dart';
|
||
import 'package:nhance_partner/core/services/platform_helper.dart';
|
||
import 'package:nhance_partner/data/utils/validators.dart';
|
||
import 'package:pinput/pinput.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import '../../../core/routing/routes.dart';
|
||
import '../../../data/services/auth_service.dart';
|
||
import '../../../data/utils/commonLoaderButton.dart';
|
||
import '../../../data/utils/toastNotification.dart';
|
||
import '../../layouts/responsive_layout.dart';
|
||
import '../../providers/manager_provider.dart';
|
||
import '../../providers/userRoleProvider.dart';
|
||
import '../../themes/indicators/text_field_theme.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
class LoginScreen extends ConsumerStatefulWidget {
|
||
const LoginScreen({super.key});
|
||
|
||
@override
|
||
ConsumerState<LoginScreen> createState() => _LoginScreenState();
|
||
}
|
||
|
||
class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
final TextEditingController _emailController = TextEditingController();
|
||
final TextEditingController _PhoneNumberController = TextEditingController();
|
||
final TextEditingController _otpController = TextEditingController();
|
||
final TextEditingController _countryController = TextEditingController();
|
||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||
late String _verificationId;
|
||
int? _resendToken;
|
||
bool _isLoading = false;
|
||
bool _obscurePassword = true;
|
||
int switcherStatus = 1;
|
||
int selectedIndex = 1;
|
||
bool enteredEmailOrMobile = false;
|
||
dynamic clickedButtonName;
|
||
dynamic token;
|
||
dynamic fCMToken;
|
||
|
||
// Future<void> _handleLogin() async {
|
||
// if (!_formKey.currentState!.validate()) return;
|
||
//
|
||
// setState(() => _isLoading = true);
|
||
//
|
||
// // Simulate API call
|
||
// await Future.delayed(const Duration(seconds: 2));
|
||
//
|
||
// // TODO: Replace with your AuthService
|
||
// final success =
|
||
// _emailController.text == "test@example.com" &&
|
||
// // _passwordController.text == "password";
|
||
//
|
||
// // setState(() => _isLoading = false);
|
||
//
|
||
// print("Succes - $success");
|
||
// if (success) {
|
||
// print("Ckeck 1");
|
||
// if (mounted) {
|
||
// print("Ckeck 2");
|
||
// await AuthService.saveToken('1234');
|
||
// final dynamic token = AuthService.saveToken('1234');
|
||
// print('token - $token');
|
||
//
|
||
// print('AppRoutes.home');
|
||
// context.go(AppRoutes.home);
|
||
// print("Ckeck 3");
|
||
// }
|
||
// } else {
|
||
// if (mounted) {
|
||
// ScaffoldMessenger.of(
|
||
// context,
|
||
// ).showSnackBar(const SnackBar(content: Text("Invalid credentials")));
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
final defaultPinTheme = PinTheme(
|
||
width: 56,
|
||
height: 56,
|
||
textStyle: TextStyle(
|
||
fontSize: 20,
|
||
color: Color.fromRGBO(30, 60, 87, 1),
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
decoration: BoxDecoration(
|
||
border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
);
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_countryController.text = "+91";
|
||
}
|
||
|
||
Future<void> initNotification() async {
|
||
try {
|
||
// await _firebaseMessaging.requestPermission();
|
||
fCMToken = await FirebaseMessaging.instance.getToken();
|
||
print('Token : $fCMToken');
|
||
|
||
if (fCMToken != null) {
|
||
// await sendDeviceToken(fCMToken);
|
||
}
|
||
} catch (e) {
|
||
print("Error getting FCM Token: $e");
|
||
}
|
||
}
|
||
|
||
Future<void> _saveUserRole(String token) async {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
final decodedToken = Jwt.parseJwt(token);
|
||
final Map<String, dynamic>? data = decodedToken['data'];
|
||
|
||
String role;
|
||
|
||
if (data == null || !data.containsKey('role_id')) {
|
||
role = "agent";
|
||
} else {
|
||
final dynamic roleId = data['role_id'];
|
||
|
||
if (roleId.toString() == "1") {
|
||
role = "manager";
|
||
} else if (roleId.toString() == "2") {
|
||
role = "staff";
|
||
} else {
|
||
role = "agent"; // fallback if unexpected value
|
||
}
|
||
}
|
||
|
||
// Save globally
|
||
ref.read(userRoleProvider.notifier).state = role;
|
||
print("✅ User role set globally: $role");
|
||
await prefs.setString('userRole', role);
|
||
// final userRole = ref.watch(userRoleProvider);
|
||
}
|
||
|
||
Future<void> _saveIdsFromToken(String token) async {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
final Map<String, dynamic> decodedToken = Jwt.parseJwt(token);
|
||
print('decodedToken : $decodedToken');
|
||
|
||
final dynamic data = decodedToken['data'];
|
||
|
||
if (data != null) {
|
||
// Manager ID
|
||
final dynamic managerIdRaw = data['manager_id'];
|
||
final int? managerId = managerIdRaw is int
|
||
? managerIdRaw
|
||
: int.tryParse(managerIdRaw.toString());
|
||
|
||
if (managerId != null) {
|
||
ref.read(managerIdProvider.notifier).state = managerId;
|
||
print("✅ Manager ID saved globally: $managerId");
|
||
await prefs.setInt('managerId', managerId);
|
||
} else {
|
||
print("⚠️ Manager ID is null or invalid");
|
||
}
|
||
|
||
// User ID
|
||
final dynamic userIdRaw = data['id'];
|
||
final int? userId = userIdRaw is int
|
||
? userIdRaw
|
||
: int.tryParse(userIdRaw.toString());
|
||
|
||
if (userId != null) {
|
||
ref.read(userIdProvider.notifier).state = userId;
|
||
print("✅ User ID saved globally: $userId");
|
||
await prefs.setInt('userId', userId);
|
||
} else {
|
||
print("⚠️ User ID is null or invalid");
|
||
}
|
||
} else {
|
||
print("⚠️ No data found in decodedToken");
|
||
}
|
||
|
||
// final managerId = ref.watch(managerIdProvider);
|
||
// final userId = ref.watch(userIdProvider);
|
||
}
|
||
|
||
// Future<void> _saveManagerId(String token) async {
|
||
// Map<String, dynamic>? decodedToken = await Jwt.parseJwt(token);
|
||
// print('decodedToken : $decodedToken');
|
||
// final dynamic managerIdRaw = decodedToken['data']?['manager_id'];
|
||
// final int? managerId = managerIdRaw is int
|
||
// ? managerIdRaw
|
||
// : int.tryParse(managerIdRaw.toString());
|
||
//
|
||
// if (managerId != null) {
|
||
// ref.read(managerIdProvider.notifier).state = managerId;
|
||
// print("Manager ID saved globally: $managerId");
|
||
// } else {
|
||
// print("Manager ID is null or invalid");
|
||
// }
|
||
// print(managerId);
|
||
// // final managerId = ref.watch(managerIdProvider);
|
||
// }
|
||
|
||
Future<bool> sendMobileOrEmailVerify(String loginUser) async {
|
||
// await Future.delayed(const Duration(seconds: 5));
|
||
try {
|
||
if (_formKey.currentState!.validate()) {
|
||
String apiEndpoint;
|
||
if (loginUser == 'agent') {
|
||
apiEndpoint = switcherStatus == 1
|
||
? Env.apiUrl + 'auth/verifyAgentWithMobileNumber'
|
||
: Env.apiUrl + 'auth/verifyAgentWithEmailId';
|
||
} else {
|
||
apiEndpoint = switcherStatus == 1
|
||
? Env.apiUrl + 'auth/verifyStaffWithMobileNumber'
|
||
: Env.apiUrl + 'auth/verifyStaffWithEmailId';
|
||
}
|
||
|
||
Map<String, dynamic> payload = switcherStatus == 1
|
||
? {'mobile': _PhoneNumberController.text}
|
||
: {'email': _emailController.text};
|
||
|
||
final response = await http.post(
|
||
Uri.parse(apiEndpoint),
|
||
body: json.encode(payload),
|
||
headers: {
|
||
HttpHeaders.contentTypeHeader: 'application/json',
|
||
'App-Signature': Env.App_Signature,
|
||
},
|
||
);
|
||
|
||
if (response.statusCode == 200) {
|
||
final data = json.decode(response.body);
|
||
|
||
final verification = loginUser == 'agent'
|
||
? data['data']['agent_verification']
|
||
: data['data']['Staff_verification'];
|
||
|
||
final message = data['data']['message'];
|
||
|
||
if (verification == true) {
|
||
if (switcherStatus == 1) {
|
||
_verifyPhoneNumber();
|
||
} else {
|
||
setState(() {
|
||
enteredEmailOrMobile = true;
|
||
});
|
||
ToastHelper.showSuccessToast(context, 'OTP sent successfully');
|
||
}
|
||
return true; // ✅ success
|
||
} else {
|
||
ToastHelper.showErrorToast(context, message);
|
||
return false; // ❌ fail
|
||
}
|
||
} else {
|
||
ToastHelper.showErrorToast(context, 'Something went wrong');
|
||
return false; // ❌ fail
|
||
}
|
||
}
|
||
return false;
|
||
} catch (e) {
|
||
ToastHelper.showErrorToast(context, 'Something went wrong');
|
||
print('Error: $e');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
Future<void> verifyMobileOrMailOTP(otpVerifyStatus) async {
|
||
try {
|
||
// Select API endpoint
|
||
final String apiEndpoint = (clickedButtonName == 'agent')
|
||
? '${Env.apiUrl}auth/getVerifiedAgentData'
|
||
: '${Env.apiUrl}auth/getVerifiedStaffData';
|
||
|
||
// Build payload depending on switcher status
|
||
final Map<String, dynamic> payload = (switcherStatus == 1)
|
||
? {
|
||
'otp_verification': otpVerifyStatus,
|
||
'mobile': _PhoneNumberController.text.trim(),
|
||
}
|
||
: {'otp': otpVerifyStatus, 'email': _emailController.text.trim()};
|
||
|
||
// Send request
|
||
final response = await http.post(
|
||
Uri.parse(apiEndpoint),
|
||
body: json.encode(payload),
|
||
headers: {
|
||
HttpHeaders.contentTypeHeader: 'application/json',
|
||
'App-Signature': Env.App_Signature,
|
||
},
|
||
);
|
||
|
||
// Check response
|
||
if (response.statusCode == 200) {
|
||
final Map<String, dynamic> data = json.decode(response.body);
|
||
|
||
final String status = data['status']?.toString() ?? 'error';
|
||
token = data['data']; // can be string or object
|
||
|
||
print('Response status: ${response.statusCode}');
|
||
print('Response body: $data');
|
||
|
||
if (status == 'success') {
|
||
ToastHelper.showSuccessToast(context, 'OTP verified successfully');
|
||
await AuthService.saveToken(token);
|
||
await _saveUserRole(token);
|
||
await _saveIdsFromToken(token);
|
||
final managerId = ref.watch(managerIdProvider);
|
||
print('managerId -- $managerId');
|
||
final userRole = ref.watch(userRoleProvider);
|
||
print('userRole -- $userRole');
|
||
context.go(AppRoutes.dashboard);
|
||
} else {
|
||
ToastHelper.showErrorToast(context, data['message'] ?? 'Invalid OTP');
|
||
}
|
||
} else {
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'Server error: ${response.statusCode}',
|
||
);
|
||
}
|
||
} catch (e, stacktrace) {
|
||
print('Error verifying OTP: $e');
|
||
print(stacktrace);
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'Something went wrong. Please try again.',
|
||
);
|
||
}
|
||
}
|
||
|
||
Future<void> verifyFirebaseMobileOTP() async {
|
||
try {
|
||
// setState(() {
|
||
// _isLoading = true;
|
||
// });
|
||
// Later, in verify screen:
|
||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
dynamic verificationId = prefs.getString('verificationId');
|
||
|
||
final credential = PhoneAuthProvider.credential(
|
||
verificationId: verificationId, // Make sure this is up-to-date
|
||
smsCode: _otpController.text,
|
||
);
|
||
|
||
print('credential $credential');
|
||
|
||
final userCredential = await FirebaseAuth.instance.signInWithCredential(
|
||
credential,
|
||
);
|
||
// await FirebaseAuth.instance.signInWithCredential(credential);
|
||
print('otp firebase check');
|
||
|
||
if (userCredential.user != null) {
|
||
print('otp firebase check done');
|
||
bool otpVerifyStatus = true;
|
||
await verifyMobileOrMailOTP(otpVerifyStatus);
|
||
} else {
|
||
ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again.');
|
||
}
|
||
|
||
// await FirebaseAuth.instance.signInWithCredential(credential).then((userCredential) async {
|
||
// if (userCredential.user != null) {
|
||
// bool otpVerifyStatus = true;
|
||
// generateToken(otpVerifyStatus);
|
||
// } else {
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
// ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again');
|
||
// }
|
||
// });
|
||
} on FirebaseAuthException catch (e) {
|
||
if (e.code == 'code-expired') {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('OTP expired. Please request a new one.'),
|
||
duration: Duration(seconds: 2),
|
||
),
|
||
);
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'OTP expired. Please request a new one.',
|
||
);
|
||
} else if (e.code == 'invalid-verification-code') {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('Invalid OTP entered. Please try again.'),
|
||
duration: Duration(seconds: 2),
|
||
),
|
||
);
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'Invalid OTP entered. Please try again.',
|
||
);
|
||
} else if (e.code == 'session-expired') {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('Session expired. Try restarting the verification.'),
|
||
duration: Duration(seconds: 2),
|
||
),
|
||
);
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'Session expired. Try restarting the verification.',
|
||
);
|
||
} else {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('Error: ${e.message}'),
|
||
duration: Duration(seconds: 2),
|
||
),
|
||
);
|
||
ToastHelper.showErrorToast(context, 'Error: ${e.message}');
|
||
}
|
||
} catch (e) {
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
print('Error: $e');
|
||
ToastHelper.showErrorToast(
|
||
context,
|
||
'Failed to verify OTP. Please try again.',
|
||
);
|
||
}
|
||
}
|
||
|
||
Future<void> _verifyPhoneNumber() async {
|
||
var enteredMobileNumber = _PhoneNumberController.text;
|
||
var countryCode = _countryController.text;
|
||
print('${countryCode + enteredMobileNumber}');
|
||
await _auth.verifyPhoneNumber(
|
||
phoneNumber: '${countryCode + enteredMobileNumber}',
|
||
timeout: const Duration(seconds: 60),
|
||
verificationCompleted: (PhoneAuthCredential credential) async {
|
||
await _auth.signInWithCredential(credential);
|
||
// ToastHelper.showSuccessToast(context, 'Verified Successfully!');
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
},
|
||
verificationFailed: (FirebaseAuthException e) {
|
||
print('Verification Failed: ${e.code} - ${e.message}');
|
||
String errorMessage;
|
||
if (e.code == 'invalid-app-credential') {
|
||
errorMessage = 'Invalid Credential. Please try again.';
|
||
} else if (e.code == 'invalid-phone-number') {
|
||
errorMessage = 'The provided phone number is not valid.';
|
||
} else if (e.code == 'too-many-requests') {
|
||
errorMessage = 'Too many requests. Try again later.';
|
||
} else {
|
||
errorMessage = 'Verification Failed: ${e.message}';
|
||
}
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(content: Text(errorMessage), duration: Duration(seconds: 2)),
|
||
);
|
||
|
||
ToastHelper.showSuccessToast(context, errorMessage);
|
||
setState(() {
|
||
_isLoading = false;
|
||
});
|
||
},
|
||
codeSent: (String verificationId, int? resendToken) async {
|
||
setState(() {
|
||
_verificationId = verificationId;
|
||
_resendToken = resendToken;
|
||
});
|
||
|
||
// When getting the verificationId
|
||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
prefs.setString('verificationId', _verificationId);
|
||
|
||
setState(() {
|
||
enteredEmailOrMobile = true;
|
||
});
|
||
ToastHelper.showSuccessToast(
|
||
context,
|
||
'Verification code sent to ${enteredMobileNumber}',
|
||
);
|
||
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
},
|
||
codeAutoRetrievalTimeout: (String verificationId) async {
|
||
setState(() {
|
||
_verificationId = verificationId;
|
||
});
|
||
final prefs = await SharedPreferences.getInstance();
|
||
await prefs.setString('verificationId', verificationId);
|
||
ToastHelper.showSuccessToast(context, 'Code auto-retrieval timed out.');
|
||
setState(() {
|
||
_isLoading = false;
|
||
});
|
||
},
|
||
);
|
||
}
|
||
|
||
void _resendCode(String mobileNumber, int? resendToken) async {
|
||
await _auth.verifyPhoneNumber(
|
||
phoneNumber: '${_countryController.text + mobileNumber}',
|
||
timeout: const Duration(seconds: 60),
|
||
forceResendingToken: resendToken,
|
||
verificationCompleted: (PhoneAuthCredential credential) async {
|
||
await _auth.signInWithCredential(credential);
|
||
},
|
||
verificationFailed: (FirebaseAuthException e) {
|
||
if (e.code == 'invalid-phone-number') {
|
||
print('The provided phone number is not valid.');
|
||
}
|
||
},
|
||
codeSent: (String verificationId, int? resendToken) async {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
await prefs.setString('verificationId', verificationId);
|
||
setState(() {
|
||
_verificationId = verificationId;
|
||
_resendToken = resendToken;
|
||
});
|
||
ToastHelper.showSuccessToast(
|
||
context,
|
||
'Verification code resent to ${mobileNumber}',
|
||
);
|
||
},
|
||
codeAutoRetrievalTimeout: (String verificationId) async {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
await prefs.setString('verificationId', verificationId);
|
||
setState(() {
|
||
_verificationId = verificationId;
|
||
});
|
||
},
|
||
);
|
||
}
|
||
|
||
// Future<void> _verifyPhoneNumber() async {
|
||
// var enteredMobileNumber = mobileController.text;
|
||
// var countryCode = countryController.text;
|
||
// print('${countryCode + enteredMobileNumber}');
|
||
// await _auth.verifyPhoneNumber(
|
||
// phoneNumber: '${countryCode + enteredMobileNumber}',
|
||
// timeout: const Duration(seconds: 60),
|
||
// verificationCompleted: (PhoneAuthCredential credential) async {
|
||
// await _auth.signInWithCredential(credential);
|
||
// // ToastHelper.showSuccessToast(context, 'Verified Successfully!');
|
||
// // setState(() {
|
||
// // _isLoading = false;
|
||
// // });
|
||
// },
|
||
// verificationFailed: (FirebaseAuthException e) {
|
||
// print('Verification Failed: ${e.code} - ${e.message}');
|
||
// String errorMessage;
|
||
// if (e.code == 'invalid-app-credential') {
|
||
// errorMessage = 'Invalid Credential. Please try again.';
|
||
// } else if (e.code == 'invalid-phone-number') {
|
||
// errorMessage = 'The provided phone number is not valid.';
|
||
// } else if (e.code == 'too-many-requests') {
|
||
// errorMessage = 'Too many requests. Try again later.';
|
||
// } else {
|
||
// errorMessage = 'Verification Failed: ${e.message}';
|
||
// }
|
||
// ScaffoldMessenger.of(context).showSnackBar(
|
||
// SnackBar(
|
||
// content: Text(errorMessage),
|
||
// duration: Duration(seconds: 2),
|
||
// ),
|
||
// );
|
||
//
|
||
// ToastHelper.showSuccessToast(context, errorMessage);
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
// },
|
||
// codeSent: (String verificationId, int? resendToken) async {
|
||
// setState(() {
|
||
// _verificationId = verificationId;
|
||
// _resendToken = resendToken;
|
||
// });
|
||
//
|
||
// // When getting the verificationId
|
||
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
// prefs.setString('verificationId', _verificationId);
|
||
//
|
||
//
|
||
// ToastHelper.showSuccessToast(
|
||
// context, 'Verification code sent to ${enteredMobileNumber}');
|
||
//
|
||
// Navigator.push(
|
||
// context,
|
||
// MaterialPageRoute(
|
||
// builder: (context) => MyVerify(
|
||
// verificationId: _verificationId,
|
||
// mobileNumber: enteredMobileNumber,
|
||
// resendToken: _resendToken,
|
||
// onResendCode: _resendCode, // Pass the phone number
|
||
// ),
|
||
// ),
|
||
// );
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
// },
|
||
// codeAutoRetrievalTimeout: (String verificationId) async{
|
||
// setState(() {
|
||
// _verificationId = verificationId;
|
||
// });
|
||
// final prefs = await SharedPreferences.getInstance();
|
||
// await prefs.setString('verificationId', verificationId);
|
||
// ToastHelper.showSuccessToast(context, 'Code auto-retrieval timed out.');
|
||
// setState(() {
|
||
// _isLoading = false;
|
||
// });
|
||
// },
|
||
// );
|
||
// }
|
||
//
|
||
// void _resendCode(String mobileNumber, int? resendToken) async {
|
||
// await _auth.verifyPhoneNumber(
|
||
// phoneNumber: '${countryController.text + mobileNumber}',
|
||
// timeout: const Duration(seconds: 60),
|
||
// forceResendingToken: resendToken,
|
||
// verificationCompleted: (PhoneAuthCredential credential) async {
|
||
// await _auth.signInWithCredential(credential);
|
||
// },
|
||
// verificationFailed: (FirebaseAuthException e) {
|
||
// if (e.code == 'invalid-phone-number') {
|
||
// print('The provided phone number is not valid.');
|
||
// }
|
||
// },
|
||
// codeSent: (String verificationId, int? resendToken) async{
|
||
// final prefs = await SharedPreferences.getInstance();
|
||
// await prefs.setString('verificationId', verificationId);
|
||
// setState(() {
|
||
// _verificationId = verificationId;
|
||
// _resendToken = resendToken;
|
||
// });
|
||
// ToastHelper.showSuccessToast(
|
||
// context, 'Verification code resent to ${mobileNumber}');
|
||
// Navigator.push(
|
||
// context,
|
||
// MaterialPageRoute(
|
||
// builder: (context) => MyVerify(
|
||
// verificationId: _verificationId,
|
||
// mobileNumber: mobileNumber,
|
||
// resendToken: _resendToken,
|
||
// onResendCode: _resendCode,
|
||
// ),
|
||
// ),
|
||
// );
|
||
// },
|
||
// codeAutoRetrievalTimeout: (String verificationId) async{
|
||
// final prefs = await SharedPreferences.getInstance();
|
||
// await prefs.setString('verificationId', verificationId);
|
||
// setState(() {
|
||
// _verificationId = verificationId;
|
||
// });
|
||
// },
|
||
// );
|
||
// }
|
||
|
||
// Future<void> sendMobileOrEmailVerify() async {
|
||
// if (!_formKey.currentState!.validate()) return;
|
||
// setState(() {
|
||
// enteredEmailOrMobile = true;
|
||
// });
|
||
// }
|
||
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: Colors.white,
|
||
body: LayoutBuilder(
|
||
builder: (context, constraints) {
|
||
if (!ResponsiveLayout.isMobile(context)) {
|
||
// Web layout
|
||
return Row(
|
||
children: [
|
||
Expanded(
|
||
child: Container(
|
||
color: Colors.white,
|
||
padding: const EdgeInsets.all(40),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Image.asset(
|
||
"assets/login/nhance-partner-logo.png",
|
||
height: 45,
|
||
),
|
||
const SizedBox(height: 40),
|
||
Expanded(
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
"Welcome Back",
|
||
style: TextStyle(
|
||
fontSize: 50,
|
||
fontWeight: FontWeight.w600,
|
||
color: Color(0xFF425C5C),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Image.asset(
|
||
"assets/login/login-content.png",
|
||
height:
|
||
MediaQuery.of(context).size.height *
|
||
0.5, // 40% of screen height
|
||
fit: BoxFit.contain,
|
||
),
|
||
const SizedBox(height: 10),
|
||
const Text(
|
||
'${'"'}Manage your policies, track quotations, and grow your business all in one place.${'"'}',
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
color: Color(0xFF000000),
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
// Right: Login form
|
||
Expanded(
|
||
child: Container(
|
||
// padding: const EdgeInsets.all(40),
|
||
decoration: const BoxDecoration(
|
||
color: Colors.white,
|
||
image: DecorationImage(
|
||
image: AssetImage(
|
||
"assets/login/login-bg.png",
|
||
), // <-- your image path
|
||
fit: BoxFit.cover, // cover entire container
|
||
),
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(40),
|
||
bottomLeft: Radius.circular(40),
|
||
),
|
||
),
|
||
child: Center(
|
||
// <-- center vertically + horizontally
|
||
child: SizedBox(
|
||
width: 600, // keep fixed width like first design
|
||
child: _LoginForm(context),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
} else {
|
||
// Mobile layout
|
||
return SingleChildScrollView(
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
const SizedBox(height: 15),
|
||
Image.asset(
|
||
"assets/login/nhance-partner-logo.png",
|
||
height: 35,
|
||
),
|
||
const SizedBox(height: 10),
|
||
Text(
|
||
"Welcome Back",
|
||
style: GoogleFonts.inter(
|
||
fontSize: 24,
|
||
fontWeight: FontWeight.w600,
|
||
color: Color(0xFF425C5C),
|
||
),
|
||
),
|
||
const SizedBox(height: 10),
|
||
Image.asset("assets/login/login-content.png", height: 120),
|
||
// const SizedBox(height: 10),
|
||
Container(
|
||
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 50),
|
||
child: Text(
|
||
'${'"'}Manage your policies, track quotations, and grow your business all in one place.${'"'}',
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: Color(0xFF000000),
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 10),
|
||
Container(
|
||
width: double.infinity,
|
||
height:
|
||
MediaQuery.of(context).size.height *
|
||
0.8, // full screen height
|
||
padding: const EdgeInsets.all(20),
|
||
decoration: const BoxDecoration(
|
||
gradient: LinearGradient(
|
||
colors: [Color(0xFF466F6C), Color(0xFF86D5CF)],
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
),
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(40),
|
||
topRight: Radius.circular(40),
|
||
),
|
||
),
|
||
child: _LoginForm(context),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _LoginForm(BuildContext context) {
|
||
const focusedBorderColor = Colors.white;
|
||
const fillColor = Color.fromRGBO(243, 246, 249, 0);
|
||
const borderColor = Color.fromRGBO(23, 171, 144, 0.4);
|
||
return Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
"Login to your account",
|
||
style: TextStyle(
|
||
fontSize: ResponsiveLayout.isMobile(context) ? 20 : 35,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
const SizedBox(height: 10),
|
||
Text(
|
||
"Enter your email or mobile number to receive a one time password.",
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(
|
||
fontSize: ResponsiveLayout.isMobile(context) ? 12 : 18,
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.all(3),
|
||
decoration: BoxDecoration(
|
||
color: Colors.grey.shade50,
|
||
borderRadius: BorderRadius.circular(50),
|
||
),
|
||
|
||
child: Row(
|
||
children: [
|
||
buildTab("Mobile", 0),
|
||
const SizedBox(width: 10),
|
||
buildTab("Email", 1),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 30),
|
||
Container(
|
||
child: Form(
|
||
key: _formKey,
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.max,
|
||
children: [
|
||
SizedBox(
|
||
width: 400,
|
||
height: 70,
|
||
child: Column(
|
||
children: [
|
||
if (switcherStatus == 0)
|
||
ThemedFormField(
|
||
hintText: 'Email',
|
||
backgroundColor: Colors.white,
|
||
validator: (value) =>
|
||
Validators.email(value, "Email"),
|
||
// imgPath: "MiscIconAssetPath.person",
|
||
controller: _emailController,
|
||
),
|
||
if (switcherStatus == 1)
|
||
ThemedFormField(
|
||
hintText: 'Mobile Number',
|
||
backgroundColor: Colors.white,
|
||
validator: (value) =>
|
||
Validators.phone(value, "Phone"),
|
||
// imgPath: "MiscIconAssetPath.person",
|
||
controller: _PhoneNumberController,
|
||
// txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||
keyboardType: TextInputType.number,
|
||
maxLength: 10,
|
||
inputFormatters: [
|
||
FilteringTextInputFormatter.digitsOnly,
|
||
],
|
||
// readOnly: true,
|
||
),
|
||
// const SizedBox(height: 16),
|
||
// ThemedFormField(
|
||
// hintText: 'Password',
|
||
// backgroundColor: Colors.white,
|
||
// validator: (value) =>
|
||
// Validators.passwordlogIn(value, "Password"),
|
||
// // imgPath: "MiscIconAssetPath.person",
|
||
// controller: _passwordController,
|
||
// isObscurable: true,
|
||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||
// // keyboardType: TextInputType.number,
|
||
// // maxLength: 10,
|
||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||
// // readOnly: true,
|
||
// ),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
if (!enteredEmailOrMobile)
|
||
SizedBox(
|
||
width: 400,
|
||
child: SizedBox(
|
||
width: double.infinity,
|
||
height: 50,
|
||
child: CommonButton(
|
||
text: "Login as Agent",
|
||
backgroundColor: Color(0xFF436462),
|
||
onPressed: () async {
|
||
setState(() {
|
||
clickedButtonName = 'agent';
|
||
});
|
||
// ⏳ Wait for API to finish
|
||
final success = await sendMobileOrEmailVerify(
|
||
'agent',
|
||
);
|
||
|
||
if (success) {
|
||
// API success → loader stops immediately
|
||
print("✅ API success");
|
||
} else {
|
||
// API failed → loader also stops immediately
|
||
print("❌ API failed");
|
||
}
|
||
},
|
||
),
|
||
// ElevatedButton(
|
||
// style: ElevatedButton.styleFrom(
|
||
// backgroundColor: Color(0xFF436462),
|
||
// padding: const EdgeInsets.symmetric(vertical: 16),
|
||
// shape: RoundedRectangleBorder(
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// ),
|
||
// ),
|
||
// onPressed: () {
|
||
// sendMobileOrEmailVerify('agent');
|
||
// setState(() {
|
||
// clickedButtonName = 'agent';
|
||
// });
|
||
// },
|
||
// child: Text(
|
||
// 'Login as Agent',
|
||
// style: TextStyle(
|
||
// fontSize: ResponsiveLayout.isMobile(context)
|
||
// ? 18
|
||
// : 20,
|
||
// fontWeight: FontWeight.w600,
|
||
// color: Colors.white,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
),
|
||
),
|
||
|
||
if (!ResponsiveLayout.isMobile(context) &&
|
||
!enteredEmailOrMobile) ...[
|
||
SizedBox(height: 10),
|
||
Container(
|
||
child: Text(
|
||
'OR',
|
||
style: TextStyle(
|
||
fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
SizedBox(height: 10),
|
||
SizedBox(
|
||
width: 400,
|
||
child: SizedBox(
|
||
width: double.infinity,
|
||
height: 50,
|
||
child: CommonButton(
|
||
text: "Login as Staff",
|
||
backgroundColor: Color(0xFF436462),
|
||
onPressed: () async {
|
||
setState(() {
|
||
clickedButtonName = 'staff';
|
||
});
|
||
// ⏳ Wait for API to finish
|
||
final success = await sendMobileOrEmailVerify(
|
||
'staff',
|
||
);
|
||
|
||
if (success) {
|
||
// API success → loader stops immediately
|
||
print("✅ API success");
|
||
} else {
|
||
// API failed → loader also stops immediately
|
||
print("❌ API failed");
|
||
}
|
||
},
|
||
),
|
||
// ElevatedButton(
|
||
// style: ElevatedButton.styleFrom(
|
||
// backgroundColor: Color(0xFF436462),
|
||
// padding: const EdgeInsets.symmetric(vertical: 16),
|
||
// shape: RoundedRectangleBorder(
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// ),
|
||
// ),
|
||
// onPressed: () {
|
||
// sendMobileOrEmailVerify('staff');
|
||
// setState(() {
|
||
// clickedButtonName = 'staff';
|
||
// });
|
||
// },
|
||
// child: Text(
|
||
// 'Login as Staff',
|
||
// style: TextStyle(
|
||
// fontSize: ResponsiveLayout.isMobile(context)
|
||
// ? 18
|
||
// : 20,
|
||
// fontWeight: FontWeight.w600,
|
||
// color: Colors.white,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
),
|
||
),
|
||
],
|
||
// if (enteredEmailOrMobile) ...[
|
||
// Container(
|
||
// child: Text(
|
||
// 'OTP',
|
||
// style: TextStyle(
|
||
// fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
|
||
// fontWeight: FontWeight.w600,
|
||
// color: Colors.white,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// Container(
|
||
// child: Pinput(
|
||
// length: 6,
|
||
// defaultPinTheme: defaultPinTheme,
|
||
// separatorBuilder: (index) => const SizedBox(width: 8),
|
||
// showCursor: true,
|
||
// controller: _otpController,
|
||
// // validator: _validatePin,
|
||
// errorPinTheme: defaultPinTheme.copyBorderWith(
|
||
// border: Border.all(color: Colors.redAccent),
|
||
// ),
|
||
// hapticFeedbackType: HapticFeedbackType.lightImpact,
|
||
// onCompleted: (pin) {
|
||
// debugPrint('onCompleted: $pin');
|
||
// },
|
||
// onChanged: (value) {
|
||
// debugPrint('onChanged: $value');
|
||
// },
|
||
// cursor: Column(
|
||
// mainAxisAlignment: MainAxisAlignment.end,
|
||
// children: [
|
||
// Container(
|
||
// margin: const EdgeInsets.only(bottom: 9),
|
||
// width: 22,
|
||
// height: 1,
|
||
// color: focusedBorderColor,
|
||
// ),
|
||
// ],
|
||
// ),
|
||
// focusedPinTheme: defaultPinTheme.copyWith(
|
||
// decoration: defaultPinTheme.decoration!.copyWith(
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// border: Border.all(color: focusedBorderColor),
|
||
// ),
|
||
// ),
|
||
// submittedPinTheme: defaultPinTheme.copyWith(
|
||
// decoration: defaultPinTheme.decoration!.copyWith(
|
||
// color: fillColor,
|
||
// borderRadius: BorderRadius.circular(19),
|
||
// border: Border.all(color: focusedBorderColor),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// const SizedBox(height: 20),
|
||
// SizedBox(
|
||
// width: 400,
|
||
// child: SizedBox(
|
||
// width: double.infinity,
|
||
// height: 50,
|
||
// child: ElevatedButton(
|
||
// style: ElevatedButton.styleFrom(
|
||
// backgroundColor: Color(0xFF436462),
|
||
// padding: const EdgeInsets.symmetric(vertical: 16),
|
||
// shape: RoundedRectangleBorder(
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// ),
|
||
// ),
|
||
// onPressed: () {
|
||
// // sendMobileOrEmailVerify('staff');
|
||
// },
|
||
// child: Text(
|
||
// 'Continue',
|
||
// style: TextStyle(
|
||
// fontSize: ResponsiveLayout.isMobile(context)
|
||
// ? 18
|
||
// : 20,
|
||
// fontWeight: FontWeight.w600,
|
||
// color: Colors.white,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ],
|
||
AnimatedSwitcher(
|
||
duration: const Duration(
|
||
milliseconds: 500,
|
||
), // animation speed
|
||
switchInCurve: Curves.easeInOutCirc,
|
||
switchOutCurve: Curves.easeOutCirc,
|
||
child: enteredEmailOrMobile
|
||
? Column(
|
||
key: const ValueKey('otp_block'),
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Container(
|
||
child: Center(
|
||
child: Text(
|
||
'OTP',
|
||
style: TextStyle(
|
||
fontSize: ResponsiveLayout.isMobile(context)
|
||
? 14
|
||
: 18,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 10),
|
||
Container(
|
||
alignment: Alignment.center,
|
||
child: Pinput(
|
||
length: 6,
|
||
defaultPinTheme: defaultPinTheme,
|
||
separatorBuilder: (index) =>
|
||
const SizedBox(width: 8),
|
||
showCursor: true,
|
||
controller: _otpController,
|
||
errorPinTheme: defaultPinTheme.copyBorderWith(
|
||
border: Border.all(color: Colors.redAccent),
|
||
),
|
||
hapticFeedbackType:
|
||
HapticFeedbackType.lightImpact,
|
||
onCompleted: (pin) =>
|
||
debugPrint('onCompleted: $pin'),
|
||
onChanged: (value) =>
|
||
debugPrint('onChanged: $value'),
|
||
cursor: Column(
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
children: [
|
||
Container(
|
||
margin: const EdgeInsets.only(bottom: 9),
|
||
width: 22,
|
||
height: 1,
|
||
color: focusedBorderColor,
|
||
),
|
||
],
|
||
),
|
||
focusedPinTheme: defaultPinTheme.copyWith(
|
||
decoration: defaultPinTheme.decoration!
|
||
.copyWith(
|
||
borderRadius: BorderRadius.circular(8),
|
||
border: Border.all(
|
||
color: focusedBorderColor,
|
||
),
|
||
),
|
||
),
|
||
submittedPinTheme: defaultPinTheme.copyWith(
|
||
decoration: defaultPinTheme.decoration!
|
||
.copyWith(
|
||
color: fillColor,
|
||
borderRadius: BorderRadius.circular(19),
|
||
border: Border.all(
|
||
color: focusedBorderColor,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Container(
|
||
alignment: Alignment.center, // center the text
|
||
child: RichText(
|
||
textAlign: TextAlign.center,
|
||
text: TextSpan(
|
||
text: 'Didn’t Receive Code? ', // normal text
|
||
style: TextStyle(
|
||
fontSize: ResponsiveLayout.isMobile(context)
|
||
? 12
|
||
: 14,
|
||
fontWeight: FontWeight.normal,
|
||
color: Colors.white,
|
||
),
|
||
children: [
|
||
TextSpan(
|
||
text: 'Resend', // bold clickable part
|
||
style: TextStyle(
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.white,
|
||
decoration: TextDecoration
|
||
.underline, // optional
|
||
),
|
||
recognizer: TapGestureRecognizer()
|
||
..onTap = () {
|
||
print('Resend clicked');
|
||
print(enteredEmailOrMobile);
|
||
print(clickedButtonName);
|
||
if (_PhoneNumberController
|
||
.text
|
||
.isNotEmpty) {
|
||
print('1224');
|
||
_resendCode(
|
||
_PhoneNumberController.text,
|
||
_resendToken,
|
||
);
|
||
} else if (_PhoneNumberController
|
||
.text
|
||
.isEmpty) {
|
||
print('1227');
|
||
sendMobileOrEmailVerify(
|
||
clickedButtonName,
|
||
);
|
||
} else {
|
||
print('data not found');
|
||
}
|
||
},
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
|
||
Center(
|
||
child: SizedBox(
|
||
width: 400,
|
||
child: CommonButton(
|
||
text: "Continue",
|
||
backgroundColor: Color(0xFF436462),
|
||
onPressed: () async {
|
||
if (switcherStatus == 1) {
|
||
await verifyFirebaseMobileOTP();
|
||
} else {
|
||
await verifyMobileOrMailOTP(
|
||
_otpController.text,
|
||
);
|
||
}
|
||
},
|
||
),
|
||
// ElevatedButton(
|
||
// style: ElevatedButton.styleFrom(
|
||
// backgroundColor: const Color(0xFF436462),
|
||
// padding: const EdgeInsets.symmetric(
|
||
// vertical: 16,
|
||
// ),
|
||
// shape: RoundedRectangleBorder(
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// ),
|
||
// ),
|
||
// onPressed: () {
|
||
// if (switcherStatus == 1) {
|
||
// verifyFirebaseMobileOTP();
|
||
// } else {
|
||
// verifyMobileOrMailOTP(_otpController.text);
|
||
// }
|
||
// },
|
||
// child: Text(
|
||
// 'Continue',
|
||
// style: TextStyle(
|
||
// fontSize: ResponsiveLayout.isMobile(context)
|
||
// ? 18
|
||
// : 20,
|
||
// fontWeight: FontWeight.w600,
|
||
// color: Colors.white,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
),
|
||
),
|
||
],
|
||
)
|
||
: const SizedBox.shrink(), // Empty widget when false
|
||
),
|
||
SizedBox(height: 20),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget buildTab(String title, int index) {
|
||
final isSelected = selectedIndex == index + 1;
|
||
return GestureDetector(
|
||
onTap: () {
|
||
setState(() {
|
||
selectedIndex = index + 1;
|
||
enteredEmailOrMobile = false;
|
||
_PhoneNumberController.text = '';
|
||
_emailController.text = '';
|
||
_otpController.text = '';
|
||
_PhoneNumberController.clear();
|
||
_emailController.clear();
|
||
_otpController.clear();
|
||
if (selectedIndex == 2) {
|
||
switcherStatus = 0;
|
||
} else {
|
||
switcherStatus = 1;
|
||
}
|
||
});
|
||
_formKey.currentState?.reset();
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.only(
|
||
top: 6.5,
|
||
bottom: 6.0,
|
||
left: 40.0,
|
||
right: 40.0,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: isSelected ? const Color(0xFF436462) : Colors.transparent,
|
||
boxShadow: isSelected
|
||
? [
|
||
BoxShadow(
|
||
color: isSelected
|
||
? const Color(0xFF436462)
|
||
: Colors.transparent, // Grey shadow
|
||
spreadRadius: 0.2,
|
||
blurRadius: 1,
|
||
offset: const Offset(0, 1), // Horizontal, Vertical
|
||
),
|
||
]
|
||
: [],
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Text(
|
||
title,
|
||
style: GoogleFonts.poppins(
|
||
fontSize: 12,
|
||
color: isSelected ? Colors.white : Colors.black,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// @override
|
||
// Widget build(BuildContext context) {
|
||
// final isWeb = MediaQuery.of(context).size.width > 600;
|
||
//
|
||
// return Scaffold(
|
||
// body: Center(
|
||
// child: Container(
|
||
// constraints: const BoxConstraints(maxWidth: 400),
|
||
// padding: const EdgeInsets.all(16.0),
|
||
// decoration: isWeb
|
||
// ? BoxDecoration(
|
||
// color: Colors.white,
|
||
// borderRadius: BorderRadius.circular(8),
|
||
// boxShadow: [
|
||
// BoxShadow(
|
||
// blurRadius: 12,
|
||
// color: Colors.black.withOpacity(0.1),
|
||
// ),
|
||
// ],
|
||
// )
|
||
// : null,
|
||
// child: Form(
|
||
// key: _formKey,
|
||
// child: Column(
|
||
// mainAxisSize: MainAxisSize.min,
|
||
// children: [
|
||
// // App Logo
|
||
// Image.asset('assets/logo.png', width: 80, height: 80),
|
||
// const SizedBox(height: 20),
|
||
//
|
||
// // Environment label
|
||
// Text(
|
||
// "Environment: ${Env.envName.toUpperCase()}",
|
||
// style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||
// ),
|
||
// const SizedBox(height: 20),
|
||
//
|
||
// ThemedFormField(
|
||
// hintText: 'Email',
|
||
// backgroundColor: Colors.white,
|
||
// validator: (value) => Validators.email(value, "Email"),
|
||
// // imgPath: "MiscIconAssetPath.person",
|
||
// controller: _emailController,
|
||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||
// // keyboardType: TextInputType.number,
|
||
// // maxLength: 10,
|
||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||
// // readOnly: true,
|
||
// ),
|
||
//
|
||
// const SizedBox(height: 16),
|
||
// ThemedFormField(
|
||
// hintText: 'Password',
|
||
// backgroundColor: Colors.white,
|
||
// validator: (value) =>
|
||
// Validators.passwordlogIn(value, "Password"),
|
||
// // imgPath: "MiscIconAssetPath.person",
|
||
// controller: _passwordController,
|
||
// isObscurable: true,
|
||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||
// // keyboardType: TextInputType.number,
|
||
// // maxLength: 10,
|
||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||
// // readOnly: true,
|
||
// ),
|
||
//
|
||
// // Password
|
||
// const SizedBox(height: 24),
|
||
//
|
||
// // Login Button
|
||
// SizedBox(
|
||
// width: double.infinity,
|
||
// child: ElevatedButton(
|
||
// onPressed: _isLoading ? null : _handleLogin,
|
||
// child: _isLoading
|
||
// ? const SizedBox(
|
||
// height: 20,
|
||
// width: 20,
|
||
// child: CircularProgressIndicator(
|
||
// strokeWidth: 2,
|
||
// valueColor: AlwaysStoppedAnimation<Color>(
|
||
// Colors.white,
|
||
// ),
|
||
// ),
|
||
// )
|
||
// : const Text("Login"),
|
||
// ),
|
||
// ),
|
||
//
|
||
// const SizedBox(height: 12),
|
||
//
|
||
// // Forgot password link
|
||
// TextButton(
|
||
// onPressed: () {
|
||
// // TODO: Navigate to forgot password screen
|
||
// },
|
||
// child: const Text("Forgot password?"),
|
||
// ),
|
||
// ],
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// );
|
||
// }
|