From 2937984b56907c0171a30c536006d983b1619154 Mon Sep 17 00:00:00 2001 From: SurendarSuri30 Date: Tue, 7 Jul 2026 17:57:19 +0530 Subject: [PATCH] claim form download --- lib/pages/postEnrollment/claimprocess.dart | 357 +++++++++++++++++- .../postEnrollment/service/api_service.dart | 15 + 2 files changed, 371 insertions(+), 1 deletion(-) diff --git a/lib/pages/postEnrollment/claimprocess.dart b/lib/pages/postEnrollment/claimprocess.dart index 0e7e231..46e0c90 100755 --- a/lib/pages/postEnrollment/claimprocess.dart +++ b/lib/pages/postEnrollment/claimprocess.dart @@ -1,11 +1,13 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; + import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:nhance_app_pwa/customAppBar/customAppBar.dart'; import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart'; + import 'package:nhance_app_pwa/pages/postEnrollment/service/svg_service.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'package:video_player/video_player.dart'; @@ -14,6 +16,9 @@ import 'package:video_player/video_player.dart'; import '../../customAppBar/responsive.dart'; import '../../customAppBar/tabs.dart'; import '../../customAppBar/toastHelper.dart'; + import '../helpers/custom_download_snackbar.dart'; + import '../helpers/ecard_download_notification_service.dart'; + import '../helpers/ecard_download_service.dart'; import '../service/SessionManager.dart'; import '../service/TokenService.dart'; import '../service/multi_video_player.dart'; @@ -37,6 +42,12 @@ import 'package:nhance_app_pwa/logger.dart'; dynamic empCodeString; dynamic empPrimaryId; dynamic client_id; + dynamic mobileNo; + dynamic client_branch_id; + dynamic emailId; + List> policyList = []; + bool _isDownloadingClaimForm = false; + final EcardDownloadService _ecardDownloadService = const EcardDownloadService(); dynamic cashLessClaimsDetails; dynamic reimbursementClaimsDetails; dynamic cashLessSectionName; @@ -91,11 +102,354 @@ import 'package:nhance_app_pwa/logger.dart'; logDebug(empCodeString); // Check if emp_code is correct empPrimaryId = session.empPrimaryId; client_id = session.client_id; + mobileNo = session.mobileNo; + client_branch_id = session.empClientBranchId; + emailId = session.empEmailCorporate ?? ''; logDebug(client_id); getCashlessAndReimbursement(); + getActiveAndInactivePolicyDetails(); } } + Future getActiveAndInactivePolicyDetails() async { + if (client_id == null || empCodeString == null) { + return; + } + + try { + final responseActive = await apiService.getActiveAndInactivePolicyDetails( + client_id!, empCodeString!, 'Active', client_branch_id, mobileNo, emailId); + + final responseInactive = await apiService.getActiveAndInactivePolicyDetails( + client_id!, empCodeString!, 'Inactive', client_branch_id, mobileNo, emailId); + + final bool isActiveSuccess = responseActive['status'] == 'success' && + responseActive['data'] != null; + final bool isInactiveSuccess = responseInactive['status'] == 'success' && + responseInactive['data'] != null; + + final List> activeData = isActiveSuccess + ? List>.from(responseActive['data']) + : []; + + final List> inactiveData = isInactiveSuccess + ? List>.from(responseInactive['data']) + : []; + + final retailPolicyDetails = + List.from(responseActive['retail_policy_data'] ?? []); + + final filteredRetail = retailPolicyDetails + .where((item) => item.containsKey('policy_transaction_id')) + .toList(); + + final combinedPolicies = [...activeData, ...inactiveData, ...filteredRetail]; + + if (mounted) { + setState(() { + policyList = combinedPolicies + .where((policy) => + policy['client_policy_id'] != null && + policy['client_policy_id'].toString().trim().isNotEmpty) + .map((policy) => Map.from(policy)) + .toList(); + }); + } + } catch (e) { + logDebug('Error fetching policies for claim form: $e'); + } + } + + String _policyDropdownLabel(Map policy) { + final name = policy['policy_name'] ?? policy['heading'] ?? ''; + final no = policy['policy_no'] ?? ''; + if (name.toString().isNotEmpty && no.toString().isNotEmpty) { + return '$name - $no'; + } + return name.toString().isNotEmpty ? name.toString() : no.toString(); + } + + bool _isApiSuccess(Map response) { + final status = response['status']; + return status == true || status == 'success'; + } + + String? _extractDownloadUrl(dynamic data) { + if (data == null) return null; + if (data is Map && data['download_url'] != null) { + final url = data['download_url'].toString().trim(); + if (url.isNotEmpty) return url; + } + if (data is String && data.trim().isNotEmpty) return data.trim(); + return null; + } + + void _showInsurerClaimFormPopup() { + if (policyList.isEmpty) { + ToastHelper.showErrorToast(context, 'No policies available'); + return; + } + + String? selectedClientPolicyId = policyList.first['client_policy_id']?.toString(); + + showDialog( + context: context, + barrierDismissible: true, + builder: (dialogContext) { + return StatefulBuilder( + builder: (context, setDialogState) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + title: Text( + 'Insurer Claim Form', + style: GoogleFonts.poppins( + fontSize: Responsive.isDesktop(context) ? 20 : 18, + fontWeight: FontWeight.w600, + color: const Color(0xFF000000), + ), + ), + content: SizedBox( + width: Responsive.isDesktop(context) ? 420 : double.maxFinite, + child: DropdownButtonFormField( + value: selectedClientPolicyId, + decoration: InputDecoration( + labelText: 'Select Policy', + border: const OutlineInputBorder(), + labelStyle: GoogleFonts.poppins( + fontSize: 14, + color: const Color(0xFF636363), + ), + ), + items: policyList.map((policy) { + final clientPolicyId = + policy['client_policy_id']?.toString() ?? ''; + return DropdownMenuItem( + value: clientPolicyId, + child: Text( + _policyDropdownLabel(policy), + style: GoogleFonts.poppins( + fontSize: 14, + color: const Color(0xFF000000), + ), + ), + ); + }).toList(), + onChanged: (value) { + setDialogState(() { + selectedClientPolicyId = value; + }); + }, + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(dialogContext), + child: Text( + 'Cancel', + style: GoogleFonts.poppins( + color: const Color(0xFF636363), + fontWeight: FontWeight.w500, + ), + ), + ), + TextButton( + onPressed: _isDownloadingClaimForm || + selectedClientPolicyId == null || + selectedClientPolicyId!.isEmpty + ? null + : () async { + await _downloadInsurerClaimForm( + selectedClientPolicyId!, + dialogContext, + ); + }, + child: Text( + 'Download', + style: GoogleFonts.poppins( + color: const Color(0xFFE26728), + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ); + }, + ); + }, + ); + } + + Future _downloadInsurerClaimForm( + String clientPolicyId, + BuildContext dialogContext, + ) async { + if (_isDownloadingClaimForm) return; + + setState(() => _isDownloadingClaimForm = true); + + try { + final response = + await apiService.getInsurerClaimFormDownloadUrl(clientPolicyId); + + if (!mounted) return; + + if (!_isApiSuccess(response)) { + ToastHelper.showErrorToast( + context, + response['message']?.toString() ?? 'Unable to download claim form', + ); + return; + } + + final downloadUrl = _extractDownloadUrl(response['data']); + if (downloadUrl == null || downloadUrl.isEmpty) { + ToastHelper.showErrorToast( + context, + response['message']?.toString() ?? 'Claim form is not available', + ); + return; + } + + final successMessage = response['message']?.toString() ?? + 'Claim form downloaded successfully'; + + final selectedPolicy = policyList.firstWhere( + (policy) => + policy['client_policy_id']?.toString() == clientPolicyId, + orElse: () => {}, + ); + final policyNo = selectedPolicy['policy_no']?.toString(); + final safePolicyNo = + policyNo?.replaceAll(RegExp(r'[^\w\-.]'), '_') ?? clientPolicyId; + final fileName = 'claim_form_$safePolicyNo.pdf'; + + if (!kIsWeb) { + CustomDownloadSnackbar.show( + context, + message: 'Downloading claim form...', + ); + } + + final token = await TokenService.getPostToken(); + final result = await _ecardDownloadService.downloadEcard( + url: downloadUrl, + fileName: fileName, + headers: { + 'APP-SIGNATURE': + 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y', + if (token != null && token.isNotEmpty) + 'Authorization': 'Bearer $token', + }, + ); + + if (!mounted) return; + + if (result.success) { + if (dialogContext.mounted) { + Navigator.pop(dialogContext); + } + ToastHelper.showSuccessToast(context, successMessage); + if (!kIsWeb && + result.savedPath != null && + result.savedPath!.isNotEmpty) { + await EcardDownloadNotificationService.showDownloadCompleted( + filePath: result.savedPath!, + fileName: fileName, + ); + } + } else { + ToastHelper.showErrorToast( + context, + result.message ?? 'Could not download claim form', + ); + } + } catch (e) { + logDebug('Claim form download error: $e'); + if (mounted) { + ToastHelper.showErrorToast( + context, + 'Unable to download claim form. Please try again.', + ); + } + } finally { + if (mounted) { + setState(() => _isDownloadingClaimForm = false); + } + } + } + + Widget _buildInsurerClaimFormButton(BuildContext context) { + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: _showInsurerClaimFormPopup, + child: Card( + elevation: 0, + shape: RoundedRectangleBorder( + side: const BorderSide( + color: Color(0xFFD9D9D9), + width: 1.0, + ), + borderRadius: BorderRadius.circular(8.0), + ), + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + ), + padding: Responsive.isDesktop(context) + ? const EdgeInsets.symmetric( + vertical: 15, horizontal: 15) + : const EdgeInsets.symmetric( + vertical: 20, horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 11, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.string( + SvgService.getSvg('general'), + width: 25, + height: 25, + ), + const SizedBox(width: 10), + Text( + 'Insurer Claim Form', + textAlign: TextAlign.start, + style: GoogleFonts.poppins( + fontSize: Responsive.isDesktop(context) ? 18 : 12, + fontWeight: FontWeight.w400, + color: const Color(0xFF404040), + ), + ), + ], + ), + ), + const Expanded( + flex: 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon( + Icons.chevron_right, + color: Color(0xFFE26728), + size: 20, + ), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } + Future getCashlessAndReimbursement() async { setState(() { isLoading = true; @@ -511,7 +865,8 @@ import 'package:nhance_app_pwa/logger.dart'; ]), ), - SizedBox(height: Responsive.isDesktop(context) ? 40 : 10), + _buildInsurerClaimFormButton(context), + SizedBox(height: Responsive.isDesktop(context) ? 40 : 10), ], ), ), diff --git a/lib/pages/postEnrollment/service/api_service.dart b/lib/pages/postEnrollment/service/api_service.dart index 36d6896..0767450 100755 --- a/lib/pages/postEnrollment/service/api_service.dart +++ b/lib/pages/postEnrollment/service/api_service.dart @@ -163,6 +163,21 @@ class ApiService { return response; } + Future> getInsurerClaimFormDownloadUrl( + String clientPolicyId) async { + logDebug(_postToken); + if (_postToken == null) { + await _initializeToken(); + } + final url = Uri.parse( + '${Environment.apiUrl}getInsurerClaimFormDownloadUrl?client_policy_id=$clientPolicyId'); + final headers = { + 'Authorization': 'Bearer $_postToken' ?? '', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + Future> getWellnessLink( empPrimaryId, client_policy_id) async { logDebug(_postToken);