From 87ed64734410afee45a2184bde4d6d5fd8cc7bf2 Mon Sep 17 00:00:00 2001 From: "sanjeev.p" Date: Tue, 17 Feb 2026 15:20:33 +0530 Subject: [PATCH] FIX_minor issues --- lib/presentation/RaiseClaimForm.dart | 1 + lib/presentation/cdTransactionDetails.dart | 138 +++++++++++++- lib/presentation/claims.dart | 164 +++++++++------- lib/presentation/claimshistory.dart | 11 +- lib/presentation/hrPolicyDetails.dart | 206 +++++++++++---------- lib/presentation/postFileUpload.dart | 104 +++++++++-- lib/presentation/preFileUpload.dart | 76 +++++--- lib/service/hrDashboardTabs/cd.dart | 59 ++++-- lib/service/multi_file_upload_widget.dart | 1 + 9 files changed, 546 insertions(+), 214 deletions(-) diff --git a/lib/presentation/RaiseClaimForm.dart b/lib/presentation/RaiseClaimForm.dart index 6451d02..1ac19e9 100644 --- a/lib/presentation/RaiseClaimForm.dart +++ b/lib/presentation/RaiseClaimForm.dart @@ -749,6 +749,7 @@ class _RaiseClaimDialogState extends State { ), IconButton( icon: const Icon(Icons.close), + tooltip: 'Close', onPressed: () => Navigator.pop(context), ), ], diff --git a/lib/presentation/cdTransactionDetails.dart b/lib/presentation/cdTransactionDetails.dart index 72ffb39..61fe4fe 100755 --- a/lib/presentation/cdTransactionDetails.dart +++ b/lib/presentation/cdTransactionDetails.dart @@ -790,12 +790,14 @@ class _cdTransactionDetailsState extends State { 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']), ), ], @@ -819,6 +821,126 @@ class _cdTransactionDetailsState extends State { } Widget _buildPagination(BuildContext context) { + final totalItems = filteredData.length; + + // Calculate entries range + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + + // Calculate total pages + final int totalPages = (totalItems / _rowsPerPage).ceil(); + const int visiblePageCount = 5; + + // Helper logic for page numbers + List getVisiblePages() { + if (totalPages <= visiblePageCount) { + return List.generate(totalPages, (i) => i + 1); + } + if (_currentPage <= 3) { + return [1, 2, 3, 4, 5]; + } + if (_currentPage >= totalPages - 2) { + return [ + totalPages - 4, + totalPages - 3, + totalPages - 2, + totalPages - 1, + totalPages + ]; + } + return [ + _currentPage - 2, + _currentPage - 1, + _currentPage, + _currentPage + 1, + _currentPage + 2, + ]; + } + + List visiblePages = getVisiblePages(); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Standard Table Footer Layout + children: [ + /// --- LEFT SIDE: ENTRY DETAILS --- + Text( + 'Showing $startEntry to $endEntry of $totalItems entries', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w500, + color: const Color(0xFF666666), + ), + ), + + /// --- RIGHT SIDE: CONTROLS --- + Row( + children: [ + + DropdownButton( + value: _rowsPerPage, + items: [5, 10, 15, 20, 50].map((int value) { + return DropdownMenuItem( + value: value, + child: Text(' $value ', + style: GoogleFonts.poppins(fontSize: 15)), + ); + }).toList(), + onChanged: (newValue) { + setState(() { + _rowsPerPage = newValue!; + _currentPage = 1; + }); + }, + ), + + const SizedBox(width: 16), + + IconButton( + onPressed: _currentPage > 1 + ? () => setState(() => _currentPage--) + : null, + icon: const Icon(Icons.chevron_left), + ), + + if (!visiblePages.contains(1)) + Row(children: [ + _buildPageButton(1), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 4), + child: Text("..."), + ), + ]), + + // Visible page buttons + for (int page in visiblePages) _buildPageButton(page), + + if (!visiblePages.contains(totalPages) && totalPages > 0) + Row(children: [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 4), + child: Text("..."), + ), + _buildPageButton(totalPages), + ]), + + // Next button + IconButton( + onPressed: _currentPage < totalPages + ? () => setState(() => _currentPage++) + : null, + icon: const Icon(Icons.chevron_right), + ), + ], + ), + ], + ), + ); + } + + Widget _buildPagination_backup(BuildContext context) { final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -1033,16 +1155,19 @@ class _ActionIconButton extends StatelessWidget { final IconData icon; final VoidCallback onTap; final bool enabled; + final String? toolTip; // 1. Define the optional tooltip string const _ActionIconButton({ required this.icon, required this.onTap, + this.toolTip, // 2. Added to constructor this.enabled = true, }); @override Widget build(BuildContext context) { - return SizedBox( + // 3. Define the main button widget + Widget button = SizedBox( width: 36, height: 36, child: Material( @@ -1061,6 +1186,17 @@ class _ActionIconButton extends StatelessWidget { ), ), ); + + // 4. Wrap with Tooltip only if enabled and tooltip text exists + if (enabled && toolTip != null) { + return Tooltip( + message: toolTip!, + preferBelow: false, // Shows tooltip above the button + child: button, + ); + } + + return button; } } diff --git a/lib/presentation/claims.dart b/lib/presentation/claims.dart index 10a7373..f8aa84b 100755 --- a/lib/presentation/claims.dart +++ b/lib/presentation/claims.dart @@ -810,51 +810,60 @@ class _ClaimsPolicieState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - GestureDetector( - onTap: () { - // print('id ${item['id']}'); - // print('emp_name ${item['emp_name']}'); - // print('emp_code ${item['emp_code']}'); - // print('policy_type ${item['policy_type']}'); - // print('client_policy_no ${item['client_policy_no']}'); - // print('claim_amount ${item['claim_amount']}'); - // print('claim_no ${item['claim_no']}'); - // print(widget.postToken); - // return; - showDialog( - context: context, - barrierDismissible: true, - builder: (BuildContext context) { - return Dialog( - backgroundColor: Colors.transparent, - insetPadding: EdgeInsets.all(16), - child: ClaimHistoryPopup( - ticket_id: item['id'] ?? '', - empName: item['emp_name'] ?? '', // example - empCode: item['emp_code'] ?? '', // example - policyType: item['policy_type'] ?? '', - clientPolicyNo: item['client_policy_no'] ?? '', - claimAmount: item['claim_amount']?.toString() ?? '', - claimNo: item['claim_no'] ?? '', - postToken: _postPreToken ?? '', - ), + // 1. Tooltip for the hover message + Tooltip( + message: 'View Claim History', + child: + // 2. MouseRegion for the hand pointer + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + // print('id ${item['id']}'); + // print('emp_name ${item['emp_name']}'); + // print('emp_code ${item['emp_code']}'); + // print('policy_type ${item['policy_type']}'); + // print('client_policy_no ${item['client_policy_no']}'); + // print('claim_amount ${item['claim_amount']}'); + // print('claim_no ${item['claim_no']}'); + // print(widget.postToken); + // return; + showDialog( + context: context, + barrierDismissible: true, + builder: (BuildContext context) { + return Dialog( + backgroundColor: Colors.transparent, + insetPadding: EdgeInsets.all(16), + child: ClaimHistoryPopup( + ticket_id: item['id'] ?? '', + empName: item['emp_name'] ?? '', // example + empCode: item['emp_code'] ?? '', // example + policyType: item['policy_type'] ?? '', + clientPolicyNo: item['client_policy_no'] ?? '', + claimAmount: item['claim_amount']?.toString() ?? '', + claimNo: item['claim_no'] ?? '', + postToken: _postPreToken ?? '', + ), + ); + }, ); }, - ); - }, - child: Container( - height: 35, - width: 35, - decoration: BoxDecoration( - color: Color(0xFF86D1D4), - borderRadius: BorderRadius.circular(8), - ), - child: Padding( - padding: EdgeInsets.all(10), // You can adjust this value - child: Image.asset( - 'assets/claimHistory.png', - fit: BoxFit.contain, - width: 5, + child: Container( + height: 35, + width: 35, + decoration: BoxDecoration( + color: Color(0xFF86D1D4), + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: EdgeInsets.all(10), // You can adjust this value + child: Image.asset( + 'assets/claimHistory.png', + fit: BoxFit.contain, + width: 5, + ), + ), ), ), ), @@ -937,6 +946,12 @@ class _ClaimsPolicieState extends State { ); Widget _buildPagination(BuildContext context) { + // 1. Calculate the range of entries being shown + final totalItems = filteredData.length; + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -947,7 +962,8 @@ class _ClaimsPolicieState extends State { if (_currentPage <= 3) { return [1, 2, 3, 4, 5]; - } else if (_currentPage >= totalPages - 2) { + } + if (_currentPage >= totalPages - 2) { return [ totalPages - 4, totalPages - 3, @@ -955,29 +971,42 @@ class _ClaimsPolicieState extends State { totalPages - 1, totalPages ]; - } else { - return [ - _currentPage - 2, - _currentPage - 1, - _currentPage, - _currentPage + 1, - _currentPage + 2, - ]; } + return [ + _currentPage - 2, + _currentPage - 1, + _currentPage, + _currentPage + 1, + _currentPage + 2, + ]; + } List visiblePages = getVisiblePages(); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( + return Padding( + // Match this horizontal padding (16) to your Table Header padding for perfect alignment + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Pushes text to left, buttons to right + children: [ + // --- LEFT SIDE: Showing Text --- + Text( + "Showing $startEntry to $endEntry of $totalItems entries", + style: GoogleFonts.poppins( + fontSize: 13, + color: const Color(0xFF585757), + fontWeight: FontWeight.w400, + ), + ), + + // --- RIGHT SIDE: Controls --- + Row( children: [ // Dropdown for rows per page DropdownButton( value: _rowsPerPage, + // focusColor: Colors.transparent, // Fix: Removes the grey/blue highlight on change items: [5, 10, 15, 20, 50].map((int value) { return DropdownMenuItem( value: value, @@ -1015,7 +1044,7 @@ class _ClaimsPolicieState extends State { for (int page in visiblePages) _buildPageButton(page), // Right ellipsis + last page - if (!visiblePages.contains(totalPages)) + if (!visiblePages.contains(totalPages) && totalPages > 0) Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 4), @@ -1033,8 +1062,8 @@ class _ClaimsPolicieState extends State { ), ], ), - ), - ], + ], + ), ); } @@ -1641,11 +1670,13 @@ class _ClaimsPolicieState extends State { _IconActionButton( icon: Icons.filter_alt_outlined, onTap: applyFilter, + tooltip:"Filter" ), const SizedBox(width: 12), _IconActionButton( icon: Icons.refresh_outlined, onTap: reset, + tooltip:"Reset" ), ], ), @@ -1703,21 +1734,24 @@ class _ClaimsHeaderDelegate extends SliverPersistentHeaderDelegate { bool shouldRebuild(_) => false; } - - // ================= ICON BUTTON ================= class _IconActionButton extends StatelessWidget { final IconData icon; final VoidCallback onTap; + final String tooltip; const _IconActionButton({ required this.icon, required this.onTap, + required this.tooltip, }); @override Widget build(BuildContext context) { - return SizedBox( + return Tooltip( + message: tooltip, + preferBelow: false, // Optional: Shows tooltip above the button + child: SizedBox( width: 40, height: 40, child: Material( @@ -1729,6 +1763,6 @@ class _IconActionButton extends StatelessWidget { child: Icon(icon, color: Colors.white, size: 20), ), ), - ); + ),); } } diff --git a/lib/presentation/claimshistory.dart b/lib/presentation/claimshistory.dart index 6038e09..cad4feb 100755 --- a/lib/presentation/claimshistory.dart +++ b/lib/presentation/claimshistory.dart @@ -796,7 +796,9 @@ class _ClaimHistoryPopupState extends State const SizedBox(width: 8), /// DOWNLOAD ICON - InkWell( + Tooltip( + message: 'Download', // Added tooltip name + child: InkWell( borderRadius: BorderRadius.circular(6), onTap: () => _launchURL(file['url']), child: Container( @@ -812,6 +814,7 @@ class _ClaimHistoryPopupState extends State ), ), ), + ), ], ), ), @@ -866,6 +869,7 @@ class _ClaimHistoryPopupState extends State ), IconButton( icon: Icon(Icons.close), + tooltip: 'Remove', // Built-in property onPressed: () { _resetIRDocs(); setState(() => showIRDocs = false); @@ -972,6 +976,7 @@ class _ClaimHistoryPopupState extends State ), trailing: IconButton( icon: Icon(Icons.cancel, color: Colors.red), + tooltip: 'Remove', // Built-in property onPressed: () => removeAssignedFile(title), ), ), @@ -1070,6 +1075,7 @@ class _ClaimHistoryPopupState extends State fontSize: 18, fontWeight: FontWeight.w600))), IconButton( icon: Icon(Icons.close), + tooltip: 'Close', // Built-in property onPressed: () { _resetIRDocs(); setState(() => showIRDocs = false); @@ -1139,6 +1145,7 @@ class _ClaimHistoryPopupState extends State maxLines: 1, overflow: TextOverflow.ellipsis), trailing: IconButton( icon: Icon(Icons.cancel, color: Colors.red), + tooltip: 'Remove', // Built-in property onPressed: () => removeAssignedFile(title)), ), ); @@ -1234,6 +1241,7 @@ class _ClaimHistoryPopupState extends State fontSize: 16, fontWeight: FontWeight.w600))), IconButton( icon: Icon(Icons.close), + tooltip: 'Close', // Built-in property onPressed: () { _resetIRDocs(); setState(() => showIRDocs = false); @@ -1304,6 +1312,7 @@ class _ClaimHistoryPopupState extends State maxLines: 1, overflow: TextOverflow.ellipsis), trailing: IconButton( icon: Icon(Icons.cancel, color: Colors.red), + tooltip: 'Remove', // Built-in property onPressed: () => removeAssignedFile(title)), ), ); diff --git a/lib/presentation/hrPolicyDetails.dart b/lib/presentation/hrPolicyDetails.dart index 5bcba05..fd0bc36 100755 --- a/lib/presentation/hrPolicyDetails.dart +++ b/lib/presentation/hrPolicyDetails.dart @@ -361,7 +361,7 @@ class _HrPolicyDetailsState extends State // Filter the original data based on the search query setState(() { filteredData = originalData.where((row) { - final empStatus = row['emp_is_active'] == 1 ? 'active' : 'inactive'; + final empStatus = row['emp_is_active'] == 1 ? 'active' : 'Inactive'; // Implement your filter logic here // For example, check if any field in the row contains the query // Adjust this logic based on your data structure @@ -377,7 +377,7 @@ class _HrPolicyDetailsState extends State .toString() .toLowerCase() .contains(query.toLowerCase()) || - row['formatted_dob'] + row['formatted_dob'].replaceAll("/", "-") .toString() .toLowerCase() .contains(query.toLowerCase()) || @@ -595,6 +595,7 @@ class _HrPolicyDetailsState extends State IconButton( tooltip: 'Previous Page', onPressed: () => {Navigator.pop(context)}, + // splashRadius: 20, icon: const Icon( Icons.arrow_back_ios, size: 18, @@ -1569,92 +1570,87 @@ class _HrPolicyDetailsState extends State child: Builder( builder: (context) { final isSelf = item['relationship'] == 'Self'; - final hasEcard = - item['ecard_download_link'] != null; + final hasEcard = item['ecard_download_link'] != null; final showEcard = isSelf && hasEcard; - final showClaim = - widget.TokenType == "post" && hasModule; + final showClaim = widget.TokenType == "post" && hasModule; if (!showEcard && !showClaim) { return SizedBox(); // No icon to show } return Row( - mainAxisAlignment: showEcard && !showClaim - ? MainAxisAlignment - .start // Only eCard, push to right - : MainAxisAlignment - .end, // eCard + claim OR only claim + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ + // --- eCard Button --- if (showEcard) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4.0), - child: GestureDetector( - onTap: () { - getEcardDownload( - item['emp_code'], - item['employee_id'], - item['client_policy_id'], - item['policy_no']); - }, - child: Container( - height: 40, - width: 40, - decoration: BoxDecoration( - color: Color(0xFFE6F5F6), - borderRadius: - BorderRadius.circular(8), - ), - child: Padding( - padding: EdgeInsets.all(4), - child: Image.asset( - 'assets/credit_card.png', - fit: BoxFit.contain, + Tooltip( + message: 'Download e-Card', + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + getEcardDownload( + item['emp_code'], + item['employee_id'], + item['client_policy_id'], + item['policy_no']); + }, + child: Container( + height: 40, + width: 40, + decoration: BoxDecoration( + color: Color(0xFFE6F5F6), + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: EdgeInsets.all(4), + child: Image.asset( + 'assets/credit_card.png', + fit: BoxFit.contain, + ), ), ), ), ), ), - if (showEcard && showClaim) - SizedBox(width: 8), + + if (showEcard && showClaim) SizedBox(width: 8), + + // --- Claim Button --- if (showClaim) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4.0), + Tooltip( + message: 'View Claims', child: MouseRegion( - cursor: - SystemMouseCursors - .click, - child: GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ClaimsPolicies( - empCode: item['emp_code']!, + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ClaimsPolicies( + empCode: item['emp_code']!, + ), ), + ); + }, + child: Container( + height: 40, + width: 40, + decoration: BoxDecoration( + color: Color(0xFFE6F5F6), + borderRadius: BorderRadius.circular(8), ), - ); - }, - child: Container( - height: 40, - width: 40, - decoration: BoxDecoration( - color: Color(0xFFE6F5F6), - borderRadius: - BorderRadius.circular(8), - ), - child: Padding( - padding: EdgeInsets.all(4), - child: Image.asset( - 'assets/claim.png', - fit: BoxFit.contain, + child: Padding( + padding: EdgeInsets.all(4), + child: Image.asset( + 'assets/claim.png', + fit: BoxFit.contain, + ), ), ), ), ), - ) ), ], ); @@ -1822,6 +1818,12 @@ class _HrPolicyDetailsState extends State } Widget _buildPagination(BuildContext context) { + // 1. Calculate the range of entries being shown + final totalItems = filteredData.length; + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -1832,7 +1834,8 @@ class _HrPolicyDetailsState extends State if (_currentPage <= 3) { return [1, 2, 3, 4, 5]; - } else if (_currentPage >= totalPages - 2) { + } + if (_currentPage >= totalPages - 2) { return [ totalPages - 4, totalPages - 3, @@ -1840,7 +1843,7 @@ class _HrPolicyDetailsState extends State totalPages - 1, totalPages ]; - } else { + } return [ _currentPage - 2, _currentPage - 1, @@ -1848,35 +1851,50 @@ class _HrPolicyDetailsState extends State _currentPage + 1, _currentPage + 2, ]; - } + } List visiblePages = getVisiblePages(); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( + return Padding( + // Match this horizontal padding (16) to your Table Header padding for perfect alignment + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Pushes text to left, buttons to right + children: [ + // --- LEFT SIDE: Showing Text --- + Text( + "Showing $startEntry to $endEntry of $totalItems entries", + style: GoogleFonts.poppins( + fontSize: 13, + color: const Color(0xFF585757), + fontWeight: FontWeight.w400, + ), + ), + + // --- RIGHT SIDE: Controls --- + Row( children: [ // Dropdown for rows per page - DropdownButton( - value: _rowsPerPage, - items: [5, 10, 15, 20, 50].map((int value) { - return DropdownMenuItem( - value: value, - child: Text(' $value ', - style: GoogleFonts.poppins(fontSize: 15)), - ); - }).toList(), - onChanged: (newValue) { - setState(() { - _rowsPerPage = newValue!; - _currentPage = 1; - }); - }, - ), + DropdownButton( + value: _rowsPerPage, + // focusColor: Colors.transparent, // Fix: Removes the grey/blue highlight on change + items: [5, 10, 15, 20, 50].map((int value) { + return DropdownMenuItem( + value: value, + child: Text(' $value ', + style: GoogleFonts.poppins(fontSize: 15)), + ); + }).toList(), + onChanged: (newValue) { + setState(() { + _rowsPerPage = newValue!; + _currentPage = 1; + }); + }, + ), + + const SizedBox(width: 8), // Previous button IconButton( @@ -1901,7 +1919,7 @@ class _HrPolicyDetailsState extends State for (int page in visiblePages) _buildPageButton(page), // Right ellipsis + last page - if (!visiblePages.contains(totalPages)) + if (!visiblePages.contains(totalPages) && totalPages > 0) Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 4), @@ -1919,8 +1937,8 @@ class _HrPolicyDetailsState extends State ), ], ), - ), - ], + ], + ), ); } diff --git a/lib/presentation/postFileUpload.dart b/lib/presentation/postFileUpload.dart index 1aed3c4..dfcf815 100755 --- a/lib/presentation/postFileUpload.dart +++ b/lib/presentation/postFileUpload.dart @@ -98,6 +98,9 @@ class _postFileUploadState extends State { String? _selectedOption; final List _allowedExtensions = ['xlsx', 'xls']; + bool showSampleButton = false; + String? currentApiValue; // To store the 'value' for the 2nd param + int _currentPage = 1; int _rowsPerPage = 5; @@ -291,6 +294,54 @@ class _postFileUploadState extends State { } } + Future downloadPostSampleFile(String apiParam) async { + print("fun Sam f - in"); + + final post_file_name = apiParam+'_sample_file.xlsx'; + print("fun Sam f - name $post_file_name" ); + final apiurl = Environment.apiUrlPost; + final String url = '$apiurl/downloadSampleExcel/$apiParam'; + final token = widget.Token; + + final response = await http.get( + Uri.parse(url), + headers: { + 'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y', + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + // 'app-signature': 'ts-traveltool-2025-signature-123456', + }, + ); + + if (response.statusCode == 200) { + try { + print("fun sam f - ${response.statusCode}" ); + + // ✅ 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', '$post_file_name') + ..click(); + + // ✅ Revoke the URL to free memory + html.Url.revokeObjectUrl(url); + + ToastHelper.showSuccessToast(context, 'File Downloaded Successfully'); + } catch (e) { + print("fun sam f - fail" ); + throw Exception('Error parsing response: $e'); + } + } else { + ToastHelper.showErrorToast(context, 'Failed to download'); + print("Download failed with status: ${response.statusCode}"); + } + } + void _uploadFile() async { print('Test'); if (kIsWeb) { @@ -562,11 +613,10 @@ class _postFileUploadState extends State { constraints: const BoxConstraints(), ), const SizedBox(width: 6), - Container( - // color: Colors.redAccent.shade100, + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, children: [ Text( "${widget.cardType} - ${widget.cardPolicyNo} " ?? @@ -581,15 +631,35 @@ class _postFileUploadState extends State { 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, - ), + 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), @@ -606,8 +676,10 @@ class _postFileUploadState extends State { onChanged: (val) { setState(() { selectedKey = val; - selectedValue = getFileUploadMasterList - .firstWhere((e) => e['key'] == val)['value']; + final selectedItem = getFileUploadMasterList.firstWhere((e) => e['key'] == val); + selectedValue = selectedItem['value']; + currentApiValue = selectedItem['key']; + showSampleButton = true; }); }, ), @@ -1089,6 +1161,12 @@ class _postFileUploadState extends State { ); Widget _buildPagination(BuildContext context) { + + final totalItems = filteredData.length; + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -1099,7 +1177,7 @@ class _postFileUploadState extends State { if (_currentPage <= 3) { return [1, 2, 3, 4, 5]; - } else if (_currentPage >= totalPages - 2) { + } if (_currentPage >= totalPages - 2) { return [ totalPages - 4, totalPages - 3, @@ -1107,7 +1185,7 @@ class _postFileUploadState extends State { totalPages - 1, totalPages ]; - } else { + } return [ _currentPage - 2, _currentPage - 1, @@ -1115,7 +1193,7 @@ class _postFileUploadState extends State { _currentPage + 1, _currentPage + 2, ]; - } + } List visiblePages = getVisiblePages(); diff --git a/lib/presentation/preFileUpload.dart b/lib/presentation/preFileUpload.dart index b9fa36b..3469d36 100755 --- a/lib/presentation/preFileUpload.dart +++ b/lib/presentation/preFileUpload.dart @@ -882,7 +882,9 @@ class _excelVerifyState extends State { SizedBox( width: 40, height: 40 , - child: ElevatedButton( + child: Tooltip( + message: 'Upload', // The text that appears on hover + child: ElevatedButton( onPressed: () => null, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFD4F1F2), @@ -903,6 +905,7 @@ class _excelVerifyState extends State { color: Color(0xFF00999E), ) ), + ), ), const SizedBox(height: 15), Text( @@ -941,7 +944,9 @@ class _excelVerifyState extends State { SizedBox( width: 40, height: 40 , - child: ElevatedButton( + child: Tooltip( + message: 'Upload', // The text that appears on hover + child: ElevatedButton( onPressed: () { if (!_validateDatesBeforeUpload()) return; if (fileName == null) { @@ -967,6 +972,7 @@ class _excelVerifyState extends State { color: Color(0xFF00999E), ) ), + ), ), SizedBox(height: 12), Text('Upload Your Documents', @@ -1175,7 +1181,9 @@ class _excelVerifyState extends State { Row( children: [ if (item['file_error_status'] == '1') - InkWell( + Tooltip( + message: 'Info', // Added tooltip name + child:InkWell( onTap: () async { print(item); // return; @@ -1227,10 +1235,13 @@ class _excelVerifyState extends State { color: Colors.red, ), ), + ), SizedBox(width: 10), _buildStatusChip(item['status']), SizedBox(width: 10), - InkWell( + Tooltip( + message: 'Download', // Added tooltip name + child:InkWell( onTap: () { getHrFileDownload(item['id'], item['file_name']); }, @@ -1249,6 +1260,7 @@ class _excelVerifyState extends State { ), ), ), + ), ], ), /// ⬇ Download @@ -1293,6 +1305,12 @@ class _excelVerifyState extends State { } Widget _buildPagination(BuildContext context) { + // 1. Calculate the range of entries being shown + final totalItems = filteredData.length; + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -1303,7 +1321,8 @@ class _excelVerifyState extends State { if (_currentPage <= 3) { return [1, 2, 3, 4, 5]; - } else if (_currentPage >= totalPages - 2) { + } + if (_currentPage >= totalPages - 2) { return [ totalPages - 4, totalPages - 3, @@ -1311,29 +1330,42 @@ class _excelVerifyState extends State { totalPages - 1, totalPages ]; - } else { - return [ - _currentPage - 2, - _currentPage - 1, - _currentPage, - _currentPage + 1, - _currentPage + 2, - ]; } + return [ + _currentPage - 2, + _currentPage - 1, + _currentPage, + _currentPage + 1, + _currentPage + 2, + ]; + } List visiblePages = getVisiblePages(); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( + return Padding( + // Match this horizontal padding (16) to your Table Header padding for perfect alignment + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Pushes text to left, buttons to right + children: [ + // --- LEFT SIDE: Showing Text --- + Text( + "Showing $startEntry to $endEntry of $totalItems entries", + style: GoogleFonts.poppins( + fontSize: 13, + color: const Color(0xFF585757), + fontWeight: FontWeight.w400, + ), + ), + + // --- RIGHT SIDE: Controls --- + Row( children: [ // Dropdown for rows per page DropdownButton( value: _rowsPerPage, + // focusColor: Colors.transparent, // Fix: Removes the grey/blue highlight on change items: [5, 10, 15, 20, 50].map((int value) { return DropdownMenuItem( value: value, @@ -1371,7 +1403,7 @@ class _excelVerifyState extends State { for (int page in visiblePages) _buildPageButton(page), // Right ellipsis + last page - if (!visiblePages.contains(totalPages)) + if (!visiblePages.contains(totalPages) && totalPages > 0) Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 4), @@ -1389,8 +1421,8 @@ class _excelVerifyState extends State { ), ], ), - ), - ], + ], + ), ); } diff --git a/lib/service/hrDashboardTabs/cd.dart b/lib/service/hrDashboardTabs/cd.dart index 0f11fca..254d2ab 100755 --- a/lib/service/hrDashboardTabs/cd.dart +++ b/lib/service/hrDashboardTabs/cd.dart @@ -553,6 +553,12 @@ class _CdPolicieState extends State { ); Widget _buildPagination(BuildContext context) { + // 1. Calculate the range of entries being shown + final totalItems = filteredData.length; + final int startEntry = totalItems == 0 ? 0 : ((_currentPage - 1) * _rowsPerPage) + 1; + int endEntry = _currentPage * _rowsPerPage; + if (endEntry > totalItems) endEntry = totalItems; + final totalPages = (filteredData.length / _rowsPerPage).ceil(); const visiblePageCount = 5; @@ -563,7 +569,8 @@ class _CdPolicieState extends State { if (_currentPage <= 3) { return [1, 2, 3, 4, 5]; - } else if (_currentPage >= totalPages - 2) { + } + if (_currentPage >= totalPages - 2) { return [ totalPages - 4, totalPages - 3, @@ -571,29 +578,42 @@ class _CdPolicieState extends State { totalPages - 1, totalPages ]; - } else { - return [ - _currentPage - 2, - _currentPage - 1, - _currentPage, - _currentPage + 1, - _currentPage + 2, - ]; } + return [ + _currentPage - 2, + _currentPage - 1, + _currentPage, + _currentPage + 1, + _currentPage + 2, + ]; + } List visiblePages = getVisiblePages(); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( + return Padding( + // Match this horizontal padding (16) to your Table Header padding for perfect alignment + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // Pushes text to left, buttons to right + children: [ + // --- LEFT SIDE: Showing Text --- + Text( + "Showing $startEntry to $endEntry of $totalItems entries", + style: GoogleFonts.poppins( + fontSize: 13, + color: const Color(0xFF585757), + fontWeight: FontWeight.w400, + ), + ), + + // --- RIGHT SIDE: Controls --- + Row( children: [ // Dropdown for rows per page DropdownButton( value: _rowsPerPage, + // focusColor: Colors.transparent, // Fix: Removes the grey/blue highlight on change items: [5, 10, 15, 20, 50].map((int value) { return DropdownMenuItem( value: value, @@ -609,8 +629,11 @@ class _CdPolicieState extends State { }, ), + const SizedBox(width: 8), + // Previous button IconButton( + tooltip: 'Previous Page', onPressed: _currentPage > 1 ? () => setState(() => _currentPage--) : null, @@ -631,7 +654,7 @@ class _CdPolicieState extends State { for (int page in visiblePages) _buildPageButton(page), // Right ellipsis + last page - if (!visiblePages.contains(totalPages)) + if (!visiblePages.contains(totalPages) && totalPages > 0) Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 4), @@ -649,8 +672,8 @@ class _CdPolicieState extends State { ), ], ), - ), - ], + ], + ), ); } diff --git a/lib/service/multi_file_upload_widget.dart b/lib/service/multi_file_upload_widget.dart index 57d23f2..a58487f 100755 --- a/lib/service/multi_file_upload_widget.dart +++ b/lib/service/multi_file_upload_widget.dart @@ -203,6 +203,7 @@ class _MultiFileUploadWidgetState extends State { title: Text(uploaded.file.name, style: const TextStyle(fontSize: 14)), trailing: IconButton( icon: const Icon(Icons.close, color: Colors.red), + tooltip: 'Remove', // Built-in property onPressed: () => _removeFile(index), ), ),