This commit is contained in:
Surendiran 2026-03-17 10:55:37 +05:30
parent ad396fefb0
commit 72b253918a
17 changed files with 3949 additions and 2169 deletions

View File

@ -220,7 +220,7 @@ class _NhanceSideBarState extends State<NhanceSideBar> {
); );
}).toList(), }).toList(),
if(postModules.isNotEmpty) if(postModules.isNotEmpty && postModules.contains(5))
_SideItem( _SideItem(
// icon: Icons.dashboard, // icon: Icons.dashboard,
icon: SvgPicture.string( icon: SvgPicture.string(

View File

@ -69,6 +69,7 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
late String _verificationId; late String _verificationId;
dynamic empMobileNo; dynamic empMobileNo;
dynamic empEmailid; dynamic empEmailid;
final tokenService = TokenStorageService();
@override @override
void initState() { void initState() {
@ -225,12 +226,53 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
// // Show a Snackbar if the OTP is invalid // // Show a Snackbar if the OTP is invalid
// print('Invalid OTP. Please try again'); // print('Invalid OTP. Please try again');
// } // }
} else if (response.statusCode == 401) {
setState(() {
_isLoading = false;
});
await tokenService.clearAll(); // 🔐 clears flutter_secure_storage
ToastHelper.showErrorToast(context, 'Session Out');
if (!context.mounted) return;
Navigator.pushNamedAndRemoveUntil(
context,
'hrLogin',
(route) => false,
);
} else if (response.statusCode == 403) {
setState(() {
_isLoading = false;
});
await tokenService.clearAll(); // 🔐 clears flutter_secure_storage
ToastHelper.showErrorToast(context, 'Session Out');
if (!context.mounted) return;
Navigator.pushNamedAndRemoveUntil(
context,
'hrLogin',
(route) => false,
);
} else if (response.statusCode == 451) {
setState(() {
_isLoading = false;
});
final body = jsonDecode(response.body);
final message = body['message'];
ToastHelper.showWarningToast(context, message);
} else if (response.statusCode == 429) {
setState(() {
_isLoading = false;
});
final body = jsonDecode(response.body);
final message = body['message'];
ToastHelper.showWarningToast(context, message);
} else { } else {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
ToastHelper.showWarningToast(context, 'Something went wrong'); throw Exception('Failed to load data');
throw Exception('Failed to verify OTP');
} }
} catch (e) { } catch (e) {
setState(() { setState(() {

View File

@ -1,6 +1,7 @@
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -12,6 +13,7 @@ import 'package:nhancepolicy/responsive.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:flutter_animated_button/flutter_animated_button.dart'; import 'package:flutter_animated_button/flutter_animated_button.dart';
import 'package:nhancepolicy/service/token_storage_service.dart'; import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:url_launcher/url_launcher.dart';
import 'config/environment.dart'; import 'config/environment.dart';
import 'email_verify.dart'; import 'email_verify.dart';
@ -517,48 +519,106 @@ class _MyPhoneState extends State<MyHrLogin> {
), ),
SizedBox(height: 20), SizedBox(height: 20),
Container( Container(
width: double width: double.infinity,
.infinity, // Make the footer full width alignment: Alignment.bottomCenter,
child: Container( padding: const EdgeInsets.symmetric(vertical: 8),
alignment: Alignment.bottomCenter, child: RichText(
padding: textAlign: TextAlign.center,
EdgeInsets.symmetric(vertical: 8), text: TextSpan(
child: RichText( text: 'By continuing, you agree with our ',
textAlign: TextAlign.center, style: GoogleFonts.poppins(
text: TextSpan( color: Colors.black,
text: fontSize: 9,
'By continuing, you agree with our ',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 9,
),
children: <TextSpan>[
TextSpan(
text: 'privacy policy ',
style: GoogleFonts.poppins(
color: Color(0xFFE26828),
fontSize: 9,
),
),
TextSpan(
text: 'and ',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 9,
),
),
TextSpan(
text: 'terms of use',
style: GoogleFonts.poppins(
color: Color(0xFFE26828),
fontSize: 9,
),
),
],
), ),
children: [
TextSpan(
text: 'privacy policy ',
style: GoogleFonts.poppins(
color: const Color(0xFFE26828),
fontSize: 9,
// decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
final url = Uri.parse(
'https://nhanceindia.in/privacy-policy/');
if (await canLaunchUrl(url)) {
await launchUrl(url,
mode: LaunchMode.externalApplication);
}
},
),
TextSpan(
text: 'and ',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 9,
),
),
TextSpan(
text: 'terms of use',
style: GoogleFonts.poppins(
color: const Color(0xFFE26828),
fontSize: 9,
// decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
final url = Uri.parse(
'https://nhanceindia.in/privacy-policy/');
if (await canLaunchUrl(url)) {
await launchUrl(url,
mode: LaunchMode.externalApplication);
}
},
),
],
), ),
), ),
), ),
// Container(
// width: double
// .infinity, // Make the footer full width
// child: Container(
// alignment: Alignment.bottomCenter,
// padding:
// EdgeInsets.symmetric(vertical: 8),
// child: RichText(
// textAlign: TextAlign.center,
// text: TextSpan(
// text:
// 'By continuing, you agree with our ',
// style: GoogleFonts.poppins(
// color: Colors.black,
// fontSize: 9,
// ),
// children: <TextSpan>[
// TextSpan(
// text: 'privacy policy ',
// style: GoogleFonts.poppins(
// color: Color(0xFFE26828),
// fontSize: 9,
// ),
// ),
// TextSpan(
// text: 'and ',
// style: GoogleFonts.poppins(
// color: Colors.black,
// fontSize: 9,
// ),
// ),
// TextSpan(
// text: 'terms of use',
// style: GoogleFonts.poppins(
// color: Color(0xFFE26828),
// fontSize: 9,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
], ],
), ),
), ),

View File

