branch module

This commit is contained in:
Surendiran 2025-10-11 18:04:18 +05:30
parent f5cd4d89ad
commit 01f99fa2ca
13 changed files with 880 additions and 243 deletions

View File

@ -1,4 +1,4 @@
API_URL=https://venbait.in/enrollment/employeeRest/ API_URL=https://app.nhanceindia.in/enrolment/employeeRest/
API_URL_POST=https://venbait.in/nhance/dev/employeeRest/ API_URL_POST=https://app.nhanceindia.in/zenith/employeeRest/
BASE_HREF=/nhance/hr/dev/ BASE_HREF=/hr/
ENV=development ENV=production

View File

@ -45,7 +45,7 @@ android {
applicationId "com.example.nhance_app_pwa" applicationId "com.example.nhance_app_pwa"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 23 minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

View File

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class BranchCard extends StatelessWidget {
final String clientName;
final String branchName;
final bool isSelected;
final VoidCallback onTap;
const BranchCard({
Key? key,
required this.clientName,
required this.branchName,
required this.isSelected,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: Container(
decoration: BoxDecoration(
color: isSelected ? Color(0xFF00999E) : Color(0xFFF0F9F9),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Color(0xFF00999E),
width: 1.5,
),
),
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
clientName,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w500,
color: isSelected ? Colors.white : Color(0xFF00999E),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 4),
Text(
branchName,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: isSelected ? Color(0xFFFDFDFD) : Color(0xFF000000),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
}
}

View File

@ -0,0 +1,272 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../customAppBar/customAppBar.dart';
import '../customAppBar/customFooter.dart';
import '../customAppBar/toastHelper.dart';
import '../service/token_storage_service.dart';
import 'branch_card_widget.dart';
class BranchSelectionPage extends StatefulWidget {
const BranchSelectionPage({Key? key}) : super(key: key);
@override
State<BranchSelectionPage> createState() => _BranchSelectionPageState();
}
class _BranchSelectionPageState extends State<BranchSelectionPage> {
List<Map<String, dynamic>> branches = [];
int? selectedIndex;
final tokenStorage = TokenStorageService();
@override
void initState() {
super.initState();
_loadBranches();
}
void _loadBranches() {
setState(() {
branches = tokenStorage.getCombinedBranches();
});
}
void _selectBranch(int index) {
setState(() {
selectedIndex = index;
});
}
Future<void> _handleNext() async {
if (selectedIndex == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Please select a branch'),
backgroundColor: Colors.orange,
),
);
return;
}
final selectedBranch = branches[selectedIndex!];
// Save selected branch and decode token
await tokenStorage.saveSelectedBranch(selectedBranch);
// Debug: Print decoded token
final decodedToken = tokenStorage.getDecodedToken();
print('Selected Branch: $selectedBranch');
print('Decoded Token: $decodedToken');
// Navigate to home
if (mounted) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
//Post Token Decode Details
final empClientBranchId = decodedToken?['post_branch_id'];
await prefs.setString('empClientBranchId', empClientBranchId);
final empPrimaryId = decodedToken?['post_hr_id'];
await prefs.setString('empPrimaryId', empPrimaryId);
final empClientId = decodedToken?['post_client_id'];
await prefs.setString('empClientId', empClientId);
final empHrId = decodedToken?['post_hr_id'];
await prefs.setString('empHrId', empHrId);
dynamic allowedModules = decodedToken?['allowed_modules'];
// If it's a String, decode it again
if (allowedModules is String) {
allowedModules = jsonDecode(allowedModules);
}
final empAllowedModules = allowedModules['post'];
await prefs.setString('empAllowed_modules', jsonEncode(empAllowedModules));
// final empAllowed_modules = decodedToken?['allowed_modules'][0]['post'];
// await prefs.setString('empAllowed_modules', jsonEncode(empAllowed_modules));
//Pre Token Decode Details
final enrollmentEmpClientBranchId = decodedToken?['pre_branch_id'];
await prefs.setString('enrollmentEmpClientBranchId', enrollmentEmpClientBranchId);
final enrollmentEmpPrimaryId = decodedToken?['pre_hr_id'];
await prefs.setString('enrollmentEmpPrimaryId', enrollmentEmpPrimaryId);
final enrollmentClient_id = decodedToken?['pre_client_id'];
await prefs.setString('enrollmentClient_id', enrollmentClient_id);
final enrollmentHrId = decodedToken?['pre_hr_id'];
await prefs.setString('enrollmentHrId', enrollmentHrId);
final enrollmentAllowedModules = allowedModules['pre'];
await prefs.setString('enrollmentAllowed_modules', jsonEncode(enrollmentAllowedModules));
// final enrollmentAllowed_modules = decodedToken?['allowed_modules'][1]['pre'];
// await prefs.setString('enrollmentAllowed_modules', jsonEncode(enrollmentAllowed_modules));
final token = await tokenStorage.getCurrentToken();
print('tokenbranch - $token');
await prefs.setString('token', token!);
ToastHelper.showSuccessToast(context, 'Successfully Login');
Navigator.pushReplacementNamed(context, 'hrDashboard');
}
}
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
// Calculate dynamic horizontal padding (10% of screen width)
final horizontalPadding = screenWidth * 0.1;
// Calculate dynamic grid height
double gridHeight = screenHeight * 0.45;
if (gridHeight < 300) gridHeight = 300;
if (gridHeight > 600) gridHeight = 600;
// Determine crossAxisCount with multiple breakpoints
int crossAxisCount;
double childAspectRatio;
if (screenWidth < 600) {
// Mobile phones
crossAxisCount = 2;
childAspectRatio = 2.5;
} else if (screenWidth < 900) {
// Small tablets
crossAxisCount = 2;
childAspectRatio = 2.8;
} else if (screenWidth < 1200) {
// Large tablets
crossAxisCount = 3;
childAspectRatio = 3;
} else {
// Desktop
crossAxisCount = 3;
childAspectRatio = 5;
}
return Scaffold(
backgroundColor: Color(0xFFEFF3F6),
appBar: CustomAppBar(),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: horizontalPadding , // Inner horizontal padding
vertical: 20, // Inner vertical padding
), // Outer padding
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
padding: const EdgeInsets.symmetric(
horizontal: 24.0, // Inner horizontal padding
vertical: 28.0, // Inner vertical padding
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Client',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 25),
Container(
height: gridHeight, // Shows approximately 3 rows
child: branches.isEmpty
? Center(
child: Text(
'No branches available',
style: TextStyle(fontSize: 16, color: Colors.grey),
),
)
: GridView.builder(
// Enable scrolling if content exceeds height
physics: ClampingScrollPhysics(),
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
childAspectRatio: childAspectRatio,
crossAxisSpacing: 15,
mainAxisSpacing: 15,
),
itemCount: branches.length,
itemBuilder: (context, index) {
final branch = branches[index];
return BranchCard(
clientName: branch['client_name'] ?? 'Unknown Client',
branchName: branch['branch_name'] ?? 'Unknown Branch',
isSelected: selectedIndex == index,
onTap: () => _selectBranch(index),
);
},
),
),
SizedBox(height: 24),
Center(
child: SizedBox(
width: 120,
height: 48,
child: ElevatedButton(
onPressed: _handleNext,
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFFF6B35),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 0,
),
child: Text(
'Next',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
),
],
),
),
),
),
),
Container(
width: double.infinity,
child: CustomFooter(),
),
],
),
);
}
}

