diff --git a/lib/Screens/userManagement/create_user/traveller_details.dart b/lib/Screens/userManagement/create_user/traveller_details.dart index 6941526..03612e9 100644 --- a/lib/Screens/userManagement/create_user/traveller_details.dart +++ b/lib/Screens/userManagement/create_user/traveller_details.dart @@ -2230,7 +2230,7 @@ class TravellerDetailsState extends State { print("Raw file path: $passportFileUrlFromApi"); apiService.getPassportDocDownload( context, - widget.userIdApi, + widget.userIdApi!, ); // // Extract public part of the path starting from "/assets" diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index e0d1a22..a58276d 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -1152,12 +1152,11 @@ class ApiService { } } - Future getPassportDocDownload(BuildContext context, userId) async { - // final String apiUrldata = '$apiUrl/api/plans/download?plan_id=$planId'; + Future getPassportDocDownload( + BuildContext context, + String userId, + ) async { final String apiUrldata = '$apiUrl/api/downloadPassport?user_id=$userId'; - - // final String apiUrldata = '$apiUrl/auth/googlelogin'; - final token = await getToken(); if (token == null) { @@ -1175,80 +1174,183 @@ class ApiService { if (response.statusCode == 200) { try { - print("PDf Dowloaded"); - final contentType = response.headers['content-type'] ?? ''; + print("✅ File download started"); - // print('contentType - $contentType'); - // String fileName = "Document"; - // if (contentType.contains("pdf")) { - // fileName += ".pdf"; - // } else if (contentType.contains("png")) { - // fileName += ".png"; - // } else if (contentType.contains("jpeg") || - // contentType.contains("jpg")) { - // fileName += ".jpg"; - // } else { - // // fallback (unknown type, save as bin) - // fileName += ".$contentType"; - // } + // Get MIME type from response + final contentType = + response.headers['content-type'] ?? 'application/octet-stream'; + // Try extracting filename from Content-Disposition final disposition = response.headers['content-disposition'] ?? ''; String fileName = "passport_$userId"; final regExp = RegExp( - r'filename[^;=\n]*=(([' - '"]).*?\2|[^;\n]*)', + r'filename[^;=\n]=(([' + '"]).?\2|[^;\n]*)', ); final match = regExp.firstMatch(disposition); if (match != null) { fileName = match.group(1)!.replaceAll('"', ''); + // 🔧 Remove UTF-8'' prefix if present + fileName = fileName.replaceFirst(RegExp(r"^UTF-8''"), ''); + } else { + // If no filename in header, determine by content type + if (contentType.contains('pdf')) { + fileName += '.pdf'; + } else if (contentType.contains('png')) { + fileName += '.png'; + } else if (contentType.contains('jpeg') || + contentType.contains('jpg')) { + fileName += '.jpg'; + } else if (contentType.contains('json')) { + fileName += '.json'; + } else if (contentType.contains('plain')) { + fileName += '.txt'; + } else { + // default fallback + fileName += '.bin'; + } } - // Create a blob from the response body - final blob = html.Blob([response.bodyBytes]); - - // Generate a download URL for the blob + // ✅ FIX: Include content type for correct format + final blob = html.Blob([response.bodyBytes], contentType); final url = html.Url.createObjectUrlFromBlob(blob); - // Create a link element to trigger the download + // Trigger download final anchor = html.AnchorElement(href: url) ..setAttribute('download', fileName) ..click(); - // Revoke the download URL to free up resources html.Url.revokeObjectUrl(url); + print("📥 Downloaded as $fileName"); } catch (e) { - throw Exception('Error parsing response: $e'); + throw Exception('Error while saving file: $e'); } } else if (response.statusCode == 403) { - print("403-FORB"); + print("403 Forbidden"); await logout(context); - return null; - // throw Exception('Failed to load users'); } else if (response.statusCode == 404) { - // showDialog( - // context: context, - // builder: (BuildContext context) { - // return AlertDialog( - // title: Text('File not found.'), - // // content: Text('File not found.'), - // actions: [ - // TextButton( - // child: Text('OK'), - // onPressed: () { - // Navigator.of(context).pop(); // Close the dialog - // }, - // ), - // ], - // ); - // }, - // ); + print("❌ File not found"); + showDialog( + context: context, + builder: + (_) => AlertDialog( + title: const Text('File not found'), + content: const Text('The requested file could not be found.'), + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ); } else { - throw Exception('Failed to load plans'); + throw Exception('Failed to download passport document'); } } + // Future getPassportDocDownload(BuildContext context, userId) async { + // // final String apiUrldata = '$apiUrl/api/plans/download?plan_id=$planId'; + // final String apiUrldata = '$apiUrl/api/downloadPassport?user_id=$userId'; + // + // // final String apiUrldata = '$apiUrl/auth/googlelogin'; + // + // final token = await getToken(); + // + // if (token == null) { + // throw Exception('Token not found. Please log in.'); + // } + // + // final response = await http.get( + // Uri.parse(apiUrldata), + // headers: { + // 'Authorization': 'Bearer $token', + // 'Content-Type': 'application/json', + // 'app-signature': 'ts-traveltool-2025-signature-123456', + // }, + // ); + // + // if (response.statusCode == 200) { + // try { + // print("PDf Dowloaded"); + // final contentType = response.headers['content-type'] ?? ''; + // + // // print('contentType - $contentType'); + // // String fileName = "Document"; + // // if (contentType.contains("pdf")) { + // // fileName += ".pdf"; + // // } else if (contentType.contains("png")) { + // // fileName += ".png"; + // // } else if (contentType.contains("jpeg") || + // // contentType.contains("jpg")) { + // // fileName += ".jpg"; + // // } else { + // // // fallback (unknown type, save as bin) + // // fileName += ".$contentType"; + // // } + // + // final disposition = response.headers['content-disposition'] ?? ''; + // String fileName = "passport_$userId"; + // + // final regExp = RegExp( + // r'filename[^;=\n]*=(([' + // '"]).*?\2|[^;\n]*)', + // ); + // final match = regExp.firstMatch(disposition); + // if (match != null) { + // fileName = match.group(1)!.replaceAll('"', ''); + // } + // + // // Create a blob from the response body + // final blob = html.Blob([response.bodyBytes]); + // + // // Generate a download URL for the blob + // final url = html.Url.createObjectUrlFromBlob(blob); + // + // // Create a link element to trigger the download + // final anchor = + // html.AnchorElement(href: url) + // ..setAttribute('download', fileName) + // ..click(); + // + // // Revoke the download URL to free up resources + // html.Url.revokeObjectUrl(url); + // } catch (e) { + // throw Exception('Error parsing response: $e'); + // } + // } + // + // + // else if (response.statusCode == 403) { + // print("403-FORB"); + // await logout(context); + // return null; + // // throw Exception('Failed to load users'); + // } else if (response.statusCode == 404) { + // // showDialog( + // // context: context, + // // builder: (BuildContext context) { + // // return AlertDialog( + // // title: Text('File not found.'), + // // // content: Text('File not found.'), + // // actions: [ + // // TextButton( + // // child: Text('OK'), + // // onPressed: () { + // // Navigator.of(context).pop(); // Close the dialog + // // }, + // // ), + // // ], + // // ); + // // }, + // // ); + // } else { + // throw Exception('Failed to load plans'); + // } + // } + Future getForexPdfDownload(BuildContext context, forexId) async { final String apiUrldata = '$apiUrl/api/plans/forexDownload?forex_id=$forexId';