@ -62,117 +62,282 @@ Future<void> startApp() async {
projectId: 'nhance-ee8d1')); projectId: 'nhance-ee8d1'));
// await dotenv.load(fileName: Environment.fileName); // await dotenv.load(fileName: Environment.fileName);
runApp(MaterialApp( // runApp(MaterialApp(
title: 'Nhance HR', // title: 'Nhance HR',
onGenerateTitle: (context) => "Nhance HR", // onGenerateTitle: (context) => "Nhance HR",
initialRoute: 'hrLogin', // initialRoute: 'hrLogin',
debugShowCheckedModeBanner: false, // debugShowCheckedModeBanner: false,
theme: ThemeData( // theme: ThemeData(
primaryColor: Color(0xFF00999E), // Primary theme color // primaryColor: Color(0xFF00999E), // Primary theme color
scaffoldBackgroundColor: Colors.white, // scaffoldBackgroundColor: Colors.white,
colorScheme: ColorScheme.fromSeed( // colorScheme: ColorScheme.fromSeed(
seedColor: Color(0xFF00999E), // seedColor: Color(0xFF00999E),
), // ),
textTheme: GoogleFonts.poppinsTextTheme(), // textTheme: GoogleFonts.poppinsTextTheme(),
elevatedButtonTheme: ElevatedButtonThemeData( // elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom( // style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF00999E), // Button background // backgroundColor: Color(0xFF00999E), // Button background
// ),
// ),
// ),
// routes: {
// 'phone': (context) => MyPhone(),
// 'mailVerify': (context) => MyEmailVerify(
// type: '',
// value: '',
//
// ),
// 'verify': (context) => MyVerify(
// verificationId: '',
// mobileNumber: '',
// resendToken: null,
// onResendCode: (String, int) {},
// ),
// 'home': (context) => MyApp(),
// 'hrLogin': (context) => MyHrLogin(),
// // 'hrVerify': (context) => MyHrVerify(
// // verificationId: '',
// // mobileNumber: '',
// // resendToken: null,
// // onResendCode: (String, int) {},
// // ),
// 'hrHome': (context) => MyHrHome(),
// 'preFileUpload': (context) => const preFileUpload(
// ClientId: '',
// policyTypeId: '',
// ClientPoliyId: '',
// clientBranchId: '',
// Token: '',
// TokenType: '',
// cardType: '',
// cardPolicyNo: '',
// cardInsurer_name: '',
// cardPolicy_name: '',
// cardPolicy_ExpDate: '',
// total_premium: '',
// ),
// 'postFileUpload': (context) => const postFileUpload(
// ClientId: '',
// policyTypeId: '',
// ClientPoliyId: '',
// clientBranchId: '',
// Token: '',
// TokenType: '',
// cardType: '',
// cardPolicyNo: '',
// cardInsurer_name: '',
// cardPolicy_name: '',
// cardPolicy_ExpDate: '',
// total_premium: '',
// ),
// 'excelErrorScreen': (context) => const excelErrorScreen(
// ClientId: '',
// policy_no: '',
// action: '',
// created_at: '',
// clientBranchId: '',
// Token: '',
// TokenType: '',
// id: ''
// ),
// 'empDetails': (context) => empDetails(),
// 'addOnsDetails': (context) => addOnsDetails(),
// 'empReviewDetails': (context) => empReviewDetails(),
// 'hrDashboard': (context) => hrDashboard(),
// 'hrPolicyDetails': (context) => hrPolicyDetails(
// ClientId: '',
// policyTypeId: '',
// ClientPoliyId: '',
// clientBranchId: '',
// Token: '',
// TokenType: '',
// cardType: '',
// cardPolicyNo: '',
// cardInsurer_name: '',
// cardPolicy_name: '',
// cardPolicy_ExpDate: '',
// total_premium: '',
// is_ecard_bulk_download_for_employee: 0,
// ),
// 'oldPolicy': (context) => oldPolicy(),
// 'branchSelection': (context) => BranchSelectionPage(),
// 'policies': (context) => policies(),
// 'CdPoliciesList': (context) => CdPoliciesList(),
// 'ClaimsPolicies': (context) => ClaimsPolicies(
// empCode:'',
// ),
// 'cdTransactionDetails': (context) => cdTransactionDetails(
// insurerName: '',
// cdMasterAccountNo: '',
// insurerId: '',
// cd_ac_pk: '',
// empClientId: '',
// ),
// },
// ));
final tokenService = TokenStorageService();
final token = await tokenService.getCurrentToken();
runApp(MyApp(initialToken: token));
}
class MyApp extends StatelessWidget {
final String? initialToken;
const MyApp({super.key, this.initialToken});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Nhance HR',
debugShowCheckedModeBanner: false,
initialRoute: (initialToken == null || initialToken!.isEmpty)
? 'hrLogin'
: 'hrHome',
theme: ThemeData(
primaryColor: const Color(0xFF00999E),
scaffoldBackgroundColor: Colors.white,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF00999E),
),
textTheme: GoogleFonts.poppinsTextTheme(),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF00999E),
),
), ),
), ),
), routes: appRoutes,
routes: { );
'phone': (context) => MyPhone(), }
'mailVerify': (context) => MyEmailVerify( }
type: '',
value: '', final Map<String, WidgetBuilder> appRoutes = {
'phone': (context) => MyPhone(),
), 'mailVerify': (context) => MyEmailVerify(
'verify': (context) => MyVerify( type: '',
verificationId: '', value: '',
mobileNumber: '',
resendToken: null, ),
onResendCode: (String, int) {}, 'verify': (context) => MyVerify(
), verificationId: '',
'home': (context) => MyApp(), mobileNumber: '',
'hrLogin': (context) => MyHrLogin(), resendToken: null,
// 'hrVerify': (context) => MyHrVerify( onResendCode: (String, int) {},
// verificationId: '', ),
// mobileNumber: '', 'home': (context) => MyApp(),
// resendToken: null, 'hrLogin': (context) => MyHrLogin(),
// onResendCode: (String, int) {}, // 'hrVerify': (context) => MyHrVerify(
// ), // verificationId: '',
'hrHome': (context) => MyHrHome(), // mobileNumber: '',
'preFileUpload': (context) => const preFileUpload( // resendToken: null,
ClientId: '', // onResendCode: (String, int) {},
policyTypeId: '', // ),
ClientPoliyId: '', 'hrHome': (context) => MyHrHome(),
clientBranchId: '', 'preFileUpload': (context) => const preFileUpload(
Token: '', ClientId: '',
TokenType: '', policyTypeId: '',
cardType: '', ClientPoliyId: '',
cardPolicyNo: '', clientBranchId: '',
cardInsurer_name: '', Token: '',
cardPolicy_name: '', TokenType: '',
cardPolicy_ExpDate: '', cardType: '',
total_premium: '', cardPolicyNo: '',
), cardInsurer_name: '',
'postFileUpload': (context) => const postFileUpload( cardPolicy_name: '',
ClientId: '', cardPolicy_ExpDate: '',
policyTypeId: '', total_premium: '',
ClientPoliyId: '', ),
clientBranchId: '', 'postFileUpload': (context) => const postFileUpload(
Token: '', ClientId: '',
TokenType: '', policyTypeId: '',
cardType: '', ClientPoliyId: '',
cardPolicyNo: '', clientBranchId: '',
cardInsurer_name: '', Token: '',
cardPolicy_name: '', TokenType: '',
cardPolicy_ExpDate: '', cardType: '',
total_premium: '', cardPolicyNo: '',
), cardInsurer_name: '',
'excelErrorScreen': (context) => const excelErrorScreen( cardPolicy_name: '',
ClientId: '', cardPolicy_ExpDate: '',
policy_no: '', total_premium: '',
action: '', ),
created_at: '', 'excelErrorScreen': (context) => const excelErrorScreen(
clientBranchId: '', ClientId: '',
Token: '', policy_no: '',
TokenType: '', action: '',
id: '' created_at: '',
), clientBranchId: '',
'empDetails': (context) => empDetails(), Token: '',
'addOnsDetails': (context) => addOnsDetails(), TokenType: '',
'empReviewDetails': (context) => empReviewDetails(), id: ''
'hrDashboard': (context) => hrDashboard(), ),
'hrPolicyDetails': (context) => hrPolicyDetails( 'empDetails': (context) => empDetails(),
ClientId: '', 'addOnsDetails': (context) => addOnsDetails(),
policyTypeId: '', 'empReviewDetails': (context) => empReviewDetails(),
ClientPoliyId: '', 'hrDashboard': (context) => hrDashboard(),
clientBranchId: '', 'hrPolicyDetails': (context) => hrPolicyDetails(
Token: '', ClientId: '',
TokenType: '', policyTypeId: '',
cardType: '', ClientPoliyId: '',
cardPolicyNo: '', clientBranchId: '',
cardInsurer_name: '', Token: '',
cardPolicy_name: '', TokenType: '',
cardPolicy_ExpDate: '', cardType: '',
total_premium: '', cardPolicyNo: '',
is_ecard_bulk_download_for_employee: 0, cardInsurer_name: '',
), cardPolicy_name: '',
'oldPolicy': (context) => oldPolicy(), cardPolicy_ExpDate: '',
'branchSelection': (context) => BranchSelectionPage(), total_premium: '',
'policies': (context) => policies(), is_ecard_bulk_download_for_employee: 0,
'CdPoliciesList': (context) => CdPoliciesList(), ),
'ClaimsPolicies': (context) => ClaimsPolicies( 'oldPolicy': (context) => oldPolicy(),
empCode:'', 'branchSelection': (context) => BranchSelectionPage(),
), 'policies': (context) => policies(),
'cdTransactionDetails': (context) => cdTransactionDetails( 'CdPoliciesList': (context) => CdPoliciesList(),
insurerName: '', 'ClaimsPolicies': (context) => ClaimsPolicies(
cdMasterAccountNo: '', empCode:'',
insurerId: '', ),
cd_ac_pk: '', 'cdTransactionDetails': (context) => cdTransactionDetails(
empClientId: '', insurerName: '',
), cdMasterAccountNo: '',
}, insurerId: '',
)); cd_ac_pk: '',
empClientId: '',
),
};
/// 🔐 Global Auth Wrapper (Protects All Pages)
class AuthWrapper extends StatefulWidget {
final Widget child;
const AuthWrapper({super.key, required this.child});
@override
State<AuthWrapper> createState() => _AuthWrapperState();
}
class _AuthWrapperState extends State<AuthWrapper> {
@override
void initState() {
super.initState();
_checkLogin();
}
void _checkLogin() {
final token = TokenStorageService().getCurrentToken();
if (token == null || token.isEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pushNamedAndRemoveUntil(
context, 'hrLogin', (route) => false);
});
}
}
@override
Widget build(BuildContext context) {
return widget.child;
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -73,11 +73,12 @@ class _CdPoliciesListState extends State<CdPoliciesList> {
} }
Future<void> checkIds() async { Future<void> checkIds() async {
print('checkIds');
_postPreToken = await tokenService.getCurrentToken(); _postPreToken = await tokenService.getCurrentToken();
empClientId = await tokenService.readValue('empClientId'); empClientId = await tokenService.readValue('empClientId');
// empClientBranchId = await tokenService.readValue('empClientBranchId'); // empClientBranchId = await tokenService.readValue('empClientBranchId');
empHrId = await tokenService.readValue('empHrId'); empHrId = await tokenService.readValue('empHrId');
print('$_postPreToken - $empClientId - $empHrId');
await getCDPoliciesDetails(empClientId, empHrId, _postPreToken); await getCDPoliciesDetails(empClientId, empHrId, _postPreToken);
} }
@ -165,7 +166,7 @@ class _CdPoliciesListState extends State<CdPoliciesList> {
rows.add([ rows.add([
item['insurer_name'] ?? '', item['insurer_name'] ?? '',
item['cd_master_account_no'] ?? '', item['cd_master_account_no'] ?? '',
'${item['balance'] ?? '0'}', '${item['balance'] ?? '0'}',
]); ]);
} }
@ -393,6 +394,30 @@ class _CdPoliciesListState extends State<CdPoliciesList> {
return InkWell( return InkWell(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
onTap: () async { onTap: () async {
await tokenService.writeValue(
'hr_cd_insurer_name',
filteredData[index]['insurer_name'].toString(),
);
await tokenService.writeValue(
'hr_cd_master_account_no',
filteredData[index]['cd_master_account_no'].toString(),
);
await tokenService.writeValue(
'hr_cd_insurer_id',
filteredData[index]['insurer_id'].toString(),
);
await tokenService.writeValue(
'hr_cd_ac_pk',
filteredData[index]['cd_ac_pk'].toString(),
);
await tokenService.writeValue(
'hr_empClientId',
empClientId.toString(),
);
Navigator.push( Navigator.push(
context, context,
@ -462,7 +487,8 @@ class _CDPolicyCard extends StatelessWidget {
Expanded( Expanded(
flex: 3, flex: 3,
child: Text( child: Text(
"${balance.toStringAsFixed(0)}", data['balance'] ?? '',
// "${balance.toStringAsFixed(0)}",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,

View File

@ -1,7 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:csv/csv.dart'; import 'package:csv/csv.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -13,12 +12,12 @@ import 'package:nhancepolicy/service/api_service.dart';
import 'package:nhancepolicy/service/token_storage_service.dart'; import 'package:nhancepolicy/service/token_storage_service.dart';
import 'package:universal_html/html.dart' as html; import 'package:universal_html/html.dart' as html;
import 'package:collection/collection.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../config/environment.dart';
import '../customAppBar/base_layout.dart'; import '../customAppBar/base_layout.dart';
import '../customAppBar/customAppBar.dart'; import 'cdList.dart';
import '../customAppBar/customFooter.dart'; import 'claims.dart';
class cdTransactionDetails extends StatefulWidget { class cdTransactionDetails extends StatefulWidget {
final String insurerName; final String insurerName;
@ -42,6 +41,14 @@ class cdTransactionDetails extends StatefulWidget {
} }
class _cdTransactionDetailsState extends State<cdTransactionDetails> { class _cdTransactionDetailsState extends State<cdTransactionDetails> {
String? localInsurerId;
String? localCdAcPk;
String? localEmpClientId;
String? localInsurerName;
String? localCdMasterAccountNo;
final tokenService = TokenStorageService(); final tokenService = TokenStorageService();
Uint8List? fileBytes; Uint8List? fileBytes;
List<Map<String, dynamic>> getCDTransData = []; List<Map<String, dynamic>> getCDTransData = [];
@ -85,7 +92,9 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
void initState() { void initState() {
super.initState(); super.initState();
apiService = ApiService(context); // Initialize ApiService here apiService = ApiService(context); // Initialize ApiService here
getCdTransactionDetails();
restoreTransactionData();
} }
@override @override
@ -93,9 +102,51 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
super.dispose(); super.dispose();
} }
// downloadPolicyFiles?file_id=13 // downloadPolicyFiles?file_id=13
// getPolicyAndEndorsementFiles?cd_ac_pk=12 // getPolicyAndEndorsementFiles?cd_ac_pk=12
Future<void> restoreTransactionData() async {
localInsurerId = widget.insurerId.trim().isNotEmpty
? widget.insurerId
: await tokenService.readValue('hr_cd_insurer_id');
localCdAcPk = widget.cd_ac_pk.trim().isNotEmpty
? widget.cd_ac_pk
: await tokenService.readValue('hr_cd_ac_pk');
localEmpClientId = widget.empClientId.trim().isNotEmpty
? widget.empClientId
: await tokenService.readValue('hr_empClientId');
localInsurerName = widget.insurerName.trim().isNotEmpty
? widget.insurerName
: await tokenService.readValue('hr_cd_insurer_name');
localCdMasterAccountNo = widget.cdMasterAccountNo.trim().isNotEmpty
? widget.cdMasterAccountNo
: await tokenService.readValue('hr_cd_master_account_no');
print('restore localInsurerId = $localInsurerId');
print('restore localCdAcPk = $localCdAcPk');
print('restore localEmpClientId = $localEmpClientId');
if (localInsurerId != null &&
localCdAcPk != null &&
localEmpClientId != null) {
getCdTransactionDetails();
}
}
Future<void> clearPolicyStorage() async {
await tokenService.removeValue('hr_cd_insurer_id');
await tokenService.removeValue('hr_cd_ac_pk');
await tokenService.removeValue('hr_empClientId');
await tokenService.removeValue('hr_cd_insurer_name');
await tokenService.removeValue('hr_cd_master_account_no');
}
Future<void> getCdTransactionDetails() async { Future<void> getCdTransactionDetails() async {
print('9'); print('9');
setState(() { setState(() {
@ -104,8 +155,8 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
try { try {
print('10'); print('10');
final _postPreToken = await tokenService.getCurrentToken(); final _postPreToken = await tokenService.getCurrentToken();
final response = await apiService.getCdTransactionData(widget.empClientId, final response = await apiService.getCdTransactionData(localEmpClientId!,
widget.insurerId, widget.cd_ac_pk, _postPreToken!); localInsurerId!, localCdAcPk!, _postPreToken!);
if (response['status'] == 'success') { if (response['status'] == 'success') {
setState(() { setState(() {
isLoading = false; isLoading = false;
@ -115,11 +166,16 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
List<Map<String, dynamic>>.from(response['data']['deposit_data']); List<Map<String, dynamic>>.from(response['data']['deposit_data']);
originalData = getCDTransData; originalData = getCDTransData;
filteredData = List.from(originalData); filteredData = List.from(originalData);
total_deposit = formatAmount(response['data']['total_deposit']); total_deposit = response['data']['total_deposit'];
total_consumed = formatAmount(response['data']['total_consumed']); // total_deposit = formatAmount(response['data']['total_deposit']);
total_refund = formatAmount(response['data']['total_refund']); total_consumed = response['data']['total_consumed'];
currect_balance = formatAmount(response['data']['currect_balance']); // total_consumed = formatAmount(response['data']['total_consumed']);
insurer_short_name = formatAmount(response['data']['insurer_short_name']); total_refund = response['data']['total_refund'];
// total_refund = formatAmount(response['data']['total_refund']);
currect_balance = response['data']['currect_balance'];
// currect_balance = formatAmount(response['data']['currect_balance']);
insurer_short_name = response['data']['insurer_short_name'];
// insurer_short_name = formatAmount(response['data']['insurer_short_name']);
print('filteredData'); print('filteredData');
print(filteredData); print(filteredData);
}); });
@ -144,25 +200,53 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
} }
} }
Future<void> _openEndorsementFile(id) async { Future<void> _openEndorsementFile(id, file_name) async {
print('9'); // final http.Response response = await apiService.getHrFileDownloadToApi(id, widget.Token);
try { final _postPreToken = await tokenService.getCurrentToken();
print('10'); print("**********-------*****");
final _postPreToken = await tokenService.getCurrentToken(); final apiurl = Environment.apiUrlPost;
final response = await apiService.getOpenEndorsementFileData(id, _postPreToken!); final String url = '$apiurl/downloadPolicyFiles?file_id=$id';
if (response['status'] == false) {
ToastHelper.showErrorToast(context, response['message']);
} else {
// ToastHelper.showWarningToast( final response = await http.get(
// context, 'Request failed with status: ${response.statusCode}'); Uri.parse(url),
print('Request failed with status: ${response['code']}'); headers: {
'APP-SIGNATURE':
'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
'Authorization': 'Bearer $_postPreToken',
'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
},
);
if (response.statusCode == 200) {
try {
print("PDF Downloaded");
// Create a blob from the response body bytes
final blob = html.Blob([response.bodyBytes]);
// Generate a download URL
final url = html.Url.createObjectUrlFromBlob(blob);
// Trigger file download automatically
final anchor = html.AnchorElement(href: url)
..setAttribute('download', '$file_name')
..click();
// Revoke the URL to free memory
html.Url.revokeObjectUrl(url);
ToastHelper.showSuccessToast(context, 'File Downloaded Successfully');
} catch (e) {
throw Exception('Error parsing response: $e');
} }
} catch (e) { } else {
print('Exception occurred: $e'); ToastHelper.showErrorToast(context, 'Failed to download');
print("Download failed with status: ${response.statusCode}");
} }
} }
Future<void> getCdEndorsementDetails(id) async { Future<void> getCdEndorsementDetails(id) async {
print('9'); print('9');
setState(() { setState(() {
@ -243,7 +327,7 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
), ),
onTap: () { onTap: () {
// Navigator.pop(context); // close popup // Navigator.pop(context); // close popup
_openEndorsementFile(file['id']); _openEndorsementFile(file['id'],file['file_name']);
}, },
); );
}, },
@ -387,9 +471,12 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
: '-', : '-',
item['endorsement_no'] ?? '', item['endorsement_no'] ?? '',
item['sub_type_text'] ?? '', item['sub_type_text'] ?? '',
item['transaction_type'] == 'Credit' ? '${formatAmount(item['amount'])}' : '-', item['transaction_type'] == 'Credit' ? '${item['amount']}' : '-',
item['transaction_type'] == 'Debit' ? '${formatAmount(item['amount'])}' : '-', // item['transaction_type'] == 'Credit' ? '${formatAmount(item['amount'])}' : '-',
'${formatAmount(item['balance']) ?? '0'}', item['transaction_type'] == 'Debit' ? '${item['amount']}' : '-',
// item['transaction_type'] == 'Debit' ? '${formatAmount(item['amount'])}' : '-',
'${item['balance'] ?? '0'}',
// '${formatAmount(item['balance']) ?? '0'}',
item['description'] ?? '', item['description'] ?? '',
item['username'] ?? '', item['username'] ?? '',
]); ]);
@ -541,7 +628,21 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
children: [ children: [
IconButton( IconButton(
tooltip: 'Previous Page', tooltip: 'Previous Page',
onPressed: () => Navigator.pop(context), onPressed: () async {
await clearPolicyStorage();
if (Navigator.canPop(context)) {
Navigator.pop(context);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
settings: const RouteSettings(name: 'cdPoliciesList'),
builder: (_) => CdPoliciesList(),
),
);
}
},
icon: const Icon( icon: const Icon(
Icons.arrow_back_ios, Icons.arrow_back_ios,
size: 18, size: 18,
@ -552,7 +653,7 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
'Transaction Details - ${insurer_short_name} (${widget.cdMasterAccountNo})', 'Transaction Details - ${insurer_short_name} (${localCdMasterAccountNo ?? widget.cdMasterAccountNo})',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -762,21 +863,36 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
SizedBox(width: 10), SizedBox(width: 10),
_cell( _cell(
item['transaction_type'] == 'Credit' item['transaction_type'] == 'Credit'
? formatAmount(item['amount']) ? item['amount']
: '-', : '-',
2, 2,
alignRight: true, alignRight: true,
), ),
// _cell(
// item['transaction_type'] == 'Credit'
// ? formatAmount(item['amount'])
// : '-',
// 2,
// alignRight: true,
// ),
SizedBox(width: 10), SizedBox(width: 10),
_cell( _cell(
item['transaction_type'] == 'Debit' item['transaction_type'] == 'Debit'
? formatAmount(item['amount']) ? item['amount']
: '-', : '-',
2, 2,
alignRight: true, alignRight: true,
), ),
// _cell(
// item['transaction_type'] == 'Debit'
// ? formatAmount(item['amount'])
// : '-',
// 2,
// alignRight: true,
// ),
SizedBox(width: 10), SizedBox(width: 10),
_cell(formatAmount(item['balance']), 2, alignRight: true), _cell(item['balance'], 2, alignRight: true),
// _cell(formatAmount(item['balance']), 2, alignRight: true),
SizedBox(width: 10), SizedBox(width: 10),
_cell(item['description'], 3), _cell(item['description'], 3),
SizedBox(width: 10), SizedBox(width: 10),
@ -784,25 +900,72 @@ class _cdTransactionDetailsState extends State<cdTransactionDetails> {
SizedBox(width: 10), SizedBox(width: 10),
Expanded( Expanded(
flex: 2, flex: 2,
child: Row( child: SizedBox(
mainAxisAlignment: MainAxisAlignment.center, height: 36,
children: [ child: Row(
if (isAllowedSubType) mainAxisAlignment: MainAxisAlignment.center,
_ActionIconButton( children: [
icon: Icons.picture_as_pdf_outlined,
toolTip: 'View Endorsement PDF', /// --- PDF ICON SLOT ---
onTap: () => getCdEndorsementDetails(item['id']), SizedBox(
width: 36,
height: 36,
child: Visibility(
visible: isAllowedSubType,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: _ActionIconButton(
icon: Icons.picture_as_pdf_outlined,
toolTip: 'View Endorsement PDF',
onTap: () => getCdEndorsementDetails(item['id']),
),
),
), ),
const SizedBox(width: 8),
if (isAllowedSubType && hasSplitUpFile) const SizedBox(width: 8),
_ActionIconButton(
icon: Icons.folder_open_outlined, /// --- FOLDER ICON SLOT ---
toolTip: 'View Files', SizedBox(
onTap: () => _launchURL(item['split_up_url']), width: 36,
height: 36,
child: Visibility(
visible: isAllowedSubType && hasSplitUpFile,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: _ActionIconButton(
icon: Icons.folder_open_outlined,
toolTip: 'View Files',
onTap: () => _launchURL(item['split_up_url']),
),
),
), ),
], ],
),
), ),
), ),
// Expanded(
// flex: 2,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// if (isAllowedSubType)
// _ActionIconButton(
// icon: Icons.picture_as_pdf_outlined,
// toolTip: 'View Endorsement PDF',
// onTap: () => getCdEndorsementDetails(item['id']),
// ),
// const SizedBox(width: 8),
// if (isAllowedSubType && hasSplitUpFile)
// _ActionIconButton(
// icon: Icons.folder_open_outlined,
// toolTip: 'View Files',
// onTap: () => _launchURL(item['split_up_url']),
// ),
// ],
// ),
// ),
], ],
), ),
); );

View File

@ -66,6 +66,8 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
return filteredData.sublist(startIndex, endIndex); return filteredData.sublist(startIndex, endIndex);
} }
int? appliedClaimStatus;
Color getStatusColor(String status) { Color getStatusColor(String status) {
switch (status.toLowerCase()) { switch (status.toLowerCase()) {
case 'claim received': case 'claim received':
@ -182,7 +184,7 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
}); });
try { try {
print('10'); print('10');
final response = await apiService.getClaimPoliciesToApi(_postPreToken!); final response = await apiService.getClaimPoliciesToApi(_postPreToken!,'');
if (response['status'] == 'success') { if (response['status'] == 'success') {
setState(() { setState(() {
isLoading = false; isLoading = false;
@ -272,6 +274,9 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
final data = claim_Detials(); final data = claim_Detials();
print("data -- $data"); print("data -- $data");
getClaimList(); getClaimList();
setState(() {
appliedClaimStatus = selectedClaimStatus; // apply only after API call
});
} }
Future<void> reset() async { Future<void> reset() async {
@ -285,6 +290,7 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
selectedClaimStatus = null; selectedClaimStatus = null;
selectedClaimStatusName = null; selectedClaimStatusName = null;
_currentPage = 1; _currentPage = 1;
appliedClaimStatus = null;
getClaimList(); getClaimList();
}); });
@ -482,16 +488,19 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
/// 🔙 Back + Title (LEFT) /// 🔙 Back + Title (LEFT)
Row( Row(
children: [ children: [
// IconButton( if(widget.empCode.isNotEmpty)
// onPressed: () => {}, IconButton(
// icon: const Icon( onPressed: () => {
// Icons.arrow_back_ios, Navigator.of(context).pop(),
// size: 18, },
// color: Colors.black, icon: const Icon(
// ), Icons.arrow_back_ios,
// padding: EdgeInsets.zero, size: 18,
// constraints: const BoxConstraints(), color: Colors.black,
// ), ),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
'Claims', 'Claims',
@ -707,11 +716,6 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
); );
} }
Widget _buildDataRow(Map<String, dynamic> item) { Widget _buildDataRow(Map<String, dynamic> item) {
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
@ -866,21 +870,28 @@ class _ClaimsPolicieState extends State<ClaimsPolicies> {
if (statusMaster.isEmpty) return const SizedBox(); if (statusMaster.isEmpty) return const SizedBox();
final List<dynamic> displayStatuses = appliedClaimStatus != null
? statusMaster.where((status) =>
int.parse(status['id'].toString()) == appliedClaimStatus)
.toList()
: statusMaster;
return SizedBox( return SizedBox(
height: 30, height: 35,
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: statusMaster.length, itemCount: displayStatuses.length,
separatorBuilder: (_, __) => const SizedBox(width: 10), separatorBuilder: (_, __) => const SizedBox(width: 10),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final statusName = final statusName =
statusMaster[index]['claim_status']?.toString() ?? ''; displayStatuses[index]['claim_status']?.toString() ?? '';
final count = getStatusCount(statusName); final count = getStatusCount(statusName);
final color = getStatusColor(statusName); final color = getStatusColor(statusName);
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color, color: color,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),

View File

@ -34,6 +34,9 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
final tokenService = TokenStorageService(); final tokenService = TokenStorageService();
final FocusNode _policyFocusNode = FocusNode(); final FocusNode _policyFocusNode = FocusNode();
bool isTpaDashboardEnabled = false;
bool isTpaSelected = false;
// Variables for API data // Variables for API data
dynamic empClientBranchId; dynamic empClientBranchId;
dynamic empHrId; dynamic empHrId;
@ -41,6 +44,7 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
String? _postPreToken = ''; String? _postPreToken = '';
int stausVal = 1; int stausVal = 1;
bool _isPolicyDropdownOpen = false; bool _isPolicyDropdownOpen = false;
html.IFrameElement? _currentIframe;
@override @override
void initState() { void initState() {
@ -114,17 +118,32 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
_metabaseLoaded = false; _metabaseLoaded = false;
}); });
// REMOVE OLD IFRAME COMPLETELY
_currentIframe?.remove();
_currentIframe = null;
// CLEAR OLD VIEW TYPES
_registeredViewTypes.clear();
final response = await apiService.postHrDashboard({ final response = await apiService.postHrDashboard({
"client_id": empClientId, "client_id": empClientId,
"client_policy_id": clientPolicyId, "client_policy_id": clientPolicyId,
}, _postPreToken); }, _postPreToken);
if (response['status'] == 'success') { if (response['status'] == 'success') {
// ADD THIS LINE
isTpaDashboardEnabled = response['is_tpa_dashboard_enable'] == true;
setState(() {
isTpaSelected = false;
});
_registerMetabaseIframe( _registerMetabaseIframe(
token: response['data']['metabaseToken'], token: response['data']['metabaseToken'],
url: response['data']['metabaseUrl'], url: response['data']['metabaseUrl'],
clientPolicyId: clientPolicyId, clientPolicyId: clientPolicyId,
); );
setState(() => _metabaseLoaded = true); setState(() => _metabaseLoaded = true);
} else { } else {
ToastHelper.showErrorToast(context, response['message']); ToastHelper.showErrorToast(context, response['message']);
@ -136,26 +155,74 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
} }
} }
Future<void> _loadTpaDashboard(String clientPolicyId) async {
try {
setState(() {
isDashboardLoading = true;
_metabaseLoaded = false;
});
// REMOVE OLD IFRAME
_currentIframe?.remove();
_currentIframe = null;
_registeredViewTypes.clear();
final response = await apiService.postHrTpaDashboard({
"client_id": empClientId,
"client_policy_id": clientPolicyId,
}, _postPreToken);
if (response['status'] == 'success') {
setState(() {
isTpaSelected = true;
});
_registerMetabaseIframe(
token: response['data']['metabaseToken'],
url: response['data']['metabaseUrl'],
clientPolicyId: clientPolicyId,
);
setState(() => _metabaseLoaded = true);
} else {
ToastHelper.showErrorToast(context, response['message']);
}
} catch (e) {
ToastHelper.showErrorToast(context, 'TPA Dashboard loading failed');
} finally {
setState(() => isDashboardLoading = false);
}
}
void _registerMetabaseIframe({ void _registerMetabaseIframe({
required String token, required String token,
required String url, required String url,
required String clientPolicyId, required String clientPolicyId,
}) { }) {
final viewType = 'metabase-dashboard-$clientPolicyId'; // 🔥 ALWAYS CREATE UNIQUE VIEW TYPE
final viewType =
'metabase-dashboard-${clientPolicyId}-${DateTime.now().millisecondsSinceEpoch}';
_dashboardViewType = viewType; _dashboardViewType = viewType;
if (_registeredViewTypes.contains(viewType)) return; final embedUrl =
"$url/embed/dashboard/$token"
"#theme=light&bordered=true&titled=true"
"&v=${DateTime.now().millisecondsSinceEpoch}"; // 🔥 cache buster
final embedUrl = "$url/embed/dashboard/$token#theme=light&bordered=true&titled=true"; final iframe = html.IFrameElement()
..src = embedUrl
..style.border = 'none'
..style.width = '100%'
..style.height = '100%'
..allowFullscreen = true;
_currentIframe = iframe;
ui.platformViewRegistry.registerViewFactory( ui.platformViewRegistry.registerViewFactory(
viewType, viewType,
(int viewId) => html.IFrameElement() (int viewId) => iframe,
..src = embedUrl
..style.border = 'none'
..style.width = '100%'
..style.height = '100%'
..allowFullscreen = true,
); );
_registeredViewTypes.add(viewType); _registeredViewTypes.add(viewType);
@ -185,7 +252,7 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
Widget _buildDashboardView() { Widget _buildDashboardView() {
if (postModules.isNotEmpty && activePoliciesList.isEmpty) { if (postModules.isNotEmpty && activePoliciesList.isEmpty) {
return const Center(child: Text('No dashboard data available for your account')); return const Center(child: Text('No active policy found.'));
} }
return Padding( return Padding(
@ -339,95 +406,127 @@ class _hrDashboardState extends State<hrDashboard> with SingleTickerProviderStat
color: Colors.white, color: Colors.white,
child: Row( child: Row(
children: [ children: [
const Text( if (!isTpaSelected)...[
'Select Policy', const Text(
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 13), 'Select Policy',
), style: TextStyle(fontWeight: FontWeight.w600, fontSize: 13),
const SizedBox(width: 12), ),
SizedBox( const SizedBox(width: 12),
width: 420, SizedBox(
height: 40, width: 420,
child: SearchAnchor( height: 40,
viewBackgroundColor: Colors.white, child: SearchAnchor(
viewConstraints: const BoxConstraints(maxHeight: 220), viewBackgroundColor: Colors.white,
viewConstraints: const BoxConstraints(maxHeight: 220),
builder: (BuildContext context, SearchController controller) {
String displayText = "Select Policy"; builder: (BuildContext context, SearchController controller) {
String displayText = "Select Policy";
if (selectedPolicyId != null) {
final policy = activePoliciesList.firstWhere( if (selectedPolicyId != null) {
(p) => p['client_policy_id'].toString() == selectedPolicyId, final policy = activePoliciesList.firstWhere(
orElse: () => {}, (p) => p['client_policy_id'].toString() == selectedPolicyId,
); orElse: () => {},
if (policy.isNotEmpty) { );
displayText = "${policy['type']} - ${policy['policy_no']}"; if (policy.isNotEmpty) {
} displayText = "${policy['type']} - ${policy['policy_no']}";
} }
}
return InkWell(
onTap: () { return InkWell(
setState(() => _isPolicyDropdownOpen = true); // 🔥 OPEN onTap: () {
controller.openView(); setState(() => _isPolicyDropdownOpen = true); // 🔥 OPEN
}, controller.openView();
child: Container( },
padding: const EdgeInsets.symmetric(horizontal: 12), child: Container(
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 12),
border: Border.all(color: Colors.grey.shade300), decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300),
), borderRadius: BorderRadius.circular(8),
child: Row( ),
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Row(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
Expanded( children: [
child: Text( Expanded(
displayText, child: Text(
style: const TextStyle(fontSize: 12), displayText,
overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12),
), overflow: TextOverflow.ellipsis,
), ),
const Icon(Icons.arrow_drop_down, color: Colors.grey), ),
], const Icon(Icons.arrow_drop_down, color: Colors.grey),
), ],
), ),
); ),
}, );
},
suggestionsBuilder:
(BuildContext context, SearchController controller) { suggestionsBuilder:
final input = controller.text.toLowerCase(); (BuildContext context, SearchController controller) {
final input = controller.text.toLowerCase();
return activePoliciesList
.where((policy) => return activePoliciesList
policy['type'] .where((policy) =>
.toString() policy['type']
.toLowerCase() .toString()
.contains(input) || .toLowerCase()
policy['policy_no'] .contains(input) ||
.toString() policy['policy_no']
.toLowerCase() .toString()
.contains(input)) .toLowerCase()
.map((policy) { .contains(input))
final label = .map((policy) {
"${policy['type']} - ${policy['policy_no']}"; final label =
"${policy['type']} - ${policy['policy_no']}";
return ListTile(
dense: true, return ListTile(
title: Text(label, style: const TextStyle(fontSize: 13)), dense: true,
onTap: () { title: Text(label, style: const TextStyle(fontSize: 13)),
setState(() { onTap: () {
selectedPolicyId = setState(() {
policy['client_policy_id'].toString(); selectedPolicyId =
_isPolicyDropdownOpen = false; // 🔥 CLOSE policy['client_policy_id'].toString();
}); _isPolicyDropdownOpen = false; // 🔥 CLOSE
});
controller.closeView(label);
_loadDashboardByPolicy(selectedPolicyId!); controller.closeView(label);
}, _loadDashboardByPolicy(selectedPolicyId!);
); },
}).toList(); );
}, }).toList();
},
),
),
],
const Spacer(),
if (isTpaDashboardEnabled)
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: isTpaSelected
? Colors.teal
: Colors.grey.shade300,
foregroundColor:
isTpaSelected ? Colors.white : Colors.black,
),
onPressed: () {
if (selectedPolicyId == null) return;
if (isTpaSelected) {
// 🔄 Switch BACK to Normal Dashboard
_loadDashboardByPolicy(selectedPolicyId!);
} else {
// 🔄 Switch TO TPA Dashboard
_loadTpaDashboard(selectedPolicyId!);
}
},
child: Text(
isTpaSelected
? "Insights from Nhance"
: "Insights from TPA ",
),
), ),
),
], ],
), ),
); );

File diff suppressed because it is too large Load Diff

View File

@ -106,43 +106,114 @@ class _policiesState extends State<policies>
} }
} }
// Future<void> _loadToken() async {
// final enrollmentRaw = await tokenService.readValue('enrollmentAllowed_modules'); // "[1]"
// final postRaw = await tokenService.readValue('empAllowed_modules'); // "[2,3,4]"
//
// // Decode safely
// enrollmentModules = enrollmentRaw != null && enrollmentRaw.isNotEmpty
// ? List<int>.from(jsonDecode(enrollmentRaw))
// : [];
//
// postModules = postRaw != null && postRaw.isNotEmpty
// ? List<int>.from(jsonDecode(postRaw))
// : [];
//
// print('enrollmentModules $enrollmentModules');
// print('postModules $postModules');
//
// _postPreToken = await tokenService.getCurrentToken();
// print(_postPreToken);
//
// if (enrollmentModules.contains(1)) {
// enrollmentClient_id = await tokenService.readValue('enrollmentClient_id');
// enrollmentEmpClientBranchId =
// await tokenService.readValue('enrollmentEmpClientBranchId');
// enrollmentHrId = await tokenService.readValue('enrollmentHrId');
//
// await getPreCashDepositDetails(enrollmentEmpClientBranchId,
// enrollmentClient_id, enrollmentHrId, _postPreToken);
// }
//
// if (postModules.contains(2)) {
// empClientId = await tokenService.readValue('empClientId');
// empClientBranchId = await tokenService.readValue('empClientBranchId');
// empHrId = await tokenService.readValue('empHrId');
//
// await getPostCashDepositDetails(empClientBranchId, empClientId, empHrId, _postPreToken);
// }
//
// }
Future<void> _loadToken() async { Future<void> _loadToken() async {
final enrollmentRaw = await tokenService.readValue('enrollmentAllowed_modules'); // "[1]" setState(() {
final postRaw = await tokenService.readValue('empAllowed_modules'); // "[2,3,4]" isLoading = true; // 🔥 START LOADER HERE
});
// Decode safely try {
enrollmentModules = enrollmentRaw != null && enrollmentRaw.isNotEmpty final enrollmentRaw =
? List<int>.from(jsonDecode(enrollmentRaw)) await tokenService.readValue('enrollmentAllowed_modules');
: []; final postRaw =
await tokenService.readValue('empAllowed_modules');
postModules = postRaw != null && postRaw.isNotEmpty enrollmentModules = enrollmentRaw != null && enrollmentRaw.isNotEmpty
? List<int>.from(jsonDecode(postRaw)) ? List<int>.from(jsonDecode(enrollmentRaw))
: []; : [];
print('enrollmentModules $enrollmentModules'); postModules = postRaw != null && postRaw.isNotEmpty
print('postModules $postModules'); ? List<int>.from(jsonDecode(postRaw))
: [];
_postPreToken = await tokenService.getCurrentToken(); _postPreToken = await tokenService.getCurrentToken();
print(_postPreToken);
if (enrollmentModules.contains(1)) { List<Future> apiCalls = [];
enrollmentClient_id = await tokenService.readValue('enrollmentClient_id');
enrollmentEmpClientBranchId =
await tokenService.readValue('enrollmentEmpClientBranchId');
enrollmentHrId = await tokenService.readValue('enrollmentHrId');
await getPreCashDepositDetails(enrollmentEmpClientBranchId, /// 👇 Add APIs dynamically
enrollmentClient_id, enrollmentHrId, _postPreToken); if (enrollmentModules.contains(1)) {
enrollmentClient_id =
await tokenService.readValue('enrollmentClient_id');
enrollmentEmpClientBranchId =
await tokenService.readValue('enrollmentEmpClientBranchId');
enrollmentHrId =
await tokenService.readValue('enrollmentHrId');
apiCalls.add(
getPreCashDepositDetails(
enrollmentEmpClientBranchId,
enrollmentClient_id,
enrollmentHrId,
_postPreToken,
),
);
}
if (postModules.contains(2)) {
empClientId = await tokenService.readValue('empClientId');
empClientBranchId =
await tokenService.readValue('empClientBranchId');
empHrId = await tokenService.readValue('empHrId');
apiCalls.add(
getPostCashDepositDetails(
empClientBranchId,
empClientId,
empHrId,
_postPreToken,
),
);
}
/// 🔥 WAIT FOR ALL APIs
await Future.wait(apiCalls);
} catch (e) {
print("Error in _loadToken: $e");
} finally {
if (mounted) {
setState(() {
isLoading = false; // 🔥 STOP LOADER ONLY ONCE
});
}
} }
if (postModules.contains(2)) {
empClientId = await tokenService.readValue('empClientId');
empClientBranchId = await tokenService.readValue('empClientBranchId');
empHrId = await tokenService.readValue('empHrId');
await getPostCashDepositDetails(empClientBranchId, empClientId, empHrId, _postPreToken);
}
} }
Future<void> getPreCashDepositDetails(enrollmentEmpClientBranchId, Future<void> getPreCashDepositDetails(enrollmentEmpClientBranchId,
@ -153,7 +224,6 @@ class _policiesState extends State<policies>
print("hr_id -$enrollmentHrId"); print("hr_id -$enrollmentHrId");
print("token -$_postPreToken"); print("token -$_postPreToken");
isLoading = true;
// setState(() { // setState(() {
// _isLoading = true; // _isLoading = true;
// }); // });
@ -171,7 +241,6 @@ class _policiesState extends State<policies>
// clintID!, clintBranchId!, hr_id, token); // clintID!, clintBranchId!, hr_id, token);
print('IN1'); print('IN1');
if (response['status'] == 'success') { if (response['status'] == 'success') {
isLoading = false;
setState(() { setState(() {
print('response'); print('response');
print(response['data']); print(response['data']);
@ -198,7 +267,6 @@ class _policiesState extends State<policies>
print("hr_id -$empHrId"); print("hr_id -$empHrId");
print("token -$_postPreToken"); print("token -$_postPreToken");
isLoading = true;
// setState(() { // setState(() {
// _isLoading = true; // _isLoading = true;
// }); // });
@ -213,7 +281,6 @@ class _policiesState extends State<policies>
// clintID!, clintBranchId!, hr_id, token); // clintID!, clintBranchId!, hr_id, token);
print('IN1'); print('IN1');
if (response['status'] == 'success') { if (response['status'] == 'success') {
isLoading = false;
setState(() { setState(() {
print('response'); print('response');
print(response['data']); print(response['data']);
@ -226,7 +293,6 @@ class _policiesState extends State<policies>
print('IN2'); print('IN2');
} else { } else {
isLoading = false;
print('API request failed with status'); print('API request failed with status');
setState(() { setState(() {
activePoliciesList = []; activePoliciesList = [];
@ -345,7 +411,16 @@ class _policiesState extends State<policies>
required List<Map<String, dynamic>> openEnrollment, required List<Map<String, dynamic>> openEnrollment,
required List<Map<String, dynamic>> activePolicies, required List<Map<String, dynamic>> activePolicies,
}) { }) {
return Scaffold( return isLoading ? Container(
color: Colors.transparent, // Semi-transparent background
child: Center(
child: // Your GIF loader widget
Image.asset(
height: 60,
width: 60,
'assets/nhance-loader.gif'), // Adjust path to your GIF loader
),
) : Scaffold(
body: SingleChildScrollView( body: SingleChildScrollView(
// padding: const EdgeInsets.all(20), // padding: const EdgeInsets.all(20),
@ -385,39 +460,45 @@ class _policiesState extends State<policies>
SizedBox(height: 15), SizedBox(height: 15),
Container( Container(
width: double.infinity, width: double.infinity,
height: 400, // constraints: const BoxConstraints(
// minHeight: 180,
// ),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
child: Column( child: IntrinsicHeight(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( children: [
'Open for Enrollment', Text(
style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600), 'Open for Enrollment',
), style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600),
SizedBox(height: 14), ),
SizedBox(height: 14),
/// SCROLLABLE AREA
openEnrollment.isEmpty
? _EmptyBox('No policies open for enrollment')
: _PolicyGrid(
policies: openEnrollment,
isEnrollment: true,
),
],
),
)
/// SCROLLABLE AREA
Expanded(
child: openEnrollment.isEmpty
? _EmptyBox('No policies open for enrollment')
: _PolicyGrid(
policies: openEnrollment,
isEnrollment: true,
),
),
],
),
), ),
], ],
if(postModules.contains(2))...[ if(postModules.contains(2))...[
SizedBox(height: 20), SizedBox(height: 20),
Container( Container(
width: double.infinity, width: double.infinity,
height: 400, // constraints: const BoxConstraints(
// minHeight: 180,
// ),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -454,15 +535,14 @@ class _policiesState extends State<policies>
const SizedBox(height: 14), const SizedBox(height: 14),
/// SCROLLABLE GRID /// SCROLLABLE GRID
Expanded( activePolicies.isEmpty
child: activePolicies.isEmpty
? stausVal == 0 ? _EmptyBox('You dont have any expired policies at the moment.') : _EmptyBox('No active policies found') ? stausVal == 0 ? _EmptyBox('You dont have any expired policies at the moment.') : _EmptyBox('No active policies found')
: _PolicyGrid( : _PolicyGrid(
policies: activePolicies, policies: activePolicies,
isEnrollment: false, isEnrollment: false,
onBulkDownload: getEcardBulkDownload, onBulkDownload: getEcardBulkDownload,
), ),
),
const SizedBox(height: 8), const SizedBox(height: 8),
Align( Align(
@ -513,123 +593,158 @@ class _PolicyGrid extends StatelessWidget {
) { ) {
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
if (width < 600) { // if (width < 600) {
return ResponsiveGridConfig(1, isEnrollment ? 1.25 : 1.15); // return ResponsiveGridConfig(1, isEnrollment ? 1.25 : 1.15);
} else if (width < 900) { // } else if (width < 900) {
return ResponsiveGridConfig(2, isEnrollment ? 1.6 : 1.45); // return ResponsiveGridConfig(2, isEnrollment ? 1.6 : 1.45);
} else if (width < 1400) { // } else if (width < 1400) {
return ResponsiveGridConfig(3, isEnrollment ? 3.1 : 2.5); // return ResponsiveGridConfig(3, isEnrollment ? 3.1 : 2.5);
// } else {
// return ResponsiveGridConfig(4, isEnrollment ? 3.1 : 2.4);
// }
if (width >= 1400) {
return const ResponsiveGridConfig(4, 2.6); // Big screen
} else if (width >= 1000) {
return const ResponsiveGridConfig(3, 2.3); // Small desktop
} else if (width >= 600) {
return const ResponsiveGridConfig(2, 2.0); // Tablet
} else { } else {
return ResponsiveGridConfig(4, isEnrollment ? 3.1 : 2.4); return const ResponsiveGridConfig(1, 1.8); // Mobile
} }
} }
@override
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final tokenService = TokenStorageService(); final tokenService = TokenStorageService();
final config = _getGridConfig(context, isEnrollment); final config = _getGridConfig(context, isEnrollment);
return GridView.builder( final int rowCount = (policies.length / config.crossAxisCount).ceil();
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.zero, double cardHeight;
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: config.crossAxisCount, if (isEnrollment) {
childAspectRatio: config.childAspectRatio, cardHeight = 140;
crossAxisSpacing: 16, } else {
mainAxisSpacing: 16, cardHeight = 170;
}
final double totalHeight =
rowCount * cardHeight + ((rowCount - 1) * 16);
return SizedBox(
height: totalHeight,
child: GridView.builder(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: config.crossAxisCount,
childAspectRatio: config.childAspectRatio,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
mainAxisExtent: isEnrollment ? 120 : 150, // fixed card height
),
itemCount: policies.length,
itemBuilder: (context, index) {
final data = policies[index];
return isEnrollment
? _EnrollmentPolicyCardNew(
data: data,
onTap: () async {
final token = await tokenService.getCurrentToken();
final clientId =
await tokenService.readValue('enrollmentClient_id');
final branchId = await tokenService
.readValue('enrollmentEmpClientBranchId');
if (token == null || clientId == null || branchId == null) {
return;
}
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: 'hrPolicyDetails'),
builder: (_) => hrPolicyDetails(
ClientId: clientId,
policyTypeId:
data['policy_type_id'].toString(),
ClientPoliyId:
data['client_policy_id'].toString(),
clientBranchId: branchId,
Token: token,
TokenType: "pre",
cardType: data['type'].toString(),
cardPolicyNo: data['policy_no'].toString(),
cardInsurer_name:
data['insurer_short_name'].toString(),
cardPolicy_name:
data['policy_name'].toString(),
cardPolicy_ExpDate:
data['policy_expiry_date'].toString(),
total_premium: '',
is_ecard_bulk_download_for_employee: 0,
),
),
);
},
)
: _ActivePolicyCardNew(
data: data,
onBulkDownload: onBulkDownload,
onTap: () async {
final token = await tokenService.getCurrentToken();
final clientId = await tokenService.readValue('empClientId');
final branchId = await tokenService.readValue('empClientBranchId');
print("token: $token");
print("clientId: $clientId");
print("branchId: $branchId");
if (token == null || clientId == null || branchId == null) {
print("Missing required values");
return;
}
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: 'hrPolicyDetails'),
builder: (_) => hrPolicyDetails(
ClientId: clientId,
policyTypeId:
data['policy_type_id'].toString(),
ClientPoliyId:
data['client_policy_id'].toString(),
clientBranchId: branchId,
Token: token,
TokenType: 'post',
cardType: data['type'].toString(),
cardPolicyNo: data['policy_no'].toString(),
cardInsurer_name:
data['insurer_short_name'].toString(),
cardPolicy_name:
data['policy_name'].toString(),
cardPolicy_ExpDate:
data['policy_expiry_date'].toString(),
total_premium:
data['total_premium'].toString(),
is_ecard_bulk_download_for_employee:
data['is_ecard_bulk_download_for_employee'],
),
),
);
},
);
},
), ),
itemCount: policies.length,
itemBuilder: (context, index) {
final data = policies[index];
return isEnrollment
? _EnrollmentPolicyCardNew(
data: data,
onTap: () async {
final token = await tokenService.getCurrentToken();
final clientId =
await tokenService.readValue('enrollmentClient_id');
final branchId = await tokenService
.readValue('enrollmentEmpClientBranchId');
if (token == null || clientId == null || branchId == null) {
return;
}
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: 'hrPolicyDetails'),
builder: (_) => hrPolicyDetails(
ClientId: clientId,
policyTypeId:
data['policy_type_id'].toString(),
ClientPoliyId:
data['client_policy_id'].toString(),
clientBranchId: branchId,
Token: token,
TokenType: "pre",
cardType: data['type'].toString(),
cardPolicyNo: data['policy_no'].toString(),
cardInsurer_name:
data['insurer_short_name'].toString(),
cardPolicy_name:
data['policy_name'].toString(),
cardPolicy_ExpDate:
data['policy_expiry_date'].toString(),
total_premium: '',
is_ecard_bulk_download_for_employee: 0,
),
),
);
},
)
: _ActivePolicyCardNew(
data: data,
onBulkDownload: onBulkDownload,
onTap: () async {
final token = await tokenService.getCurrentToken();
final clientId =
await tokenService.readValue('empClientId');
final branchId =
await tokenService.readValue('empClientBranchId');
if (token == null || clientId == null || branchId == null) {
return;
}
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: 'hrPolicyDetails'),
builder: (_) => hrPolicyDetails(
ClientId: clientId,
policyTypeId:
data['policy_type_id'].toString(),
ClientPoliyId:
data['client_policy_id'].toString(),
clientBranchId: branchId,
Token: token,
TokenType: 'post',
cardType: data['type'].toString(),
cardPolicyNo: data['policy_no'].toString(),
cardInsurer_name:
data['insurer_short_name'].toString(),
cardPolicy_name:
data['policy_name'].toString(),
cardPolicy_ExpDate:
data['policy_expiry_date'].toString(),
total_premium:
data['total_premium'].toString(),
is_ecard_bulk_download_for_employee:
data['is_ecard_bulk_download_for_employee'],
),
),
);
},
);
},
); );
} }
} }

View File

@ -51,8 +51,7 @@ class postFileUpload extends StatefulWidget {
required this.cardInsurer_name, required this.cardInsurer_name,
required this.cardPolicy_name, required this.cardPolicy_name,
required this.cardPolicy_ExpDate, required this.cardPolicy_ExpDate,
required this.total_premium required this.total_premium})
})
: super(key: key); : super(key: key);
@override @override
@ -61,6 +60,23 @@ class postFileUpload extends StatefulWidget {
class _postFileUploadState extends State<postFileUpload> { class _postFileUploadState extends State<postFileUpload> {
final tokenService = TokenStorageService(); final tokenService = TokenStorageService();
String localClientId = '';
String localPolicyTypeId = '';
String localClientPolicyId = '';
String localClientBranchId = '';
String localToken = '';
String localTokenType = '';
String localCardType = '';
String localCardPolicyNo = '';
String localCardInsurerName = '';
String localCardPolicyName = '';
String localCardPolicyExpDate = '';
String localTotalPremium = '';
Uint8List? fileBytes; Uint8List? fileBytes;
Uint8List? fileBytes2; Uint8List? fileBytes2;
late String _token; late String _token;
@ -101,9 +117,8 @@ class _postFileUploadState extends State<postFileUpload> {
bool showSampleButton = false; bool showSampleButton = false;
String? currentApiValue; // To store the 'value' for the 2nd param String? currentApiValue; // To store the 'value' for the 2nd param
int _currentPage = 1; int _currentPage = 1;
int _rowsPerPage = 5; int _rowsPerPage = 6;
List<dynamic> get _paginatedData { List<dynamic> get _paginatedData {
final startIndex = (_currentPage - 1) * _rowsPerPage; final startIndex = (_currentPage - 1) * _rowsPerPage;
@ -125,9 +140,12 @@ class _postFileUploadState extends State<postFileUpload> {
void initState() { void initState() {
super.initState(); super.initState();
apiService = ApiService(context); apiService = ApiService(context);
_loadToken(); restoreUploadData().then((_) {
getFileUploadMasterDetails(); _loadToken();
getFileListDetails(); getFileUploadMasterDetails();
getFileListDetails();
});
} }
@override @override
@ -137,22 +155,85 @@ class _postFileUploadState extends State<postFileUpload> {
} }
Future<void> _loadToken() async { Future<void> _loadToken() async {
// final token = prefs.getString('hrtoken'); final token = localToken.isNotEmpty
final token = widget.Token; ? localToken
: await tokenService.readValue('upload_Token');
if (token != null && token.isNotEmpty) { if (token != null && token.isNotEmpty) {
setState(() { setState(() {
_token = token; _token = token;
}); });
Map<String, dynamic>? decodedToken = Jwt.parseJwt(token);
print('decodedToken $decodedToken');
} else { } else {
// Token is empty or null, handle accordingly (e.g., navigate to login screen)
// For now, let's navigate to the login screen
ToastHelper.showErrorToast(context, 'Session Out'); ToastHelper.showErrorToast(context, 'Session Out');
Navigator.pushReplacementNamed(context, 'hrLogin'); Navigator.pushReplacementNamed(context, 'hrLogin');
} }
} }
Future<void> restoreUploadData() async {
localClientId = widget.ClientId.isNotEmpty
? widget.ClientId
: await tokenService.readValue('upload_ClientId') ?? '';
localPolicyTypeId = widget.policyTypeId.isNotEmpty
? widget.policyTypeId
: await tokenService.readValue('upload_policyTypeId') ?? '';
localClientPolicyId = widget.ClientPoliyId.isNotEmpty
? widget.ClientPoliyId
: await tokenService.readValue('upload_ClientPoliyId') ?? '';
localClientBranchId = widget.clientBranchId.isNotEmpty
? widget.clientBranchId
: await tokenService.readValue('upload_clientBranchId') ?? '';
localToken = widget.Token.isNotEmpty
? widget.Token
: await tokenService.readValue('upload_Token') ?? '';
localTokenType = widget.TokenType.isNotEmpty
? widget.TokenType
: await tokenService.readValue('upload_TokenType') ?? '';
localCardType = widget.cardType.isNotEmpty
? widget.cardType
: await tokenService.readValue('upload_cardType') ?? '';
localCardPolicyNo = widget.cardPolicyNo.isNotEmpty
? widget.cardPolicyNo
: await tokenService.readValue('upload_cardPolicyNo') ?? '';
localCardInsurerName = widget.cardInsurer_name.isNotEmpty
? widget.cardInsurer_name
: await tokenService.readValue('upload_cardInsurer_name') ?? '';
localCardPolicyName = widget.cardPolicy_name.isNotEmpty
? widget.cardPolicy_name
: await tokenService.readValue('upload_cardPolicy_name') ?? '';
localCardPolicyExpDate = widget.cardPolicy_ExpDate.isNotEmpty
? widget.cardPolicy_ExpDate
: await tokenService.readValue('upload_cardPolicy_ExpDate') ?? '';
localTotalPremium = widget.total_premium.isNotEmpty
? widget.total_premium
: await tokenService.readValue('upload_total_premium') ?? '';
}
Future<void> clearUploadStorage() async {
await tokenService.removeValue('upload_ClientId');
await tokenService.removeValue('upload_policyTypeId');
await tokenService.removeValue('upload_ClientPoliyId');
await tokenService.removeValue('upload_clientBranchId');
await tokenService.removeValue('upload_Token');
await tokenService.removeValue('upload_TokenType');
await tokenService.removeValue('upload_cardType');
await tokenService.removeValue('upload_cardPolicyNo');
await tokenService.removeValue('upload_cardInsurer_name');
await tokenService.removeValue('upload_cardPolicy_name');
await tokenService.removeValue('upload_cardPolicy_ExpDate');
await tokenService.removeValue('upload_total_premium');
}
// Future<void> getPolicyDetails() async { // Future<void> getPolicyDetails() async {
// setState(() { // setState(() {
// clientPolicyId = argumentsData['client_policy_id']; // clientPolicyId = argumentsData['client_policy_id'];
@ -184,7 +265,7 @@ class _postFileUploadState extends State<postFileUpload> {
Future<void> getFileUploadMasterDetails() async { Future<void> getFileUploadMasterDetails() async {
print('9'); print('9');
try { try {
final response = await apiService.getFileUploadMastersToApi(widget.Token); final response = await apiService.getFileUploadMastersToApi(localToken);
if (response['status'] == true) { if (response['status'] == true) {
print('getFileUploadMasterList1'); print('getFileUploadMasterList1');
@ -220,8 +301,8 @@ class _postFileUploadState extends State<postFileUpload> {
print('9'); print('9');
try { try {
final response = await apiService.getFileListToApi( final response = await apiService.getFileListToApi(empPrimaryId,
empPrimaryId, widget.cardPolicyNo, empClientId,widget.Token,widget.TokenType); localCardPolicyNo, empClientId, localToken, localTokenType);
if (response['status'] == 'success') { if (response['status'] == 'success') {
print('getThrFileList'); print('getThrFileList');
@ -248,18 +329,20 @@ class _postFileUploadState extends State<postFileUpload> {
} }
Future<void> getHrFileDownload(id, file_name) async { Future<void> getHrFileDownload(id, file_name) async {
// final http.Response response = await apiService.getHrFileDownloadToApi(id, widget.Token); // final http.Response response = await apiService.getHrFileDownloadToApi(id, localToken);
print("**********-------*****"); print("**********-------*****");
final encryptClientId = widget.ClientId; final encryptClientId = localClientId;
print(encryptClientId); print(encryptClientId);
final apiurl = Environment.apiUrlPost; final apiurl = Environment.apiUrlPost;
final String url = '$apiurl/hrFileDownload?id=$id&cliend_id=$encryptClientId'; final String url =
final token = widget.Token; '$apiurl/hrFileDownload?id=$id&cliend_id=$encryptClientId';
final token = localToken;
final response = await http.get( final response = await http.get(
Uri.parse(url), Uri.parse(url),
headers: { headers: {
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y', 'APP-SIGNATURE':
'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456', // 'app-signature': 'ts-traveltool-2025-signature-123456',
@ -297,16 +380,17 @@ class _postFileUploadState extends State<postFileUpload> {
Future<void> downloadPostSampleFile(String apiParam) async { Future<void> downloadPostSampleFile(String apiParam) async {
print("fun Sam f - in"); print("fun Sam f - in");
final post_file_name = apiParam+'_sample_file.xlsx'; final post_file_name = apiParam + '_sample_file.xlsx';
print("fun Sam f - name $post_file_name" ); print("fun Sam f - name $post_file_name");
final apiurl = Environment.apiUrlPost; final apiurl = Environment.apiUrlPost;
final String url = '$apiurl/downloadSampleExcel/$apiParam'; final String url = '$apiurl/downloadSampleExcel/$apiParam';
final token = widget.Token; final token = localToken;
final response = await http.get( final response = await http.get(
Uri.parse(url), Uri.parse(url),
headers: { headers: {
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y', 'APP-SIGNATURE':
'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456', // 'app-signature': 'ts-traveltool-2025-signature-123456',
@ -315,7 +399,7 @@ class _postFileUploadState extends State<postFileUpload> {
if (response.statusCode == 200) { if (response.statusCode == 200) {
try { try {
print("fun sam f - ${response.statusCode}" ); print("fun sam f - ${response.statusCode}");
// Create a blob from the response body bytes // Create a blob from the response body bytes
final blob = html.Blob([response.bodyBytes]); final blob = html.Blob([response.bodyBytes]);
@ -333,7 +417,7 @@ class _postFileUploadState extends State<postFileUpload> {
ToastHelper.showSuccessToast(context, 'File Downloaded Successfully'); ToastHelper.showSuccessToast(context, 'File Downloaded Successfully');
} catch (e) { } catch (e) {
print("fun sam f - fail" ); print("fun sam f - fail");
throw Exception('Error parsing response: $e'); throw Exception('Error parsing response: $e');
} }
} else { } else {
@ -475,7 +559,8 @@ class _postFileUploadState extends State<postFileUpload> {
print('else'); print('else');
// Attach the file to the request // Attach the file to the request
// Set authorization token in headers // Set authorization token in headers
request.headers['APP-SIGNATURE'] = 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y'; request.headers['APP-SIGNATURE'] =
'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y';
request.headers['Authorization'] = 'Bearer $_token'; request.headers['Authorization'] = 'Bearer $_token';
// request.files.add(http.MultipartFile.fromBytes('file', fileBytes, // request.files.add(http.MultipartFile.fromBytes('file', fileBytes,
// filename: fileName)); // filename: fileName));
@ -492,13 +577,13 @@ class _postFileUploadState extends State<postFileUpload> {
)); ));
print('clintID: $clintID'); print('clintID: $clintID');
request.fields['client_id'] = widget.ClientId; request.fields['client_id'] = localClientId;
request.fields['policy_no'] = widget.cardPolicyNo; request.fields['policy_no'] = localCardPolicyNo;
request.fields['client_branch_id'] = widget.clientBranchId; request.fields['client_branch_id'] = localClientBranchId;
request.fields['file_action'] = selectedKey!; request.fields['file_action'] = selectedKey!;
// request.fields['status'] = selectedKey!; // request.fields['status'] = selectedKey!;
request.fields['created_by'] = empPrimaryId; request.fields['created_by'] = empPrimaryId;
request.fields['policy_id'] = widget.ClientPoliyId; request.fields['policy_id'] = localClientBranchId;
// "client_id": 1, // "client_id": 1,
// "client_branch_id": 2, // "client_branch_id": 2,
// "policy_no": "POL123456", // "policy_no": "POL123456",
@ -520,15 +605,15 @@ class _postFileUploadState extends State<postFileUpload> {
isLoading = false; isLoading = false;
}); });
ToastHelper.showSuccessToast(context, data['message']); ToastHelper.showSuccessToast(context, data['message']);
getFileListDetails();
setState(() { setState(() {
selectedValue = null; selectedValue = null;
selectedKey = null; selectedKey = null;
resetErrorCount(); resetErrorCount();
getFileListDetails();
}); });
} else { } else {
getFileListDetails();
setState(() { setState(() {
getFileListDetails();
isLoading = false; isLoading = false;
selectedValue = null; selectedValue = null;
selectedKey = null; selectedKey = null;
@ -587,217 +672,267 @@ class _postFileUploadState extends State<postFileUpload> {
} }
Widget _buildContent(BuildContext context) { Widget _buildContent(BuildContext context) {
return isLoading ? Container( return isLoading
color: Colors.transparent, // Semi-transparent background ? Container(
child: Center( color: Colors.transparent, // Semi-transparent background
child: // Your GIF loader widget child: Center(
Image.asset( child: // Your GIF loader widget
height: 60, Image.asset(
width: 60, height: 60,
'assets/nhance-loader.gif'), // Adjust path to your GIF loader width: 60,
), 'assets/nhance-loader.gif'), // Adjust path to your GIF loader
): Container( ),
child: Column( )
children: [ : Container(
Row( child: Column(
children: [ children: [
IconButton( Row(
tooltip: 'Previous Page',
onPressed: () => {Navigator.pop(context)},
icon: const Icon(
Icons.arrow_back_ios,
size: 18,
color: Colors.black,
),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
const SizedBox(width: 6),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( IconButton(
"${widget.cardType} - ${widget.cardPolicyNo} " ?? tooltip: 'Previous Page',
'', onPressed: () async {
style: GoogleFonts.poppins( if (Navigator.canPop(context)) {
color: Colors.black, Navigator.pop(context);
fontSize: 14, return;
fontWeight: FontWeight.w500, }
),
),
Text(
widget.TokenType == 'pre'
? "${widget.cardPolicy_name} (${widget.cardPolicy_ExpDate})"
: "${widget.cardInsurer_name} - ${widget.cardPolicy_name} (${widget.cardPolicy_ExpDate})",
style: GoogleFonts.poppins(color: Colors.grey, fontSize: 12, fontWeight: FontWeight.w400),
),
],
),
),
// Visibility toggles based on dropdown selection
Visibility(
visible: showSampleButton,
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: SizedBox(
child: ElevatedButton(
onPressed: () {
// Pass the dynamic value to the function
downloadPostSampleFile(currentApiValue ?? '');
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFE26728),
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
child: Text(
'Sample Excel',
style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white),
),
),
),
),
),
],
),
SizedBox(height:20),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Select File Action
Expanded(
flex: 5,
child: buildStyledDropdown(
label: 'Select File Action',
value: selectedKey,
items: getFileUploadMasterList,
onChanged: (val) {
setState(() {
selectedKey = val;
final selectedItem = getFileUploadMasterList.firstWhere((e) => e['key'] == val);
selectedValue = selectedItem['value'];
currentApiValue = selectedItem['key'];
showSampleButton = true;
});
},
),
),
const SizedBox(width: 16), final clientId = await tokenService.readValue('hr_ClientId') ?? '';
final policyTypeId = await tokenService.readValue('hr_policyTypeId') ?? '';
final clientPolicyId = await tokenService.readValue('hr_ClientPoliyId') ?? '';
final clientBranchId = await tokenService.readValue('hr_clientBranchId') ?? '';
final token = await tokenService.readValue('hr_Token') ?? '';
final tokenType = await tokenService.readValue('hr_TokenType') ?? '';
final cardType = await tokenService.readValue('hr_cardType') ?? '';
final policyNo = await tokenService.readValue('hr_cardPolicyNo') ?? '';
final insurer = await tokenService.readValue('hr_cardInsurer_name') ?? '';
final policyName = await tokenService.readValue('hr_cardPolicy_name') ?? '';
final expDate = await tokenService.readValue('hr_cardPolicy_ExpDate') ?? '';
final totalPremium = await tokenService.readValue('hr_total_premium') ?? '';
final bulkDownload = await tokenService.readValue('hr_is_ecard_bulk_download_for_employee') ?? '0';
/// Upload Box Navigator.pushReplacement(
Expanded( context,
flex: 5, MaterialPageRoute(
child: Column( settings: const RouteSettings(name: 'hrPolicyDetails'),
crossAxisAlignment: CrossAxisAlignment.start, builder: (_) => hrPolicyDetails(
children: [ ClientId: clientId,
/// LABEL policyTypeId: policyTypeId,
RichText( ClientPoliyId: clientPolicyId,
text: TextSpan( clientBranchId: clientBranchId,
text: 'Upload File', Token: token,
style: GoogleFonts.poppins( TokenType: tokenType,
fontSize: 12, cardType: cardType,
fontWeight: FontWeight.w500, cardPolicyNo: policyNo,
color: Colors.black, cardInsurer_name: insurer,
), cardPolicy_name: policyName,
children: const [ cardPolicy_ExpDate: expDate,
TextSpan( total_premium: totalPremium,
text: '(Supported Formats: XLSX)', is_ecard_bulk_download_for_employee: int.tryParse(bulkDownload) ?? 0,
style: TextStyle(
fontSize: 11,
color: Colors.grey,
fontWeight: FontWeight.w400,
), ),
), ),
);
},
icon: const Icon(
Icons.arrow_back_ios,
size: 18,
color: Colors.black,
),
),
const SizedBox(width: 6),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"${localCardType} - ${localCardPolicyNo} " ??
'',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
Text(
localTokenType == 'pre'
? "${localCardPolicyName} (${localCardPolicyExpDate})"
: "${localCardInsurerName} - ${localCardPolicyName} (${localCardPolicyExpDate})",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 12,
fontWeight: FontWeight.w400),
),
], ],
), ),
), ),
// Visibility toggles based on dropdown selection
const SizedBox(height: 6), Visibility(
visible: showSampleButton,
/// DOTTED UPLOAD BOX child: Padding(
DragTarget<html.File>( padding: const EdgeInsets.only(left: 10),
onAccept: (html.File droppedFile) { child: SizedBox(
setState(() { child: ElevatedButton(
fileName = droppedFile.name; onPressed: () {
}); // Pass the dynamic value to the function
_dragAndDropFile(droppedFile); downloadPostSampleFile(currentApiValue ?? '');
},
builder: (context, candidateData, rejectedData) {
return GestureDetector(
onTap: () {
if (selectedValue != null) {
_uploadFile();
} else {
ToastHelper.showErrorToast(
context,
'Please select file action',
);
}
}, },
child: Container( style: ElevatedButton.styleFrom(
height: 40 , backgroundColor: const Color(0xFFE26728),
padding: const EdgeInsets.symmetric(horizontal: 12), elevation: 0,
decoration: BoxDecoration( shape: RoundedRectangleBorder(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
borderRadius: BorderRadius.circular(8), ),
border: Border.all( child: Text(
color: const Color(0xFF00A6A6), 'Sample Excel',
width: 1, style: GoogleFonts.poppins(
), fontSize: 14,
), fontWeight: FontWeight.w700,
child: Row( color: Colors.white),
children: [ ),
Expanded( ),
child: Text( ),
fileName ?? 'Upload Your Documents', ),
overflow: TextOverflow.ellipsis,
style: GoogleFonts.poppins(
fontSize: 13,
color: fileName == null
? Colors.grey
: Colors.black,
),
),
),
const Icon(
Icons.file_upload_outlined,
size: 18,
color: Colors.black,
),
],
),
)
);
},
), ),
], ],
), ),
), SizedBox(height: 20),
], Expanded(
), child: SingleChildScrollView(
SizedBox(height: 20), child: Column(
Row( crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Row(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildFileUploadedGrid(), /// Select File Action
const SizedBox(height: 16), Expanded(
_buildPagination(context), flex: 5,
], child: buildStyledDropdown(
), label: 'Select File Action',
) value: selectedKey,
items: getFileUploadMasterList,
onChanged: (val) {
setState(() {
selectedKey = val;
final selectedItem = getFileUploadMasterList
.firstWhere((e) => e['key'] == val);
selectedValue = selectedItem['value'];
currentApiValue = selectedItem['key'];
showSampleButton = true;
});
},
),
),
], const SizedBox(width: 16),
),
],
),
);
/// Upload Box
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// LABEL
RichText(
text: TextSpan(
text: 'Upload File',
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.black,
),
children: const [
TextSpan(
text: '(Supported Formats: XLSX)',
style: TextStyle(
fontSize: 11,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
],
),
),
const SizedBox(height: 6),
/// DOTTED UPLOAD BOX
DragTarget<html.File>(
onAccept: (html.File droppedFile) {
setState(() {
fileName = droppedFile.name;
});
_dragAndDropFile(droppedFile);
},
builder:
(context, candidateData, rejectedData) {
return GestureDetector(
onTap: () {
if (selectedValue != null) {
_uploadFile();
} else {
ToastHelper.showErrorToast(
context,
'Please select file action',
);
}
},
child: Container(
height: 40,
padding: const EdgeInsets.symmetric(
horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(8),
border: Border.all(
color: const Color(0xFF00A6A6),
width: 1,
),
),
child: Row(
children: [
Expanded(
child: Text(
fileName ??
'Upload Your Documents',
overflow:
TextOverflow.ellipsis,
style: GoogleFonts.poppins(
fontSize: 13,
color: fileName == null
? Colors.grey
: Colors.black,
),
),
),
const Icon(
Icons.file_upload_outlined,
size: 18,
color: Colors.black,
),
],
),
));
},
),
],
),
),
],
),
SizedBox(height: 20),
Column(
children: [
_buildFileUploadedGrid(),
const SizedBox(height: 16),
_buildPagination(context),
],
),
])))
],
),
);
} }
Widget buildUploadBox({ Widget buildUploadBox({
@ -852,8 +987,6 @@ class _postFileUploadState extends State<postFileUpload> {
); );
} }
Widget buildStyledDropdown({ Widget buildStyledDropdown({
required String label, required String label,
required String? value, required String? value,
@ -906,7 +1039,6 @@ class _postFileUploadState extends State<postFileUpload> {
); );
} }
Widget _buildFileUploadedGrid() { Widget _buildFileUploadedGrid() {
if (filteredData.isEmpty) { if (filteredData.isEmpty) {
return const SizedBox( return const SizedBox(
@ -916,20 +1048,23 @@ class _postFileUploadState extends State<postFileUpload> {
} }
return GridView.builder( return GridView.builder(
shrinkWrap: true, shrinkWrap: true, // IMPORTANT
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(), // Disable inner scroll
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // 👈 2 cards per row crossAxisCount: 2,
crossAxisSpacing: 16, crossAxisSpacing: 16,
mainAxisSpacing: 16, mainAxisSpacing: 16,
childAspectRatio: 10, // 👈 card height childAspectRatio: 10,
), ),
itemCount: _paginatedData.length, itemCount: _paginatedData.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = _paginatedData[index]; final item = _paginatedData[index];
return _buildFileCard(item); return _buildFileCard(item);
}, },
); );
} }
Widget _buildFileCard(Map<String, dynamic> item) { Widget _buildFileCard(Map<String, dynamic> item) {
@ -1014,9 +1149,7 @@ class _postFileUploadState extends State<postFileUpload> {
children: [ children: [
/// 🔴 Error + Status /// 🔴 Error + Status
Row( Row(
children: [ children: [],
],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -1024,58 +1157,60 @@ class _postFileUploadState extends State<postFileUpload> {
Row( Row(
children: [ children: [
if (item['file_error_status'] == '1') if (item['file_error_status'] == '1')
InkWell( InkWell(
onTap: () async { onTap: () async {
print(item); print(item);
// return; // return;
final String? token = await tokenService.getCurrentToken(); final String? token =
final String? empClientId = await tokenService.readValue('empClientId'); await tokenService.getCurrentToken();
final String? empBranchId = await tokenService.readValue('empClientBranchId'); final String? empClientId =
await tokenService.readValue('empClientId');
final String? empBranchId =
await tokenService.readValue('empClientBranchId');
print(item); print(item);
print(empClientId); print(empClientId);
print(widget.policyTypeId); print(localPolicyTypeId);
print(empBranchId); print(empBranchId);
print(token); print(token);
print('post'); print('post');
print(widget.cardType); print(localCardType);
print(widget.cardPolicyNo); print(localCardPolicyNo);
print(widget.cardInsurer_name); print(localCardInsurerName);
print(widget.cardPolicy_name); print(localCardPolicyName);
print(widget.cardPolicy_ExpDate); print(localCardPolicyExpDate);
print(item['id']); print(item['id']);
// SAFETY CHECK // SAFETY CHECK
if (token == null || if (token == null ||
empClientId == null || empClientId == null ||
empBranchId == null) { empBranchId == null) {
debugPrint('❌ Missing required data for navigation ${token}'); debugPrint(
return; '❌ Missing required data for navigation ${token}');
} return;
}
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) => excelErrorScreen(
excelErrorScreen( ClientId: empClientId,
ClientId: empClientId, policy_no: item['policy_no'],
policy_no: item['policy_no'], action: item['file_action'],
action: item['file_action'], created_at: item['created_at'],
created_at: item['created_at'], clientBranchId: empBranchId,
clientBranchId: empBranchId, Token: token,
Token: token, TokenType: 'post',
TokenType: 'post', id: item['id']),
id: item['id'] ),
), );
), },
); child: Icon(
}, Icons.error,
child: Icon( size: 16,
Icons.error, color: Colors.red,
size: 16, ),
color: Colors.red,
), ),
),
SizedBox(width: 10), SizedBox(width: 10),
_buildStatusChip(item['status']), _buildStatusChip(item['status']),
SizedBox(width: 10), SizedBox(width: 10),
@ -1100,8 +1235,8 @@ class _postFileUploadState extends State<postFileUpload> {
), ),
], ],
), ),
/// Download
/// Download
], ],
), ),
], ],
@ -1109,7 +1244,6 @@ class _postFileUploadState extends State<postFileUpload> {
); );
} }
Widget _buildStatusChip(String status) { Widget _buildStatusChip(String status) {
final s = status.toLowerCase(); final s = status.toLowerCase();
@ -1142,7 +1276,6 @@ class _postFileUploadState extends State<postFileUpload> {
); );
} }
static final _dataBold = GoogleFonts.poppins( static final _dataBold = GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -1161,14 +1294,14 @@ class _postFileUploadState extends State<postFileUpload> {
); );
Widget _buildPagination(BuildContext context) { Widget _buildPagination(BuildContext context) {
final totalItems = filteredData.length; final totalItems = filteredData.length;
final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; final int startEntry =
totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1;
int endEntry = _currentPage * _rowsPerPage; int endEntry = _currentPage * _rowsPerPage;
if (endEntry > totalItems) endEntry = totalItems; if (endEntry > totalItems) endEntry = totalItems;
final totalPages = (filteredData.length / _rowsPerPage).ceil(); final totalPages = (filteredData.length / _rowsPerPage).ceil();
const visiblePageCount = 5; const visiblePageCount = 6;
List<int> getVisiblePages() { List<int> getVisiblePages() {
if (totalPages <= visiblePageCount) { if (totalPages <= visiblePageCount) {
@ -1177,7 +1310,8 @@ class _postFileUploadState extends State<postFileUpload> {
if (_currentPage <= 3) { if (_currentPage <= 3) {
return [1, 2, 3, 4, 5]; return [1, 2, 3, 4, 5];
} if (_currentPage >= totalPages - 2) { }
if (_currentPage >= totalPages - 2) {
return [ return [
totalPages - 4, totalPages - 4,
totalPages - 3, totalPages - 3,
@ -1186,14 +1320,13 @@ class _postFileUploadState extends State<postFileUpload> {
totalPages totalPages
]; ];
} }
return [ return [
_currentPage - 2, _currentPage - 2,
_currentPage - 1, _currentPage - 1,
_currentPage, _currentPage,
_currentPage + 1, _currentPage + 1,
_currentPage + 2, _currentPage + 2,
]; ];
} }
List<int> visiblePages = getVisiblePages(); List<int> visiblePages = getVisiblePages();
@ -1208,7 +1341,7 @@ class _postFileUploadState extends State<postFileUpload> {
// Dropdown for rows per page // Dropdown for rows per page
DropdownButton<int>( DropdownButton<int>(
value: _rowsPerPage, value: _rowsPerPage,
items: [5, 10, 15, 20, 50].map((int value) { items: [6, 10, 15, 20, 50].map((int value) {
return DropdownMenuItem<int>( return DropdownMenuItem<int>(
value: value, value: value,
child: Text(' $value ', child: Text(' $value ',

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@ class ApiService {
String? _token; String? _token;
String? _hrtoken; String? _hrtoken;
bool _isSessionOutToastShown = false; // Flag to track toast message bool _isSessionOutToastShown = false; // Flag to track toast message
bool isTpaDashboardEnabled = false;
bool isTpaSelected = false; // track which dashboard is active
ApiService(this.context) { ApiService(this.context) {
_initializeToken(); _initializeToken();
@ -676,9 +678,32 @@ class ApiService {
} }
} }
Future<Map<String, dynamic>> getClaimPoliciesToApi(String token) async { Future<Map<String, dynamic>> postHrTpaDashboard(params, token) async {
final url = Uri.parse('${Environment.apiUrlPost}getHrTpaDashboard');
final headers = {
'Authorization': 'Bearer ${token ?? ''}',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
};
final response = await http.post(
url,
headers: headers,
body: jsonEncode(params),
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception(
'Failed to load HR TPA dashboard: ${response.statusCode}');
}
}
Future<Map<String, dynamic>> getClaimPoliciesToApi(String token,empClientId) async {
print("getgetClaimPoliciesToApii1"); print("getgetClaimPoliciesToApii1");
final url = Uri.parse('${Environment.apiUrlPost}claimsSearch'); final url = Uri.parse('${Environment.apiUrlPost}claimsSearch?client_id=$empClientId');
final headers = { final headers = {
'Authorization': 'Bearer $token' ?? '', 'Authorization': 'Bearer $token' ?? '',
@ -993,6 +1018,10 @@ class ApiService {
} }
Future<Map<String, dynamic>> _handleResponse(http.Response response) async { Future<Map<String, dynamic>> _handleResponse(http.Response response) async {
// 'throttle' => 429,
// 'soft' => 429,
// 'medium' => 403,
// 'hard' => 451,
if (response.statusCode == 200) { if (response.statusCode == 200) {
return jsonDecode(response.body); return jsonDecode(response.body);
} else if (response.statusCode == 401) { } else if (response.statusCode == 401) {
@ -1001,6 +1030,17 @@ class ApiService {
await _clearLocalStorageAndRedirect(); await _clearLocalStorageAndRedirect();
} }
return {}; return {};
} else if (response.statusCode == 403) {
if (!_isSessionOutToastShown) {
_isSessionOutToastShown = true;
await _clearLocalStorageAndRedirect();
}
return {};
}else if (response.statusCode == 451) {
final body = jsonDecode(response.body);
final message = body['message'];
ToastHelper.showWarningToast(context, message);
return {};
} else if (response.statusCode == 429) { } else if (response.statusCode == 429) {
final body = jsonDecode(response.body); final body = jsonDecode(response.body);
final message = body['message']; final message = body['message'];

View File

@ -11,6 +11,7 @@ class MultiFileUploadWidget extends StatefulWidget {
State<MultiFileUploadWidget> createState() => _MultiFileUploadWidgetState(); State<MultiFileUploadWidget> createState() => _MultiFileUploadWidgetState();
static bool hasFiles = false; static bool hasFiles = false;
static bool showValidation = false;
} }
class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> { class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
@ -44,6 +45,7 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
setState(() { setState(() {
errorMessage = null; errorMessage = null;
MultiFileUploadWidget.hasFiles = fileService.files.isNotEmpty; MultiFileUploadWidget.hasFiles = fileService.files.isNotEmpty;
MultiFileUploadWidget.showValidation = false;
}); });
} }
} }
@ -52,6 +54,9 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
fileService.removeFileAt(index); fileService.removeFileAt(index);
setState(() { setState(() {
MultiFileUploadWidget.hasFiles = fileService.files.isNotEmpty; MultiFileUploadWidget.hasFiles = fileService.files.isNotEmpty;
if (fileService.files.isEmpty) {
MultiFileUploadWidget.showValidation = true;
}
}); });
} }
@ -173,7 +178,9 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
// ), // ),
], ],
if (fileService.files.isEmpty && errorMessage == null) ...[ if (MultiFileUploadWidget.showValidation &&
fileService.files.isEmpty &&
errorMessage == null) ...[
const SizedBox(height: 4), const SizedBox(height: 4),
const Text( const Text(
"Required", "Required",

View File

@ -241,6 +241,9 @@ class TokenStorageService {
await _secureStorage.write(key: key, value: value); await _secureStorage.write(key: key, value: value);
} }
Future<void> removeValue(String key) async {
await _secureStorage.delete(key: key);
}
Future<void> clearBranchSession() async { Future<void> clearBranchSession() async {
final keysToRemove = [ final keysToRemove = [

View File

@ -33,6 +33,26 @@
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<style> <style>
/* Hide card three-dot menu */
[data-testid="dashcard-action-panel"] {
display: none !important;
}
/* Fallback selector */
.DashCard-actions {
display: none !important;
}
/* Hide powered by footer */
.MetabasePoweredBy {
display: none !important;
}
/* Fallback */
a[href*="metabase.com"] {
display: none !important;
}
.content { .content {
width: 10%; width: 10%;
height: 10vh; height: 10vh;