import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:frontend/utils/auth_utils.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:universal_html/html.dart' as html; import 'package:universal_html/js.dart'; import '../../config/apiUrl.dart'; import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; class ApiService { Future storeUserDetails(BuildContext context, String token) async { try { final parts = token.split('.'); if (parts.length != 3) throw Exception('Invalid token format'); final payload = json.decode( utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))), ); final userData = payload['data']; final prefs = await SharedPreferences.getInstance(); await prefs.setString('auth_token', token); await prefs.setString( 'user_data', jsonEncode(userData), ); // Store full user data if (userData != null) { final pref = await SharedPreferences.getInstance(); // await pref.clear(); // print("Clearing Token--"); await pref.setString('auth_token', token); await pref.setString('user_data', jsonEncode(userData)); // userRole = userData['role']; print("store1userData - $userData"); print("store2userData11 - ${userData['role']}"); // print("userData12 - $userRole"); } await getOrganizationData(context); } catch (e) { print('Error decoding token: $e'); } } Future logout(BuildContext context) async { await logoutApi(); final prefs = await SharedPreferences.getInstance(); await prefs.clear(); // Optional: clear sessionStorage if used // html.window.sessionStorage.clear(); // Navigate to login or home page context?.go('/'); } Future logoutApi() async { String? userId = await getUserId(); print('userId - $userId'); final String apiUrldata = '$apiUrl/api/auth/logout?user_id=$userId'; 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) { final data = json.decode(response.body); print("Logout API response: $data"); } else { throw Exception('Failed to logout. Status: ${response.statusCode}'); } } Future storeTripUserDetails(BuildContext context, String token) async { try { final parts = token.split('.'); if (parts.length != 3) throw Exception('Invalid token format'); print('storeTripUserDetails - $token'); final payload = json.decode( utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))), ); final userData = payload['data']; final prefs = await SharedPreferences.getInstance(); await prefs.setString('trip_auth_token', token); await prefs.setString( 'trip_user_data', jsonEncode(userData), ); // Store full user data if (userData != null) { final pref = await SharedPreferences.getInstance(); await pref.setString('trip_auth_token', token); await pref.setString('trip_user_data', jsonEncode(userData)); // userRole = userData['role']; print("storetrip_userData - $userData"); print("storetrip_2userData11 - ${userData['role']}"); // print("userData12 - $userRole"); } // await getOrganizationData(context); } catch (e) { print('Error decoding token: $e'); } } Future getOrganizationData(BuildContext context) async { try { print("ORG getUpdatedServices"); final result = await fetchOrganization(context); print("UUPdatedServices - $result"); // ✅ Save to local storage final prefs = await SharedPreferences.getInstance(); final jsonString = jsonEncode(result); await prefs.setString('org_data', jsonString); print("✅ Organization data saved to SharedPreferences."); print("selectedOrg - $result"); } catch (e) { print('Error fetching updatedServices list: $e'); } } Future> fetchCountryList(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getcountryMaster'; 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 { final data = json.decode(response.body); print("Country - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load country list'); } } Future> fetchHotelsList(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getHotels'; 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 { final data = json.decode(response.body); print("Hotelss - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load country list'); } } Future> fetchAirlineList(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getAirlineMaster'; 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 { final data = json.decode(response.body); print("Airline - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load country list'); } } Future> fetchUsers(BuildContext context) async { String? ordId = await getOrgId(); final String apiUrlData = '$apiUrl/api/users?org_id=$ordId'; final String? token = await getToken(); print("Fetch Users"); print("TOEKRWE: $token"); 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) { final data = json.decode(response.body); return data['data']; // Returning raw JSON list } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load users'); } } Future fetchCostCenter(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getCostCenterMaster'; final token = await getToken(); final userId = await getUserId(); // print("SUSRTRT- $userId"); // 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } List plansJson = data['data']; // 'data' is a Map, not a List // setState(() { // apiCostData = plansJson; // Store API response in state // if(apiCostData!.isNotEmpty){ // selectedCostCenterId =apiCostData?.first['department_id']; // } // if (apiCostData != null && apiCostData!.isNotEmpty) { // selectedCostCenterId ??= apiCostData!.first['department_id']?.toString(); // } // }); print('plansJSON'); return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future fetchDepartmentCostCenter(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getDepartmentList'; final token = await getToken(); final userId = await getUserId(); // print("SUSRTRT- $userId"); // 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } List plansJson = data['data']; // 'data' is a Map, not a List // setState(() { // apiCostData = plansJson; // Store API response in state // if(apiCostData!.isNotEmpty){ // selectedCostCenterId =apiCostData?.first['department_id']; // } // if (apiCostData != null && apiCostData!.isNotEmpty) { // selectedCostCenterId ??= apiCostData!.first['department_id']?.toString(); // } // }); print('plansJSON'); return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchMasterDropdown(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getDropdownMaster'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } Map plansJson = data['data']; // 'data' is a Map, not a List return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchAllServices(BuildContext context) async { final String apiUrldata = '$apiUrl/api/service'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchAllGroup(BuildContext context) async { String? orgId = await getOrgId(); final String apiUrldata = '$apiUrl/api/groups?for=table_view&org_id=$orgId'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchFindGroup(BuildContext context) async { String? orgId = await getOrgId(); final String apiUrldata = '$apiUrl/api/groups/find/$orgId'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchAllPolicy(BuildContext context) async { String? orgId = await getOrgId(); final String apiUrldata = '$apiUrl/api/policy?for=table_view&org_id=$orgId'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> getSinglePolicy( int policyId, BuildContext context, ) async { final String apiUrldata = '$apiUrl/api/policy/find/${policyId}'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } Map plansJson = data['data']; // 'data' is a Map, not a List return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> fetchOrganization(BuildContext context) async { String? orgId = await getOrgId(); // final String apiUrldata = '$apiUrl/api/organizations'; final String apiUrldata = '$apiUrl/api/organizations/find/$orgId'; final token = await getToken(); print('ORGFindToken - $token'); 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } // Make sure each item is a Map // final List> orgList = // List>.from(data['data']); // return orgList; return Map.from(data['data']); } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load organizations'); } } Future> getViewPlan( String planId, userId, BuildContext context, ) async { final String apiUrldata = '$apiUrl/api/plans/cancle_plan?plan_id=$planId&updated_by=$userId'; // final String apiUrldata = '$apiUrl/api/plans/find/$planId'; print("API URL: $apiUrldata"); // final token = await getToken(); final token = await getToken(); final response = await http.get( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', // Add token here 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); if (response.statusCode == 200) { final Map? resData = json.decode(response.body); return resData?["data"]; } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> getViewPlanEdit( String planId, BuildContext context, ) async { final String apiUrldata = '$apiUrl/api/plans/find/$planId'; print("API URL: $apiUrldata"); // final token = await getToken(); final token = await getToken(); final response = await http.put( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', // Add token here 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); if (response.statusCode == 200) { final Map? resData = json.decode(response.body); return resData?["data"]; } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future handleTokenRefresh(BuildContext context, String userId) async { final String apiUrldata = '$apiUrl/api/user/refreshUserToken?user_id=$userId'; print("API URL: $userId"); // final token = await getToken(); final token = await getToken(); 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) { final data = jsonDecode(response.body); print("data- $data"); final token = data['token']; // Assuming the token is in response // final userId = data['user_id'].toString(); print("Token - $token"); await storeUserDetails(context, token); } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return null; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future handleTripWiseToken(String userId, BuildContext context) async { final String apiUrldata = '$apiUrl/api/user/refreshUserToken?user_id=$userId'; print("API URL: $userId"); // final token = await getToken(); final token = await getToken(); print('handleTripWiseToken OLd - $token'); 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) { final data = jsonDecode(response.body); print("data- $data"); final token = data['token']; // Assuming the token is in response // final userId = data['user_id'].toString(); print('handleTripWiseToken NEW - $token'); await storeTripUserDetails(context, token); } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return null; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future viewPlan( BuildContext context, String planId, { bool isViewMode = false, bool isMyTrips = false, }) async { try { Map planData = await getViewPlanEdit(planId, context); print("ViewAAA API Service - $planData"); context.go( isMyTrips ? '/createPlan' : '/allTrips/trips', extra: {'planData': planData, 'isViewMode': isViewMode}, ); } catch (e) { print("Error fetching plan: $e"); } } Future viewPlanForApprover( BuildContext context, String planId, String? approverId, String? delegaterId, String? approver_status, { bool isViewMode = false, bool isApprover = true, }) async { try { Map planData = await getViewPlanEdit(planId, context); print("ViewAAA - $planData"); context.replace( '/approver/plans', extra: { 'planData': planData, 'approver_status': approver_status, 'approverId': approverId, 'delegaterId': delegaterId, 'isViewMode': isViewMode, 'isApprover': isApprover, }, ); } catch (e) { print("Error fetching plan: $e"); } } Future> fetchUserApprovalList( BuildContext context, ) async { String? orgId = await getOrgId(); String? userId = await getUserId(); // final String apiUrldata = '$apiUrl/api/organizations'; final String apiUrldata = '$apiUrl/api/plans/findApprovalList?user_id=$userId&org_id=$orgId'; // '$apiUrl/api/findApprovalList?user_id=$userId&org_id=$orgId'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } // Make sure each item is a Map // final List> orgList = // List>.from(data['data']); // return orgList; return Map.from(data['data']); } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load organizations'); } } // Flight From - To Future> fetchFlightsCountryList( BuildContext context, String? tripType, ) async { print("FlightTripType- $tripType"); final String apiUrldata = '$apiUrl/api/getAirportCodeMaster?trip_type=$tripType'; 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 { final data = json.decode(response.body); print("Country - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load country list'); } } Future> fetchTrainCountryList(BuildContext context) async { final String apiUrldata = '$apiUrl/api/getTrainCodeMaster'; 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 { final data = json.decode(response.body); print("Country - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } return data['data']; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load country list'); } } Future getPdfDownload(BuildContext context, planId) async { final String apiUrldata = '$apiUrl/api/plans/download?plan_id=$planId'; // 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"); // 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', 'trip_plan_$planId.pdf') ..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 getPassportDocDownload( BuildContext context, String userId, ) async { final String apiUrldata = '$apiUrl/api/downloadPassport?user_id=$userId'; 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("✅ File download started"); // 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]*)', ); 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'; } } // ✅ FIX: Include content type for correct format final blob = html.Blob([response.bodyBytes], contentType); final url = html.Url.createObjectUrlFromBlob(blob); // Trigger download final anchor = html.AnchorElement(href: url) ..setAttribute('download', fileName) ..click(); html.Url.revokeObjectUrl(url); print("📥 Downloaded as $fileName"); } catch (e) { throw Exception('Error while saving file: $e'); } } else if (response.statusCode == 403) { print("403 Forbidden"); await logout(context); } else if (response.statusCode == 404) { 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 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'; // 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"); // 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', 'Forex_$forexId.pdf') ..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'); } } // download the Template for bulk upload the user Future> getDownloadUserTemplateForUpload( BuildContext context, ) async { final String apiUrldata = '$apiUrl/api/user/userUploadTemplate'; // download the Template for bulk upload user => api // 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("XL Dowloaded"); // 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', 'user_file.xlsx') ..click(); // Revoke the download URL to free up resources html.Url.revokeObjectUrl(url); return {'status': true, 'message': 'Successfully Downloaded'}; } catch (e) { return {'status': false, 'message': 'Download error: $e'}; } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else if (response.statusCode == 404) { return {'status': false, 'message': 'File not found (404).'}; } else { return {'status': false, 'message': 'Failed to download. Try again.'}; } } //---------------------------------------User Management----------------------------------- Future> getSingleUser( BuildContext context, int userId, ) async { print('Single USer 1 - $userId'); final String apiUrldata = '$apiUrl/api/users/find/$userId'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } print('Single USer 1'); Map plansJson = data['data']; // 'data' is a Map, not a List print('Single USer 2'); return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> getForexDetailsFind( BuildContext context, int userId, ) async { print('Single Forez 1 - $userId'); // final String apiUrldata = '$apiUrl/api/users/find/$userId'; final String apiUrldata = '$apiUrl/api/findForexPerdiem?forex_perdiem_id=$userId'; 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 { final data = json.decode(response.body); print("forexDat - $data"); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List forexList = data['data']; if (forexList.isEmpty) { throw Exception('No forex data found.'); } return forexList.first as Map; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } // --- Future> getDepartmentDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/findDepartment?id=$id'; 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 { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); // print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List> listData = List>.from(data['data']); if (listData.isEmpty) { throw Exception("No department found with ID $id"); } return listData[0]; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load department details'); } } Future> getPurposeOfTravelDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/findPurposeOfTravel?id=$id'; 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 { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); // print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List> listData = List>.from(data['data']); if (listData.isEmpty) { throw Exception("No department found with ID $id"); } return listData[0]; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load department details'); } } Future> getTemplateFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/template/find/$id'; final token = await getToken(); if (token == null) { throw Exception('Token not found. Please log in.'); } final response = await http.put( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); if (response.statusCode == 200) { try { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); // print(data); // if (!data.containsKey('data') || data['data'] is! List) { // throw Exception( // "Invalid response format: 'data' field is missing or not a List"); // } // // final List> listData = // List>.from(data['data']); // // if (listData.isEmpty) { // throw Exception("No department found with ID $id"); // } // // return listData[0]; if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } return Map.from(data['data']); } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load department details'); } } Future> getForexTemplate() async { final String apiUrldata = '$apiUrl/api/getForexTemplate?template_name=forex'; 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 { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); print(data); // if (!data.containsKey('data') || data['data'] is! List) { // throw Exception( // "Invalid response format: 'data' field is missing or not a List"); // } // // final List> listData = // List>.from(data['data']); // // if (listData.isEmpty) { // throw Exception("No department found with ID $id"); // } // // return listData[0]; if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } return Map.from(data['data']); } catch (e) { throw Exception('Error parsing response: $e'); } } else { throw Exception('Failed to load department details'); } } Future showCancelConfirmationDialog( BuildContext context, Color? layoutColor, ) async { return await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( backgroundColor: Colors.white, title: Text( 'Cancel Confirmation', style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w500, ), ), content: Text( 'Do you want to cancel?', style: GoogleFonts.poppins( fontSize: 14.5, fontWeight: FontWeight.w500, ), ), actions: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: layoutColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: layoutColor ?? Colors.grey, width: 2, ), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () { Navigator.of(context).pop(false); }, child: Text( "Cancel", style: GoogleFonts.poppins(fontSize: 12), ), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: layoutColor, // Keep original color foregroundColor: Colors.white, // Keep original color disabledBackgroundColor: layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: layoutColor ?? Colors.grey, width: 1, ), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () => Navigator.of( context, ).pop(true), // Disable when in view mode child: Text("OK", style: GoogleFonts.poppins(fontSize: 12)), ), ], ); }, ) ?? false; // Default to false if dismissed } Future viewPlanTravelAgent( BuildContext context, String planId, { bool isViewMode = false, bool isMyTrips = false, }) async { try { Map planData = await getViewPlanEdit(planId, context); print("ViewAAA - $planData"); context.go( '/travelagent/trips', extra: {'planData': planData, 'isViewMode': isViewMode}, ); } catch (e) { print("Error fetching plan: $e"); } } Future> getCostCenterDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/findCostCenter?cost_center_id=$id'; 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 { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); // print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List> listData = List>.from(data['data']); if (listData.isEmpty) { throw Exception("No CostCenter found with ID $id"); } return listData[0]; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load CostCenter details'); } } Future> getHotelsDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/findHotels?hotel_id=$id'; 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 { final data = json.decode(response.body); // print('findout the result'); // print(data.runtimeType); // print(data); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List> listData = List>.from(data['data']); if (listData.isEmpty) { throw Exception("No Hotel data found with ID $id"); } return listData[0]; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load Hotel details'); } } Future> getGroupDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/groups/find/$id'; 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 { final data = json.decode(response.body); print(data); if (!data.containsKey('data') || data['data'] is! Map) { throw Exception( "Invalid response format: 'data' field is missing or not a Map", ); } print('Single USer 1'); Map plansJson = data['data']; // 'data' is a Map, not a List print('Single USer 2'); return plansJson; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future> getTravellerDetailsFind( BuildContext context, int id, ) async { final String apiUrldata = '$apiUrl/api/travellers/find?traveller_id=$id'; //c 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 { final data = json.decode(response.body); if (!data.containsKey('data') || data['data'] is! List) { throw Exception( "Invalid response format: 'data' field is missing or not a List", ); } final List> listData = List>.from(data['data']); if (listData.isEmpty) { throw Exception("No Traveller data found with ID $id"); } return listData[0]; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load Hotel details'); } } // ----------------------- User Management - CheckDuplicate --------------- Future> CheckDuplicate( BuildContext context, String label, String field, String value, String? userId, ) async { String apiUrldata; if (userId == null || userId.isEmpty) { apiUrldata = '$apiUrl/api/checkDuplicate?$field=$value'; } else { apiUrldata = '$apiUrl/api/checkDuplicate?$field=$value&user_id=$userId'; } 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 { final data = json.decode(response.body); // Updated to match actual response structure if (data['status'] == "exists") { print("${data['field']} - $value already exists"); return {"message": "$label already exists", "field": data['field']}; } else { print("$label - $value is a new value"); return {}; } } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception( 'Failed to load checkDuplicate data. Status code: ${response.statusCode}', ); } } // ----------------------- User Management - CheckDuplicate end here ---------------------------------- // ----------------------- Report ------------------------- Future> CallReports( BuildContext context, String apiRoute, String body, ) async { String apiUrldata = '$apiUrl/api/$apiRoute'; final token = await getToken(); if (token == null) { throw Exception('Token not found. Please log in.'); } final response = await http.post( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, body: body, ); if (response.statusCode == 200) { try { final data = json.decode(response.body); return data; } catch (e) { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else { throw Exception( 'Failed to load data. Status code: ${response.statusCode}', ); } } Future> reportExcelDownload( BuildContext context, String apiRoute, String body, String name, ) async { final String apiUrldata = '$apiUrl/api/$apiRoute'; // Sanitize name for filename (optional) final safeName = name.replaceAll( RegExp(r'[^\w\s-]'), '', ); // remove any special chars if needed final excelName = '$safeName.xlsx'; final token = await getToken(); if (token == null) { throw Exception('Token not found. Please log in.'); } final response = await http.post( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, body: body, ); if (response.statusCode == 200) { try { print("report XL Dowloaded"); print(excelName); // 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', excelName) ..click(); // Revoke the download URL to free up resources html.Url.revokeObjectUrl(url); // throw Exception('Sucessfully Downloaded'); return {'status': true, 'message': 'Successfully Downloaded'}; } catch (e) { // throw Exception('Error parsing response: $e'); return {'status': false, 'message': 'Download error: $e'}; } } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return {}; // throw Exception('Failed to load users'); } else if (response.statusCode == 404) { // throw Exception('File not found.'); return {'status': false, 'message': 'File not found (404).'}; } else { // throw Exception('Failed to Download'); return {'status': false, 'message': 'Failed to download. Try again.'}; } } // ----------------------- Report ------------------------- Future> fetchGetHotels(BuildContext context) async { // return []; final orgId = await getOrgId(); final String apiUrlData = '$apiUrl/api/getHotels'; final String? token = await getToken(); print("Fetch Hotels 2KN : $token"); 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) { final data = json.decode(response.body); return data['data']; // Returning raw JSON list } else if (response.statusCode == 403) { print("403-FORB"); await logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load users'); } } }