View File

@ -87,12 +87,29 @@ class _CustomAppBarState extends State<CustomAppBar> {
// }, // },
// ), // ),
// if (showBackToHR) // if (showBackToHR)
// NavBarItem( NavBarItem(
// text: "Back To HR", text: "Change Branch",
// onTap: () { onTap: () async {
// // hrLogout(context); final prefs = await SharedPreferences.getInstance();
// }, await prefs.remove('selected_branch');
// ), await prefs.remove('decoded_token');
await prefs.remove('clientLogo');
await prefs.remove('clientName');
await prefs.remove('empAllowed_modules');
await prefs.remove('empClientBranchId');
await prefs.remove('empClientId');
await prefs.remove('empEmail');
await prefs.remove('empHrId');
await prefs.remove('empPrimaryId');
await prefs.remove('enrollmentAllowed_modules');
await prefs.remove('enrollmentClient_id');
await prefs.remove('enrollmentEmpClientBranchId');
await prefs.remove('enrollmentEmpPrimaryId');
await prefs.remove('enrollmentHrId');
await prefs.remove('token');
Navigator.pushNamed(context, 'branchSelection');
},
),
NavBarItem( NavBarItem(
text: "Logout", text: "Logout",
onTap: () async { onTap: () async {

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:nhancepolicy/responsive.dart'; import 'package:nhancepolicy/responsive.dart';
import 'package:nhancepolicy/service/api_service.dart'; import 'package:nhancepolicy/service/api_service.dart';
import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:pinput/pinput.dart'; import 'package:pinput/pinput.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -17,16 +18,15 @@ import '../customAppBar/toastHelper.dart';
import '../models/environment.dart'; import '../models/environment.dart';
import '../models/platform_helper_mobile.dart' import '../models/platform_helper_mobile.dart'
if (dart.library.html) '../models/platform_helper_other.dart'; if (dart.library.html) '../models/platform_helper_other.dart';
import 'branch/branch_selection_page.dart';
// import 'dart:html' as html; // import 'dart:html' as html;
class MyEmailVerify extends StatefulWidget { class MyEmailVerify extends StatefulWidget {
final String email; final String type; // 'email' or 'mobile'
final String value;
const MyEmailVerify({ const MyEmailVerify({super.key, required this.type, required this.value});
Key? key,
required this.email,
}) : super(key: key);
@override @override
State<MyEmailVerify> createState() => _MyEmailVerifyState(); State<MyEmailVerify> createState() => _MyEmailVerifyState();
@ -99,9 +99,12 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
void verifyOTP(String otp) async { void verifyOTP(String otp) async {
try { try {
final Map<String, dynamic> payload = (widget.type == 'mobile')
? {'otp': _otpController.text,'mobile_no': widget.value}
: {'otp': _otpController.text, 'email': widget.value};
final response = await http.post( final response = await http.post(
Uri.parse(Environment.apiUrl + 'getVerifiedHrData'), Uri.parse(Environment.apiUrl + 'getVerifiedHrData'),
body: json.encode({'email': widget.email, 'otp': _otpController.text}), body: json.encode(payload),
headers: { headers: {
HttpHeaders.contentTypeHeader: 'application/json', HttpHeaders.contentTypeHeader: 'application/json',
}, },
@ -112,35 +115,56 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
_isLoading = false; _isLoading = false;
}); });
Map<String, dynamic> data = json.decode(response.body); Map<String, dynamic> data = json.decode(response.body);
print('data: $data'); print('Response data: $data');
_token = data['data'];
String status = data['status'];
// Directly access the post_enrollment data // Extract enrollment data
Map<String, dynamic> post = data['post_enrollment']; List<dynamic> preEnrollmentData = data['data'] ?? [];
print('post: $post'); Map<String, dynamic> postEnrollment = data['post_enrollment'] ?? {};
List<dynamic> postEnrollmentData = postEnrollment['data'] ?? [];
_postToken = post['data']; // Save to global storage
String postStatus = post['status']; final tokenStorage = TokenStorageService();
await tokenStorage.saveEnrollmentData(
preEnrollmentData,
postEnrollmentData,
);
if (postStatus == 'success') { // Navigate to branch selection
setState(() { Navigator.pushReplacement(
_isLoading = false; context,
}); MaterialPageRoute(
postSuccessData(post, data); builder: (context) => BranchSelectionPage(),
} else if (status == 'success') { ),
setState(() { );
_isLoading = false; // print('data: $data');
}); // _token = data['data'];
enrollmentSuccessData(data); // String status = data['status'];
} else { //
setState(() { // // Directly access the post_enrollment data
_isLoading = false; // Map<String, dynamic> post = data['post_enrollment'];
}); // print('post: $post');
ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again'); //
// Show a Snackbar if the OTP is invalid // _postToken = post['data'];
print('Invalid OTP. Please try again'); // String postStatus = post['status'];
} //
// if (postStatus == 'success') {
// setState(() {
// _isLoading = false;
// });
// postSuccessData(post, data);
// } else if (status == 'success') {
// setState(() {
// _isLoading = false;
// });
// enrollmentSuccessData(data);
// } else {
// setState(() {
// _isLoading = false;
// });
// ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again');
// // Show a Snackbar if the OTP is invalid
// print('Invalid OTP. Please try again');
// }
} else { } else {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -289,9 +313,17 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
Future<void> verifyMobileAndEmailNumber() async { Future<void> verifyMobileAndEmailNumber() async {
try { try {
// var enteredMobileNumber = mobileController.text; // var enteredMobileNumber = mobileController.text;
final Map<String, dynamic> payload = (widget.type == 'mobile')
? {'mobile_number': widget.value}
: {'email': widget.value};
String apiEndpoint = (widget.type == 'mobile')
? Environment.apiUrl + 'verifyHrWithMobileNumber'
: Environment.apiUrl + 'verifyHrWithEmail';
final response = await http.post( final response = await http.post(
Uri.parse(Environment.apiUrl + 'verifyEmployeeEmailId'), Uri.parse(apiEndpoint),
body: json.encode({'email': widget.email}), body: json.encode(payload),
headers: { headers: {
HttpHeaders.contentTypeHeader: 'application/json', HttpHeaders.contentTypeHeader: 'application/json',
}, },
@ -303,7 +335,7 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
String message = data['data']['message']; String message = data['data']['message'];
if (userVerification) { if (userVerification) {
ToastHelper.showSuccessToast( ToastHelper.showSuccessToast(
context, 'Verification code sent to ${widget.email}'); context, 'Verification code sent to ${widget.value}');
} else { } else {
ToastHelper.showErrorToast(context, message); ToastHelper.showErrorToast(context, message);
print('Invalid mobile number'); print('Invalid mobile number');
@ -622,14 +654,17 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
text: text:
"Please enter the one-time usage code sent to your mobile number ${widget.email}", "Please enter the one-time usage code sent to your ",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
height: 1.5, height: 1.5,
color: Color(0xFF000000)), color: Color(0xFF000000)),
children: [ children: [
TextSpan( TextSpan(
text: " (Change Email)", text: widget.type == 'mobile' ? 'mobile number ${widget.value}' : 'Email Id ${widget.value}',
),
TextSpan(
text: widget.type == 'mobile' ? ' (Change Mobile)' : ' (Change Email)',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Color( color: Color(

View File

@ -495,6 +495,9 @@ class _excelVerifyState extends State<excelVerify> {
}); });
handleImportAction(); handleImportAction();
} else { } else {
setState(() {
isLoading = false;
});
ToastHelper.showErrorToast(context, data['message']); ToastHelper.showErrorToast(context, data['message']);
print('Table'); print('Table');

View File

@ -12,6 +12,7 @@ import 'package:nhancepolicy/service/hrDashboardTabs/activePolicies.dart';
import 'package:nhancepolicy/service/hrDashboardTabs/cd.dart'; import 'package:nhancepolicy/service/hrDashboardTabs/cd.dart';
import 'package:nhancepolicy/service/hrDashboardTabs/claims.dart'; import 'package:nhancepolicy/service/hrDashboardTabs/claims.dart';
import 'package:nhancepolicy/service/hrDashboardTabs/preEnrollment.dart'; import 'package:nhancepolicy/service/hrDashboardTabs/preEnrollment.dart';
import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'customAppBar/customAppBar.dart'; import 'customAppBar/customAppBar.dart';
@ -75,6 +76,7 @@ class _hrDashboardState extends State<hrDashboard>
]; ];
ScrollController _scrollController = ScrollController(); ScrollController _scrollController = ScrollController();
int selectedIndex = 0; int selectedIndex = 0;
final tokenService = TokenStorageService();
@override @override
void initState() { void initState() {
@ -94,6 +96,7 @@ class _hrDashboardState extends State<hrDashboard>
// isLoading = false; // isLoading = false;
// }); // });
// }); // });
} }
@override @override
@ -104,11 +107,15 @@ class _hrDashboardState extends State<hrDashboard>
checkToken() async { checkToken() async {
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
enrollToken = prefs.getString('enrollToken'); // enrollToken = prefs.getString('pre_enrollment_data');
_postToken = prefs.getString('_postToken'); // _postToken = prefs.getString('post_enrollment_data');
// Get the current token
final token = await tokenService.getCurrentToken();
print('token - $token');
print('token check in'); print('token check in');
if((enrollToken != null && enrollToken!.isNotEmpty) || (_postToken != null && _postToken!.isNotEmpty)){ if((token != null && token!.isNotEmpty)){
print('token check done'); print('token check done');
_loadToken(); _loadToken();
} else { } else {
@ -120,17 +127,21 @@ class _hrDashboardState extends State<hrDashboard>
Future<void> _loadToken() async { Future<void> _loadToken() async {
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
_postToken = prefs.getString('_postToken'); enrollToken = await tokenService.getCurrentToken();
enrollToken = prefs.getString('enrollToken'); _postToken = await tokenService.getCurrentToken();
print(enrollToken);
print(_postToken);
if (enrollToken != null && enrollToken!.isNotEmpty) { if (enrollToken != null && enrollToken!.isNotEmpty) {
Map<String, dynamic>? decodedToken = Jwt.parseJwt(enrollToken!); // Map<String, dynamic>? decodedToken = Jwt.parseJwt(enrollToken!);
enrollmentClient_id = decodedToken['client_id'].toString(); // enrollmentClient_id = decodedToken['client_id'].toString();
enrollmentClient_id = prefs.getString('enrollmentClient_id');
enrollmentEmpClientBranchId = enrollmentEmpClientBranchId =
prefs.getString('enrollmentEmpClientBranchId'); prefs.getString('enrollmentEmpClientBranchId');
enrollmentHrId = prefs.getString('enrollmentHrId'); enrollmentHrId = prefs.getString('enrollmentHrId');
print("Pre decodedToken - $decodedToken"); // print("Pre decodedToken - $decodedToken");
print("Pre enrollmentClient_id - $enrollmentClient_id"); print("Pre enrollmentClient_id - $enrollmentClient_id");
print("Pre enrollmentEmpClientBranchId - $enrollmentEmpClientBranchId"); print("Pre enrollmentEmpClientBranchId - $enrollmentEmpClientBranchId");
print("Pre enrollmentHrId - $enrollmentHrId"); print("Pre enrollmentHrId - $enrollmentHrId");
@ -163,7 +174,9 @@ class _hrDashboardState extends State<hrDashboard>
clientLogo = prefs.getString('clientLogo'); clientLogo = prefs.getString('clientLogo');
clientName = prefs.getString('clientName'); clientName = prefs.getString('clientName');
} else { } else {
getClientLogoAndDetails( empClientId = prefs.getString('empClientId');
empClientBranchId = prefs.getString('empClientBranchId');
getClientLogoAndDetails(empClientId,empClientBranchId,
enrollmentEmpClientBranchId, enrollmentClient_id, enrollToken); enrollmentEmpClientBranchId, enrollmentClient_id, enrollToken);
} }
getCashDepositDetails(enrollmentEmpClientBranchId, enrollmentClient_id, getCashDepositDetails(enrollmentEmpClientBranchId, enrollmentClient_id,
@ -171,14 +184,15 @@ class _hrDashboardState extends State<hrDashboard>
} }
if (_postToken != null && _postToken!.isNotEmpty) { if (_postToken != null && _postToken!.isNotEmpty) {
Map<String, dynamic>? postdecodedToken = Jwt.parseJwt(_postToken!); // Map<String, dynamic>? postdecodedToken = Jwt.parseJwt(_postToken!);
empClientId = postdecodedToken['client_id'].toString(); // empClientId = postdecodedToken['client_id'].toString();
empClientId = prefs.getString('empClientId');
empClientBranchId = prefs.getString('empClientBranchId'); empClientBranchId = prefs.getString('empClientBranchId');
empHrId = prefs.getString('empHrId'); empHrId = prefs.getString('empHrId');
print('post empHrId- $empHrId'); print('post empHrId- $empHrId');
print('postdecodedToken- $postdecodedToken'); // print('postdecodedToken- $postdecodedToken');
print('post empClientId- $empClientId'); print('post empClientId- $empClientId');
print('post empClientBranchId- $empClientBranchId'); print('post empClientBranchId- $empClientBranchId');
@ -250,7 +264,10 @@ class _hrDashboardState extends State<hrDashboard>
clientLogo = prefs.getString('clientLogo'); clientLogo = prefs.getString('clientLogo');
clientName = prefs.getString('clientName'); clientName = prefs.getString('clientName');
} else { } else {
getClientLogoAndDetails(empClientBranchId, empClientId, _postToken); empClientId = prefs.getString('empClientId');
empClientBranchId = prefs.getString('empClientBranchId');
getClientLogoAndDetails(empClientId,empClientBranchId,
enrollmentEmpClientBranchId, enrollmentClient_id, _postToken);
} }
print("getCashDepositDetails"); print("getCashDepositDetails");
} }
@ -344,9 +361,10 @@ class _hrDashboardState extends State<hrDashboard>
}).toList(); }).toList();
} }
Future<void> getClientLogoAndDetails(clintBranchId, clintID, token) async { Future<void> getClientLogoAndDetails(post_client_id, post_client_branch_id,
pre_client_branch_id, pre_client_id, token) async {
var url = Uri.parse(Environment.apiUrl + var url = Uri.parse(Environment.apiUrl +
'getClientDetails?client_id=$clintID&client_branch_id=$clintBranchId'); 'getClientDetails?post_client_id=$post_client_id&post_branch_id=$post_client_branch_id&pre_client_id=$pre_client_id&pre_branch_id=$pre_client_branch_id');
try { try {
var response = await http.get( var response = await http.get(
url, url,
@ -525,6 +543,7 @@ class _hrDashboardState extends State<hrDashboard>
width: double.infinity, width: double.infinity,
// height: 75, // height: 75,
height: MediaQuery.of(context).size.height * 0.12, height: MediaQuery.of(context).size.height * 0.12,
padding: Responsive.isDesktop(context) padding: Responsive.isDesktop(context)
? const EdgeInsets.only( ? const EdgeInsets.only(
top: 10, bottom: 10, left: 20, right: 20) top: 10, bottom: 10, left: 20, right: 20)
@ -542,32 +561,48 @@ class _hrDashboardState extends State<hrDashboard>
height: 80, height: 80,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Image.network( child: Image.network(
clientLogo ?? '', Uri.encodeFull(clientLogo ?? ''),
width: 80, // Set the width here width: 200,
height: 60, // Set the height here height: 200,
loadingBuilder: (BuildContext context, fit: BoxFit.contain,
Widget child, frameBuilder: (BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded) {
ImageChunkEvent? loadingProgress) { if (wasSynchronouslyLoaded) {
if (loadingProgress == null) return child; return child;
}
return AnimatedOpacity(
opacity: frame == null ? 0 : 1,
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut,
child: child,
);
},
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center( return Center(
child: SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != strokeWidth: 2,
null valueColor: AlwaysStoppedAnimation<Color>(Colors.grey),
? loadingProgress value: loadingProgress.expectedTotalBytes != null
.cumulativeBytesLoaded / ? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes! (loadingProgress.expectedTotalBytes ?? 1)
: null, : null,
), ),
),
); );
}, },
errorBuilder: (BuildContext context, Object error, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) {
StackTrace? stackTrace) { return Text('');
return Image.asset( // Image.asset(
'assets/Solid_gray.png', // Replace 'default_image.png' with your default image asset path // 'assets/Solid_gray.png',
width: 80, // width: 80,
height: 60, // height: 60,
fit: BoxFit.cover, // fit: BoxFit.cover,
); // );
}, },
), ),
), ),

View File

@ -49,12 +49,12 @@ class _MyPhoneState extends State<MyHrLogin> {
clearLocalStorageWhenStarts(fromData) async { clearLocalStorageWhenStarts(fromData) async {
print(fromData); print(fromData);
if(kIsWeb) { // if(kIsWeb) {
print('vndbbcbdskbvkj3'); print('vndbbcbdskbvkj3');
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear(); prefs.clear();
print('Local Storage Clear'); print('Local Storage Clear');
} // }
} }
@ -99,8 +99,6 @@ class _MyPhoneState extends State<MyHrLogin> {
if (userVerification) { if (userVerification) {
final SharedPreferences prefs = final SharedPreferences prefs =
await SharedPreferences.getInstance(); await SharedPreferences.getInstance();
// var enteredMobileNumber = mobileController.text;
// prefs.setString('empMobileNo', enteredMobileNumber);
if (isEmailFieldVisible) { if (isEmailFieldVisible) {
print('isEmailFieldVisible $isEmailFieldVisible'); print('isEmailFieldVisible $isEmailFieldVisible');
prefs.setString('empEmail', emailController.text); prefs.setString('empEmail', emailController.text);
@ -111,12 +109,23 @@ class _MyPhoneState extends State<MyHrLogin> {
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => MyEmailVerify( builder: (context) => MyEmailVerify(
email: emailController.text, // Pass the phone number type: 'email',
value: emailController.text.trim(), // Pass the phone number
), ),
), ),
); );
} else { } else {
_verifyPhoneNumber(); ToastHelper.showSuccessToast(
context, 'Verification code sent to ${emailController.text}');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyEmailVerify(
type: 'mobile',
value: mobileController.text.trim(), // Pass the phone number
),
),
);
} }
// ToastHelper.showSuccessToast(context, message); // ToastHelper.showSuccessToast(context, message);
@ -144,129 +153,129 @@ class _MyPhoneState extends State<MyHrLogin> {
} }
} }
Future<void> _verifyPhoneNumber() async { // Future<void> _verifyPhoneNumber() async {
var enteredMobileNumber = mobileController.text; // var enteredMobileNumber = mobileController.text;
var countryCode = countryController.text; // var countryCode = countryController.text;
print('${countryCode + enteredMobileNumber}'); // print('${countryCode + enteredMobileNumber}');
await _auth.verifyPhoneNumber( // await _auth.verifyPhoneNumber(
phoneNumber: '${countryCode + enteredMobileNumber}', // phoneNumber: '${countryCode + enteredMobileNumber}',
timeout: const Duration(seconds: 60), // timeout: const Duration(seconds: 60),
verificationCompleted: (PhoneAuthCredential credential) async { // verificationCompleted: (PhoneAuthCredential credential) async {
await _auth.signInWithCredential(credential); // await _auth.signInWithCredential(credential);
// ToastHelper.showSuccessToast(context, 'Verified Successfully!'); // // 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(() { // setState(() {
// _isLoading = false; // _isLoading = false;
// }); // });
}, // },
verificationFailed: (FirebaseAuthException e) { // codeSent: (String verificationId, int? resendToken) async {
print('Verification Failed: ${e.code} - ${e.message}'); // setState(() {
String errorMessage; // _verificationId = verificationId;
if (e.code == 'invalid-app-credential') { // _resendToken = resendToken;
errorMessage = 'Invalid Credential. Please try again.'; // });
} else if (e.code == 'invalid-phone-number') { //
errorMessage = 'The provided phone number is not valid.'; // // When getting the verificationId
} else if (e.code == 'too-many-requests') { // SharedPreferences prefs = await SharedPreferences.getInstance();
errorMessage = 'Too many requests. Try again later.'; // prefs.setString('verificationId', _verificationId);
} else { //
errorMessage = 'Verification Failed: ${e.message}'; // ToastHelper.showSuccessToast(
} // context, 'Verification code sent to ${enteredMobileNumber}');
ScaffoldMessenger.of(context).showSnackBar( //
SnackBar( // Navigator.push(
content: Text(errorMessage), // context,
duration: Duration(seconds: 2), // MaterialPageRoute(
), // builder: (context) => MyHrVerify(
); // verificationId: _verificationId,
// mobileNumber: enteredMobileNumber,
ToastHelper.showSuccessToast(context, errorMessage); // resendToken: _resendToken,
setState(() { // onResendCode: _resendCode, // Pass the phone number
_isLoading = false; // ),
}); // ),
}, // );
codeSent: (String verificationId, int? resendToken) async { // setState(() {
setState(() { // _isLoading = false;
_verificationId = verificationId; // });
_resendToken = resendToken; // },
}); // codeAutoRetrievalTimeout: (String verificationId) async {
// setState(() {
// When getting the verificationId // _verificationId = verificationId;
SharedPreferences prefs = await SharedPreferences.getInstance(); // });
prefs.setString('verificationId', _verificationId); // final prefs = await SharedPreferences.getInstance();
// await prefs.setString('verificationId', verificationId);
ToastHelper.showSuccessToast( // ToastHelper.showSuccessToast(context, 'Code auto-retrieval timed out.');
context, 'Verification code sent to ${enteredMobileNumber}'); // setState(() {
// _isLoading = false;
Navigator.push( // });
context, // },
MaterialPageRoute( // );
builder: (context) => MyHrVerify( // }
verificationId: _verificationId, //
mobileNumber: enteredMobileNumber, // void _resendCode(String mobileNumber, int? resendToken) async {
resendToken: _resendToken, // await _auth.verifyPhoneNumber(
onResendCode: _resendCode, // Pass the phone number // phoneNumber: '${countryController.text + mobileNumber}',
), // timeout: const Duration(seconds: 60),
), // forceResendingToken: resendToken,
); // verificationCompleted: (PhoneAuthCredential credential) async {
setState(() { // await _auth.signInWithCredential(credential);
_isLoading = false; // },
}); // verificationFailed: (FirebaseAuthException e) {
}, // if (e.code == 'invalid-phone-number') {
codeAutoRetrievalTimeout: (String verificationId) async { // print('The provided phone number is not valid.');
setState(() { // }
_verificationId = verificationId; // },
}); // codeSent: (String verificationId, int? resendToken) async {
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
await prefs.setString('verificationId', verificationId); // await prefs.setString('verificationId', verificationId);
ToastHelper.showSuccessToast(context, 'Code auto-retrieval timed out.'); // setState(() {
setState(() { // _verificationId = verificationId;
_isLoading = false; // _resendToken = resendToken;
}); // });
}, // ToastHelper.showSuccessToast(
); // context, 'Verification code resent to ${mobileNumber}');
} // Navigator.push(
// context,
void _resendCode(String mobileNumber, int? resendToken) async { // MaterialPageRoute(
await _auth.verifyPhoneNumber( // builder: (context) => MyHrVerify(
phoneNumber: '${countryController.text + mobileNumber}', // verificationId: _verificationId,
timeout: const Duration(seconds: 60), // mobileNumber: mobileNumber,
forceResendingToken: resendToken, // resendToken: _resendToken,
verificationCompleted: (PhoneAuthCredential credential) async { // onResendCode: _resendCode,
await _auth.signInWithCredential(credential); // ),
}, // ),
verificationFailed: (FirebaseAuthException e) { // );
if (e.code == 'invalid-phone-number') { // },
print('The provided phone number is not valid.'); // codeAutoRetrievalTimeout: (String verificationId) async {
} // final prefs = await SharedPreferences.getInstance();
}, // await prefs.setString('verificationId', verificationId);
codeSent: (String verificationId, int? resendToken) async { // setState(() {
final prefs = await SharedPreferences.getInstance(); // _verificationId = verificationId;
await prefs.setString('verificationId', verificationId); // });
setState(() { // },
_verificationId = verificationId; // );
_resendToken = resendToken; // }
});
ToastHelper.showSuccessToast(
context, 'Verification code resent to ${mobileNumber}');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyHrVerify(
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;
});
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -4,6 +4,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:nhancepolicy/customAppBar/toastHelper.dart'; import 'package:nhancepolicy/customAppBar/toastHelper.dart';
import 'package:nhancepolicy/models/environment.dart'; import 'package:nhancepolicy/models/environment.dart';
import 'package:nhancepolicy/service/api_service.dart'; import 'package:nhancepolicy/service/api_service.dart';
import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:pinput/pinput.dart'; import 'package:pinput/pinput.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -14,6 +15,8 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:nhancepolicy/responsive.dart'; import 'package:nhancepolicy/responsive.dart';
import 'package:jwt_decode/jwt_decode.dart'; import 'package:jwt_decode/jwt_decode.dart';
import 'branch/branch_selection_page.dart';
class MyHrVerify extends StatefulWidget { class MyHrVerify extends StatefulWidget {
final String verificationId; final String verificationId;
final String mobileNumber; final String mobileNumber;
@ -139,35 +142,58 @@ class _MyVerifyState extends State<MyHrVerify> {
_isLoading = false; _isLoading = false;
}); });
Map<String, dynamic> data = json.decode(response.body); Map<String, dynamic> data = json.decode(response.body);
print('data: $data');
_token = data['data'];
String status = data['status'];
// Directly access the post_enrollment data print('Response data: $data');
Map<String, dynamic> post = data['post_enrollment'];
print('post: $post');
_postToken = post['data']; // Extract enrollment data
String postStatus = post['status']; List<dynamic> preEnrollmentData = data['data'] ?? [];
Map<String, dynamic> postEnrollment = data['post_enrollment'] ?? {};
List<dynamic> postEnrollmentData = postEnrollment['data'] ?? [];
if (postStatus == 'success') { // Save to global storage
setState(() { final tokenStorage = TokenStorageService();
_isLoading = false; await tokenStorage.saveEnrollmentData(
}); preEnrollmentData,
postSuccessData(post, data); postEnrollmentData,
} else if (status == 'success') { );
setState(() {
_isLoading = false; // Navigate to branch selection
}); Navigator.pushReplacement(
enrollmentSuccessData(data); context,
} else { MaterialPageRoute(
setState(() { builder: (context) => BranchSelectionPage(),
_isLoading = false; ),
}); );
ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again');
// Show a Snackbar if the OTP is invalid // print('data: $data');
print('Invalid OTP. Please try again'); // _token = data['data'];
} // String status = data['status'];
//
// // Directly access the post_enrollment data
// Map<String, dynamic> post = data['post_enrollment'];
// print('post: $post');
//
// _postToken = post['data'];
// String postStatus = post['status'];
//
// if (postStatus == 'success') {
// setState(() {
// _isLoading = false;
// });
// postSuccessData(post, data);
// } else if (status == 'success') {
// setState(() {
// _isLoading = false;
// });
// enrollmentSuccessData(data);
// } else {
// setState(() {
// _isLoading = false;
// });
// ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again');
// // Show a Snackbar if the OTP is invalid
// print('Invalid OTP. Please try again');
// }
} else { } else {
setState(() { setState(() {
_isLoading = false; _isLoading = false;

View File

@ -2,6 +2,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:nhancepolicy/addons.dart'; import 'package:nhancepolicy/addons.dart';
import 'package:nhancepolicy/branch/branch_selection_page.dart';
import 'package:nhancepolicy/empReview.dart'; import 'package:nhancepolicy/empReview.dart';
import 'package:nhancepolicy/empDetails.dart'; import 'package:nhancepolicy/empDetails.dart';
import 'package:nhancepolicy/excel_verification.dart'; import 'package:nhancepolicy/excel_verification.dart';
@ -10,6 +11,7 @@ import 'package:nhancepolicy/hrVerify.dart';
import 'package:nhancepolicy/models/environment.dart'; import 'package:nhancepolicy/models/environment.dart';
import 'package:nhancepolicy/phone.dart'; import 'package:nhancepolicy/phone.dart';
import 'package:nhancepolicy/postFileUpload.dart'; import 'package:nhancepolicy/postFileUpload.dart';
import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:nhancepolicy/verify.dart'; import 'package:nhancepolicy/verify.dart';
import 'package:nhancepolicy/home.dart'; import 'package:nhancepolicy/home.dart';
import 'package:nhancepolicy/hrDashboard.dart'; import 'package:nhancepolicy/hrDashboard.dart';
@ -28,8 +30,23 @@ Future<void> main() async {
// print('Local Storage cleared by window'); // print('Local Storage cleared by window');
// html.window.localStorage.clear(); // html.window.localStorage.clear();
// }); // });
// Ask confirmation (browser may or may not show it again)
// html.window.onBeforeUnload.listen((event) {
// final e = event as html.BeforeUnloadEvent;
// e.preventDefault();
// e.returnValue = '';
// });
// Always clear when user leaves (refresh/close)
// html.window.onUnload.listen((event) {
// html.window.localStorage.clear();
// });
// await dotenv.load(fileName: Environment.fileName); // await dotenv.load(fileName: Environment.fileName);
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// Initialize token storage
await TokenStorageService().initialize();
await Firebase.initializeApp( await Firebase.initializeApp(
options: const FirebaseOptions( options: const FirebaseOptions(
apiKey: 'AIzaSyCSvDM5fG2blDBE69Cae3S-iYRwwNBy7xo', apiKey: 'AIzaSyCSvDM5fG2blDBE69Cae3S-iYRwwNBy7xo',
@ -57,7 +74,9 @@ Future<void> main() async {
routes: { routes: {
'phone': (context) => MyPhone(), 'phone': (context) => MyPhone(),
'mailVerify': (context) => MyEmailVerify( 'mailVerify': (context) => MyEmailVerify(
email: '', type: '',
value: '',
), ),
'verify': (context) => MyVerify( 'verify': (context) => MyVerify(
verificationId: '', verificationId: '',
@ -130,6 +149,7 @@ Future<void> main() async {
cardPolicy_ExpDate: '', cardPolicy_ExpDate: '',
), ),
'oldPolicy': (context) => oldPolicy(), 'oldPolicy': (context) => oldPolicy(),
'branchSelection': (context) => BranchSelectionPage(),
}, },
)); ));
} }

View File

@ -19,8 +19,8 @@ class ApiService {
Future<void> _initializeToken() async { Future<void> _initializeToken() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
_token = prefs.getString('token') ?? ''; _token = prefs.getString('token') ?? '';
final hrprefs = await SharedPreferences.getInstance(); // final hrprefs = await SharedPreferences.getInstance();
_hrtoken = hrprefs.getString('hrtoken') ?? ''; // _hrtoken = hrprefs.getString('hrtoken') ?? '';
} }
Future<void> getTokenLoadAPI(token) async { Future<void> getTokenLoadAPI(token) async {

View File

@ -0,0 +1,157 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
class TokenStorageService {
static final TokenStorageService _instance = TokenStorageService._internal();
factory TokenStorageService() => _instance;
TokenStorageService._internal();
// Storage keys
static const String _preEnrollmentKey = 'pre_enrollment_data';
static const String _postEnrollmentKey = 'post_enrollment_data';
static const String _selectedBranchKey = 'selected_branch';
static const String _decodedTokenKey = 'decoded_token';
// In-memory cache
List<dynamic>? _preEnrollmentData;
List<dynamic>? _postEnrollmentData;
Map<String, dynamic>? _selectedBranch;
Map<String, dynamic>? _decodedToken;
// Initialize - Load data from storage
Future<void> initialize() async {
final prefs = await SharedPreferences.getInstance();
final preData = prefs.getString(_preEnrollmentKey);
if (preData != null) {
_preEnrollmentData = json.decode(preData);
}
final postData = prefs.getString(_postEnrollmentKey);
if (postData != null) {
_postEnrollmentData = json.decode(postData);
}
final branchData = prefs.getString(_selectedBranchKey);
if (branchData != null) {
_selectedBranch = json.decode(branchData);
}
final tokenData = prefs.getString(_decodedTokenKey);
if (tokenData != null) {
_decodedToken = json.decode(tokenData);
}
}
// Save enrollment data
Future<void> saveEnrollmentData(List<dynamic> preData, List<dynamic> postData) async {
_preEnrollmentData = preData;
_postEnrollmentData = postData;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_preEnrollmentKey, json.encode(preData));
await prefs.setString(_postEnrollmentKey, json.encode(postData));
}
// Get combined unique branches
List<Map<String, dynamic>> getCombinedBranches() {
List<Map<String, dynamic>> combined = [];
Set<String> seenTokens = {};
Set<String> seenIds = {};
// Add pre-enrollment data
if (_preEnrollmentData != null) {
for (var item in _preEnrollmentData!) {
String token = item['token']?.toString() ?? '';
String uniqueId = '${item['id']}_${item['client_id']}_${item['client_branch_id']}';
if (seenIds.contains(uniqueId)) continue;
if (token.isNotEmpty && seenTokens.contains(token)) continue;
if (token.isNotEmpty) seenTokens.add(token);
seenIds.add(uniqueId);
combined.add({...item, 'enrollment_type': 'pre'});
}
}
// Add post-enrollment data
if (_postEnrollmentData != null) {
for (var item in _postEnrollmentData!) {
String token = item['token']?.toString() ?? '';
String uniqueId = '${item['id']}_${item['client_id']}_${item['client_branch_id']}';
if (seenIds.contains(uniqueId)) continue;
if (token.isNotEmpty && seenTokens.contains(token)) continue;
if (token.isNotEmpty) seenTokens.add(token);
seenIds.add(uniqueId);
combined.add({...item, 'enrollment_type': 'post'});
}
}
return combined;
}
// Save selected branch and decode token
Future<void> saveSelectedBranch(Map<String, dynamic> branch) async {
_selectedBranch = branch;
String token = branch['token']?.toString() ?? '';
if (token.isNotEmpty) {
_decodedToken = _decodeJWT(token);
} else {
_decodedToken = null;
}
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_selectedBranchKey, json.encode(branch));
if (_decodedToken != null) {
await prefs.setString(_decodedTokenKey, json.encode(_decodedToken));
}
}
// Decode JWT token
Map<String, dynamic>? _decodeJWT(String token) {
try {
final parts = token.split('.');
if (parts.length != 3) return null;
final payload = parts[1];
var normalized = base64Url.normalize(payload);
var decoded = utf8.decode(base64Url.decode(normalized));
return json.decode(decoded);
} catch (e) {
print('Error decoding token: $e');
return null;
}
}
// Getters
Map<String, dynamic>? getSelectedBranch() => _selectedBranch;
Map<String, dynamic>? getDecodedToken() => _decodedToken;
String? getCurrentToken() => _selectedBranch?['token'];
bool isLoggedIn() {
return _selectedBranch != null &&
_selectedBranch!['token'] != null &&
_selectedBranch!['token'].toString().isNotEmpty;
}
// Clear all data (logout)
Future<void> clearAll() async {
_preEnrollmentData = null;
_postEnrollmentData = null;
_selectedBranch = null;
_decodedToken = null;
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_preEnrollmentKey);
await prefs.remove(_postEnrollmentKey);
await prefs.remove(_selectedBranchKey);
await prefs.remove(_decodedTokenKey);
}
}