Compare commits

..

10 Commits

Author SHA1 Message Date
venbaittech
491965dc7f forexsign_bg_colr_chng 2025-10-31 18:36:34 +05:30
venbaittech
85fd7c0b47 address_input_restrict 2025-10-30 16:31:33 +05:30
venbaittech
220e7c4c9e final code 2025-10-29 15:17:44 +05:30
venbaittech
08ac38a64b travel_agent_remarks_access 2025-10-29 12:34:19 +05:30
venbaittech
816d8b1bf1 Passport File Download 2025-10-29 10:20:48 +05:30
venbaittech
a838aaeae0 Broken Access 2025-10-29 09:28:12 +05:30
venbaittech
aaff31e8d4 ui_input_formatters 2025-10-27 17:35:57 +05:30
venbaittech
52878d6810 FORBIDEN REFRESH HANDLING 2025-10-16 09:24:18 +05:30
venbaittech
bd7d538481 UI_PASSPORT_DOC_DOWNLOAD 2025-10-08 15:06:06 +05:30
venbaittech
030d1487a6 API_SECURITY 2025-10-08 11:37:26 +05:30
90 changed files with 4660 additions and 18628 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -204,7 +204,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
Future<List<Plan>> fetchPlans() async {
late String apiUrldata;
apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
apiUrldata = '$apiUrl/api/allPlans?org_id=$orgId';
// if (roleUser == "Org Admin") {
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
@ -231,6 +232,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
// List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -264,6 +270,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
print("Plan Deleted successfully!");
print("Response: ${response.body}");
initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -273,7 +284,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
bool confirmed = await apiService.showCancelConfirmationDialog(
context,
layoutColor,
@ -281,7 +292,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
if (confirmed) {
try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
refresh();
// postPlanData(planData, planId);
@ -321,6 +336,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
approverData = List<Map<String, dynamic>>.from(
data['data']['approver_data'] ?? [],
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print('Failed to load');
label = "Error - Failed to load data";
@ -1071,7 +1091,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
); // Close popup manually
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1095,7 +1115,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
);
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1117,6 +1137,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1137,6 +1158,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
apiService
.getPdfDownload(
context,
plan.planId,
);
},
@ -1162,10 +1184,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),
IconButton(
@ -1389,7 +1411,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
); // Close popup manually
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1414,7 +1436,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
);
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1436,6 +1458,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1454,10 +1477,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
);
apiService
.getPdfDownload(
plan.planId,
);
apiService.getPdfDownload(
context,
plan.planId,
);
},
),
@ -1482,10 +1505,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
@ -22,6 +23,7 @@ class TripInformation extends StatefulWidget {
}
class _TripInformationState extends State<TripInformation> {
final ApiService apiService = ApiService();
late Future<Map<String, dynamic>> _tripInfoFuture;
Future<Map<String, dynamic>> fetchComments() async {
@ -48,6 +50,11 @@ class _TripInformationState extends State<TripInformation> {
final Map<String, dynamic> dataMap =
jsonData['data'] as Map<String, dynamic>;
return dataMap;
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load comments');
}
@ -136,14 +143,17 @@ class _TripInformationState extends State<TripInformation> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
keyValueRow("Action", item["action"]),
keyValueRow("Approver", item["approver"]),
keyValueRow("Action", item["action"] ?? '-'),
keyValueRow("Approver", item["approver"] ?? '-'),
keyValueRow(
"Is Action Done",
item["is_action_done"],
item["is_action_done"] ?? '-',
),
keyValueRow("Action On", item["action_on"] ?? '-'),
keyValueRow(
"Email Status",
item["email_status"] ?? '-',
),
keyValueRow("Action On", item["action_on"]),
keyValueRow("Email Status", item["email_status"]),
],
),
),

View File

@ -5,6 +5,7 @@ import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import '../../config/apiUrl.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
class CommentModalList extends StatefulWidget {
@ -24,6 +25,7 @@ class CommentModalList extends StatefulWidget {
}
class _CommentModalListState extends State<CommentModalList> {
final ApiService apiService = ApiService();
late Future<List<Map<String, dynamic>>> _commentsFuture;
// Future<List<Map<String, dynamic>>> fetchComments1() async {
@ -68,6 +70,11 @@ class _CommentModalListState extends State<CommentModalList> {
final jsonData = json.decode(response.body);
final List<dynamic> dataList = jsonData['data'];
return dataList.cast<Map<String, dynamic>>();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load comments');
}

View File

@ -1,5 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'dart:html' as html;
import 'package:frontend/Screens/allTrips/plan_info_mdl.dart';
import 'package:frontend/data/models/plan.dart';
import 'package:frontend/utils/travelAgent_remarks.dart';
@ -29,6 +31,7 @@ class TravelAgentListPlans extends StatefulWidget {
class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
final ApiService apiService = ApiService();
late StreamSubscription<html.PopStateEvent> _popStateListener;
int currentPage = 0;
int itemsPerPage = 10;
@ -39,6 +42,8 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
String? token;
String? TripPlanAction;
late bool _dialogShown = false;
Color? layoutColor;
Color? bodyColor;
late Future<List<Plan>> futurePlans;
@ -50,6 +55,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
void initState() {
super.initState();
_checkAuthAndLoadData();
checkbackbutton();
// getToken();
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
@ -82,6 +88,81 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
loadInitialData();
}
void checkbackbutton() async {
roleUser = await getRoleUser();
print(roleUser);
if (roleUser == "Travel Agent") {
print("user");
final prefs = await SharedPreferences.getInstance();
final String? msUserStr = prefs.getString('is_microsoft_user');
final bool msUser = msUserStr?.toLowerCase() == 'true';
print("msUser - $msUser");
html.window.history.pushState(null, '', html.window.location.href);
if (!msUser) {
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
}
// Re-push to prevent leaving
html.window.history.pushState(null, '', html.window.location.href);
});
}
}
}
@override
void dispose() {
_popStateListener.cancel(); // Remove the browser popstate listener
super.dispose();
}
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0");
await apiService.logout(context);
// // Example: clear session or shared preferences
// final prefs = await SharedPreferences.getInstance();
// await prefs.clear();
// context.go("/");
print("logue 1");
}
void _showBackConfirmationDialog() {
if (!mounted) return;
_dialogShown = true;
showDialog(
context: context,
builder:
(context) => AlertDialog(
title: Text("Confirm"),
content: Text("Do you want to logout?"),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context); // Close dialog
_dialogShown = false;
},
child: Text("Cancel"),
),
TextButton(
onPressed: () async {
// Navigator.pop(context); // Close dialog
_dialogShown = false;
await _logoutAndRedirect(context);
},
child: Text("Logout"),
),
],
),
);
}
void filterPlans(String query) {
print("allPlans before filtering: $allPlans");
final lowerQuery = query.toLowerCase();
@ -221,6 +302,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
// List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -254,6 +340,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
print("Plan Deleted successfully!");
print("Response: ${response.body}");
initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -271,7 +362,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
if (confirmed) {
try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
refresh();
// postPlanData(planData, planId);
@ -839,12 +934,13 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
Navigator.pop(
context,
); // Close popup manually
ApiService.viewPlanTravelAgent(
context,
plan.planId,
isViewMode:
true,
);
ApiService()
.viewPlanTravelAgent(
context,
plan.planId,
isViewMode:
true,
);
},
),
// IconButton(
@ -888,6 +984,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
);
apiService
.getPdfDownload(
context,
plan.planId,
);
},
@ -915,6 +1012,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
);
apiService
.getForexPdfDownload(
context,
plan.forexId,
);
},

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Future<dynamic> showApprovalDialog(
BuildContext context,
@ -115,6 +116,11 @@ Future<dynamic> showApprovalDialog(
TextField(
style: TextStyle(fontFamily: "Inter", fontSize: 14),
maxLines: 3,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
onChanged: (value) => remarks = value,
decoration: InputDecoration(
hintText: "Remarks...",
@ -263,8 +269,14 @@ Future<String?> showRejectDialog1(
const Text("Please enter reason for rejection."),
const SizedBox(height: 10),
TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
maxLines: 3,
onChanged: (value) => remarks = value,
decoration: const InputDecoration(
hintText: "Remarks...",
hintStyle: TextStyle(

View File

@ -204,6 +204,11 @@ class _ApprovalListState extends State<ApprovalList> {
List<dynamic> plansJson = data['data'];
print('plansJson $plansJson');
return plansJson.map((json) => Plan.fromJson(json)).toList();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -237,6 +242,11 @@ class _ApprovalListState extends State<ApprovalList> {
print("Plan Deleted successfully!");
print("Response: ${response.body}");
initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -246,7 +256,7 @@ class _ApprovalListState extends State<ApprovalList> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
// try {
// Map<String, dynamic> planData = await getViewPlan(planId);
// print("ViewAAA - $planData");
@ -263,7 +273,11 @@ class _ApprovalListState extends State<ApprovalList> {
if (confirmed) {
try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
refresh();
// postPlanData(planData, planId);
@ -297,6 +311,11 @@ class _ApprovalListState extends State<ApprovalList> {
final Map<String, dynamic>? resData = json.decode(response.body);
return resData?["data"];
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -402,6 +421,11 @@ class _ApprovalListState extends State<ApprovalList> {
approverData = List<Map<String, dynamic>>.from(
data['data']['approver_data'] ?? [],
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print('Failed to load');
label = "Error - Failed to load data";
@ -1157,7 +1181,7 @@ class _ApprovalListState extends State<ApprovalList> {
Navigator.pop(
context,
);
ApiService.viewPlanForApprover(
ApiService().viewPlanForApprover(
context,
plan.planId,
plan.approverId,
@ -1184,6 +1208,7 @@ class _ApprovalListState extends State<ApprovalList> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1204,6 +1229,7 @@ class _ApprovalListState extends State<ApprovalList> {
);
apiService
.getPdfDownload(
context,
plan.planId,
);
},
@ -1229,10 +1255,10 @@ class _ApprovalListState extends State<ApprovalList> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),
@ -1511,10 +1537,10 @@ class _ApprovalListState extends State<ApprovalList> {
Navigator.pop(
context,
);
apiService
.getPdfDownload(
plan.planId,
);
apiService.getPdfDownload(
context,
plan.planId,
);
},
),
if (plan.statusValue ==
@ -1538,10 +1564,10 @@ class _ApprovalListState extends State<ApprovalList> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),
IconButton(

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
import 'dart:convert';
import 'dart:html' as html;
// import 'dart:ui' as html;
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:frontend/config/apiUrl.dart';
import 'package:google_fonts/google_fonts.dart';
@ -103,12 +105,24 @@ class _LoginWidgetState extends State<LoginWidget> {
print("userData12 - $userRole");
}
await apiService.getOrganizationData();
await apiService.getOrganizationData(context);
} catch (e) {
print('Error decoding token: $e');
}
}
String encryptLoginPayload(Map<String, String> credentials) {
final key = encrypt.Key.fromUtf8('1234567890123456'); // 16 chars key
final iv = encrypt.IV.fromUtf8('abcdefghijklmnop'); // 16 chars IV
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc),
);
final jsonString = jsonEncode(credentials);
final encrypted = encrypter.encrypt(jsonString, iv: iv);
return encrypted.base64;
}
Future<void> _login(BuildContext context) async {
if (_formKey.currentState!.validate()) {
setState(() {
@ -117,6 +131,11 @@ class _LoginWidgetState extends State<LoginWidget> {
const String url = '$apiUrl/api/auth/login';
final encryptedData = encryptLoginPayload({
'email': _emailController.text.trim(),
'password': _passwordController.text.trim(),
});
try {
final response = await http.post(
Uri.parse(url),
@ -125,10 +144,11 @@ class _LoginWidgetState extends State<LoginWidget> {
'Accept': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
},
body: jsonEncode({
'email': _emailController.text.trim(),
'password': _passwordController.text.trim(),
}),
body: jsonEncode({'encrypted': true, 'payload': encryptedData}),
// body: jsonEncode({
// 'email': _emailController.text.trim(),
// 'password': _passwordController.text.trim(),
// }),
);
if (response.statusCode == 200) {
@ -138,6 +158,9 @@ class _LoginWidgetState extends State<LoginWidget> {
final token = data['token']; // Assuming the token is in response
// final userId = data['user_id'].toString();
final prefs = await SharedPreferences.getInstance();
prefs.clear();
print("CLEARINGGG-- ");
print("Token - $token");
await storeUserDetails(token);
@ -145,7 +168,7 @@ class _LoginWidgetState extends State<LoginWidget> {
msg: "You're in!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
timeInSecForIosWeb: 3,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 18.0,
@ -159,6 +182,11 @@ class _LoginWidgetState extends State<LoginWidget> {
} else {
context.go('/listPlan');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
final body = jsonDecode(response.body);
final messages = body['messages'];
@ -173,7 +201,7 @@ class _LoginWidgetState extends State<LoginWidget> {
msg: "Login Failed: $errorMessage",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
timeInSecForIosWeb: 6,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0,
@ -200,8 +228,8 @@ class _LoginWidgetState extends State<LoginWidget> {
msg: "Login Failed: $e",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: Colors.red,
timeInSecForIosWeb: 5,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0,
webBgColor: "linear-gradient(to right, #dc1c13, #dc1c13)",
@ -250,6 +278,11 @@ class _LoginWidgetState extends State<LoginWidget> {
fontSize: 16.0,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print(response);
@ -318,6 +351,11 @@ class _LoginWidgetState extends State<LoginWidget> {
fontSize: 16.0,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print('23');
print('otp wrong');
@ -368,8 +406,10 @@ class _LoginWidgetState extends State<LoginWidget> {
}
}
void _clearAllFields() {
Future<void> _clearAllFields() async {
print("CLEAR ALL Fields");
final prefs = await SharedPreferences.getInstance();
prefs.clear();
_emailController.clear();
_passwordController.clear();
@ -543,6 +583,7 @@ class _LoginWidgetState extends State<LoginWidget> {
_buildLabel("Email Address"),
TextFormField(
controller: _emailController,
inputFormatters: [],
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 11,
@ -1166,6 +1207,11 @@ class _LoginWidgetState extends State<LoginWidget> {
print('auth URL not Founded');
throw Exception('auth URL not Founded');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
final errorMessage = json.decode(response.body)['message'];
print(errorMessage);

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -247,6 +248,12 @@ class CostCenterDataState extends State<CostCenterData> {
});
break;
case 403:
print("403-FORB");
await apiService.logout(context);
break;
// throw Exception('Failed to load users');
default:
print("Failed to submit costcenter. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -308,6 +315,11 @@ class CostCenterDataState extends State<CostCenterData> {
child: TextField(
controller: controllers["name"],
focusNode: focusNodes["nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Name",
@ -350,6 +362,11 @@ class CostCenterDataState extends State<CostCenterData> {
child: TextField(
controller: controllers["description"],
focusNode: focusNodes["descriptionFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
maxLines: null,
expands: true,

View File

@ -78,16 +78,21 @@ class CostCenterListState extends State<CostCenterList> {
if (!mounted) return;
try {
futureCostCenter = fetchGetCostCenter();
futureCostCenter?.then((object) {
setState(() {
allCostCenter = object;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureCostCenter?.then((object) {
setState(() {
allCostCenter = object;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -157,6 +162,11 @@ class CostCenterListState extends State<CostCenterList> {
final data = json.decode(response.body);
print(data['data']);
return data['data']; // Returning raw JSON list
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -658,6 +668,7 @@ class CostCenterListState extends State<CostCenterList> {
);
final data = await apiService
.getCostCenterDetailsFind(
context,
costcenterId,
);
print("CostCenterId -- $data");
@ -751,6 +762,7 @@ class CostCenterListState extends State<CostCenterList> {
);
final data = await apiService
.getCostCenterDetailsFind(
context,
costcenterId,
);
print("CostCenterId -- $data");

View File

@ -40,6 +40,7 @@ class StatusDashboardState extends State<StatusDashboard> {
List<int> flightData = [];
List<int> accommodationData = [];
List<int> forexData = [];
final ApiService apiService = ApiService();
final categoryIcons = {
"flight": Icons.flight,
@ -96,8 +97,10 @@ class StatusDashboardState extends State<StatusDashboard> {
_dialogShown = true;
final parentContext = context; // <-- save parent context
showDialog(
context: context,
context: parentContext,
builder:
(context) => AlertDialog(
title: Text("Confirm"),
@ -105,16 +108,20 @@ class StatusDashboardState extends State<StatusDashboard> {
actions: [
TextButton(
onPressed: () {
Navigator.pop(context); // Close dialog
Navigator.pop(parentContext); // Close dialog
_dialogShown = false;
},
child: Text("Cancel"),
),
TextButton(
onPressed: () async {
Navigator.pop(context); // Close dialog
// Navigator.pop(parentContext); // Close dialog
_dialogShown = false;
await _logoutAndRedirect(context);
print("logue 1s");
// Use parentContext for navigation, not dialog context
if (!mounted) return;
await _logoutAndRedirect(parentContext);
print("logue 2s");
},
child: Text("Logout"),
),
@ -123,14 +130,52 @@ class StatusDashboardState extends State<StatusDashboard> {
);
}
// void _showBackConfirmationDialog() {
// if (!mounted) return;
//
// _dialogShown = true;
//
// showDialog(
// context: context,
// builder:
// (context) => AlertDialog(
// title: Text("Confirm"),
// content: Text("Do you want to logout?"),
// actions: [
// TextButton(
// onPressed: () {
// Navigator.pop(context); // Close dialog
// _dialogShown = false;
// },
// child: Text("Cancel"),
// ),
// TextButton(
// onPressed: () async {
// Navigator.pop(context); // Close dialog
// _dialogShown = false;
//
// // Use the parent widget's context
// if (!mounted) return;
// await _logoutAndRedirect(context);
// },
// child: Text("Logout"),
// ),
// ],
// ),
// );
// }
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue _logoutAndRedirect");
// Navigator.pop(context); // closes dialog
_dialogShown = false;
print("logue 0");
await apiService.logout(context);
// Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
// final prefs = await SharedPreferences.getInstance();
// await prefs.clear();
context.go("/");
// context.go("/");
print("logue 1");
}
@ -214,6 +259,11 @@ class StatusDashboardState extends State<StatusDashboard> {
final apiData = json.decode(response.body);
print("Fetch StatusDashboard -- Reponse Here : $apiData");
return apiData; // Returning raw JSON list
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}

View File

@ -41,6 +41,7 @@ class StatusDashboardState extends State<StatusDashboard> {
List<int> flightData = [];
List<int> accommodationData = [];
List<int> forexData = [];
final ApiService apiService = ApiService();
final categoryIcons = {
"flight": Icons.flight,
@ -53,14 +54,14 @@ class StatusDashboardState extends State<StatusDashboard> {
"Partially Approved",
"Approved",
"Rejected",
"Cancelled"
"Cancelled",
];
// Extract counts for "Both" section
List<int> getStatusValues(Map<String, dynamic> serviceData) {
final both = serviceData['Both'] ?? {};
return statusLabels.map((label) => (both[label] ?? 0) as int).toList();
}
// Extract counts for "Both" section
List<int> getStatusValues(Map<String, dynamic> serviceData) {
final both = serviceData['Both'] ?? {};
return statusLabels.map((label) => (both[label] ?? 0) as int).toList();
}
@override
void initState() {
@ -113,7 +114,7 @@ class StatusDashboardState extends State<StatusDashboard> {
),
TextButton(
onPressed: () async {
Navigator.pop(context); // Close dialog
// Navigator.pop(context); // Close dialog
_dialogShown = false;
await _logoutAndRedirect(context);
},
@ -126,12 +127,14 @@ class StatusDashboardState extends State<StatusDashboard> {
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0");
Navigator.pop(context); // closes dialog
_dialogShown = false;
await apiService.logout(context);
// Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
// final prefs = await SharedPreferences.getInstance();
// await prefs.clear();
context.go("/");
// context.go("/");
print("logue 1");
}
@ -210,6 +213,10 @@ class StatusDashboardState extends State<StatusDashboard> {
final apiData = json.decode(response.body);
print("Fetch StatusDashboard -- Reponse Here : $apiData");
return apiData; // Returning raw JSON list
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
} else {
throw Exception('Failed to load users');
}
@ -316,25 +323,27 @@ class StatusDashboardState extends State<StatusDashboard> {
setState(() {
// currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount;
typeData = selectedView == "Today"
? typeBasedTodayCount
: typeBasedWeeklyCount ;
statusData = selectedView == "Today"
? statusBasedTodayCount
: statusBasedWeeklyCount ;
typeData =
selectedView == "Today" ? typeBasedTodayCount : typeBasedWeeklyCount;
statusData =
selectedView == "Today"
? statusBasedTodayCount
: statusBasedWeeklyCount;
flightData = selectedView == "Today"
? getStatusValues(todayBasedCount['flight'] ?? {})
: getStatusValues(weekBasedCount['flight'] ?? {});
accommodationData = selectedView == "Today"
? getStatusValues(todayBasedCount['acomodation'] ?? {})
: getStatusValues(weekBasedCount['acomodation'] ?? {});
forexData = selectedView == "Today"
? getStatusValues(todayBasedCount['forex'] ?? {})
: getStatusValues(weekBasedCount['forex'] ?? {});
flightData =
selectedView == "Today"
? getStatusValues(todayBasedCount['flight'] ?? {})
: getStatusValues(weekBasedCount['flight'] ?? {});
accommodationData =
selectedView == "Today"
? getStatusValues(todayBasedCount['acomodation'] ?? {})
: getStatusValues(weekBasedCount['acomodation'] ?? {});
forexData =
selectedView == "Today"
? getStatusValues(todayBasedCount['forex'] ?? {})
: getStatusValues(weekBasedCount['forex'] ?? {});
});
print("statusBasedCount - => $statusBasedCount");
print("Current Data - => $currentData");
// 👇 Local function to create the card widget
@ -399,6 +408,7 @@ class StatusDashboardState extends State<StatusDashboard> {
print("dashboard ..");
}
}
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
Widget toggleChip(String label) {
@ -446,7 +456,7 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column(
children: [
Tooltip(
message: label ,
message: label,
child: Image.asset(
label == 'Domestic'
? 'assets/images/IconsImg/Domestic_new.png'
@ -520,8 +530,12 @@ class StatusDashboardState extends State<StatusDashboard> {
);
}
Widget buildCategoryCard(String title, IconData icon, List<String> statusLabels,List<int> values) {
Widget buildCategoryCard(
String title,
IconData icon,
List<String> statusLabels,
List<int> values,
) {
final statusIcons = [
Icons.calendar_today,
Icons.assignment,
@ -532,9 +546,9 @@ class StatusDashboardState extends State<StatusDashboard> {
final statusColors = [
Color(0xFFFBFFCA),
Color(0xFFFFF1CD),// Colors.yellow.shade100, // Color(0xFFCAE77B),
Color(0xFFDAFFE8),// Colors.green.shade100, // Color(0xFF72D480),
Color(0xFFFFD6D3),// Colors.red.shade100, // Color(0xFFF88C8C),
Color(0xFFFFF1CD), // Colors.yellow.shade100, // Color(0xFFCAE77B),
Color(0xFFDAFFE8), // Colors.green.shade100, // Color(0xFF72D480),
Color(0xFFFFD6D3), // Colors.red.shade100, // Color(0xFFF88C8C),
Color(0xFFFFA8A8), // Colors.red.shade200, // Color(0xFFE94B4B),
];
@ -575,17 +589,16 @@ class StatusDashboardState extends State<StatusDashboard> {
color: Color(0xFF004A8E),
shape: BoxShape.circle,
),
child: Icon(
icon,
color: Colors.white,
size: 20,
),
child: Icon(icon, color: Colors.white, size: 20),
),
const SizedBox(width: 10),
Text(title, style: GoogleFonts.poppins(
Text(
title,
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.bold
),),
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
@ -603,7 +616,9 @@ class StatusDashboardState extends State<StatusDashboard> {
height: 28,
decoration: BoxDecoration(
color: statusColors[index], // background color
borderRadius: BorderRadius.circular(4), // square with slight rounding
borderRadius: BorderRadius.circular(
4,
), // square with slight rounding
),
alignment: Alignment.center,
child: Icon(
@ -613,16 +628,20 @@ class StatusDashboardState extends State<StatusDashboard> {
),
),
const SizedBox(width: 6),
Text(statusLabels[index], style: GoogleFonts.poppins(
color: Colors.black87,
),),
Text(
statusLabels[index],
style: GoogleFonts.poppins(color: Colors.black87),
),
],
),
Text(values[index].toString(), style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.bold,
),),
Text(
values[index].toString(),
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
);
@ -789,31 +808,33 @@ class StatusDashboardState extends State<StatusDashboard> {
],
),
padding: const EdgeInsets.all(15),
child: Row(
children: [
...typeData.map((item) {
return Expanded(
child: Column(
children: [
buildTopCard(
// icon: item['value'] == "Domestic"
// ? Icons.home
// : Icons.travel_explore,
color: item['value'] == "Domestic"
? Color(0xFF0DB04B)
: Color(0xFF004A8E),
label: item['value'],
count: item['count'],
bgColor: item['value'] == "Domestic"
? const Color(0xFFD6FBE4)
: const Color(0xFFD9E8FF),
),
],
),
);
}).toList(),
],
),
child: Row(
children: [
...typeData.map((item) {
return Expanded(
child: Column(
children: [
buildTopCard(
// icon: item['value'] == "Domestic"
// ? Icons.home
// : Icons.travel_explore,
color:
item['value'] == "Domestic"
? Color(0xFF0DB04B)
: Color(0xFF004A8E),
label: item['value'],
count: item['count'],
bgColor:
item['value'] == "Domestic"
? const Color(0xFFD6FBE4)
: const Color(0xFFD9E8FF),
),
],
),
);
}).toList(),
],
),
),
),
const SizedBox(width: 20),
@ -836,18 +857,27 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Status",
style: GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
Text(
"Status",
style: GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 23),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
...statusData.map((item) => statusCard(item['value'], item['count'])).toList(),
...statusData
.map(
(item) => statusCard(
item['value'],
item['count'],
),
)
.toList(),
],
),
],
@ -862,11 +892,32 @@ class StatusDashboardState extends State<StatusDashboard> {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: buildCategoryCard("Flight", Icons.flight,statusLabels,flightData)),
Expanded(
child: buildCategoryCard(
"Flight",
Icons.flight,
statusLabels,
flightData,
),
),
const SizedBox(width: 10),
Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined,statusLabels,accommodationData)),
Expanded(
child: buildCategoryCard(
"Accomodation",
Icons.hotel_outlined,
statusLabels,
accommodationData,
),
),
const SizedBox(width: 10),
Expanded(child: buildCategoryCard("Forex", Icons.attach_money,statusLabels,forexData)),
Expanded(
child: buildCategoryCard(
"Forex",
Icons.attach_money,
statusLabels,
forexData,
),
),
],
),
],

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -249,6 +250,11 @@ class DepartmentDataState extends State<DepartmentData> {
behavior: SnackBarBehavior.floating,
),
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -308,6 +314,11 @@ class DepartmentDataState extends State<DepartmentData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["dropdown_value"],
focusNode: focusNodes["dropdown_valueFocusNode"],
style: const TextStyle(fontSize: 12),

View File

@ -78,16 +78,21 @@ class DepartmentListState extends State<DepartmentList> {
if (!mounted) return;
try {
futureDepartment = fetchGetDepartment();
futureDepartment?.then((object) {
setState(() {
allDepartment = object;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureDepartment?.then((object) {
setState(() {
allDepartment = object;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -156,6 +161,11 @@ class DepartmentListState extends State<DepartmentList> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -315,6 +325,7 @@ class DepartmentListState extends State<DepartmentList> {
height: 40,
child: TextField(
controller: searchController,
onChanged: filterDepartment,
decoration: InputDecoration(
hintText: "Search ...",
@ -654,6 +665,7 @@ class DepartmentListState extends State<DepartmentList> {
);
final data = await apiService
.getDepartmentDetailsFind(
context,
departmentId,
);
print("DepartmentId -- $data");
@ -746,6 +758,7 @@ class DepartmentListState extends State<DepartmentList> {
);
final data = await apiService
.getDepartmentDetailsFind(
context,
departmentId,
);
print("DepartmentId -- $data");

View File

@ -8,6 +8,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../config/apiUrl.dart';
import '../../data/models/Searchtraveller.dart';
import '../../data/models/searchUser.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
import '../../widgets/custom_text_traveller.dart';
@ -32,6 +33,7 @@ class UserSelectionDialog extends StatefulWidget {
}
class _UserSelectionDialogState extends State<UserSelectionDialog> {
final ApiService apiService = ApiService();
TextEditingController _controller = TextEditingController();
TextEditingController _searchController = TextEditingController();
// List<String> _filteredUsers = [];
@ -107,6 +109,11 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
"Unexpected response format: Expected a List but got ${responseBody.runtimeType}",
);
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception(
'Failed to load users. Status Code: ${response.statusCode}',
@ -164,6 +171,11 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
"Unexpected response format: Expected a List but got ${responseBody.runtimeType}",
);
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception(
'Failed to load users. Status Code: ${response.statusCode}',
@ -707,6 +719,7 @@ class TravelerForm extends StatefulWidget {
}
class _TravelerFormState extends State<TravelerForm> {
final ApiService apiService = ApiService();
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('auth_token');
@ -819,6 +832,11 @@ class _TravelerFormState extends State<TravelerForm> {
backgroundColor: Colors.green,
),
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
ScaffoldMessenger.of(
context,

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/organization/mailSettings.dart';
import 'package:frontend/Screens/organization/themeColor.dart';
import 'package:frontend/utils/auth_utils.dart';
@ -141,22 +142,27 @@ class _groupState extends State<Group> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllPolicy();
final result = await apiService.fetchAllPolicy(context);
orgId = await getOrgId();
userId = await getUserId();
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
setState(() {
apiAllPolicy = result;
setState(() {
apiAllPolicy = result;
apiForDomestic =
result.where((policy) => policy["domestic"] == "1").toList();
apiForInternational =
result.where((policy) => policy["international"] == "1").toList();
});
print("Fetched services: $apiAllPolicy");
print("Domestic policies: $apiForDomestic");
print("International policies: $apiForInternational");
apiForDomestic =
result.where((policy) => policy["domestic"] == "1").toList();
apiForInternational =
result.where((policy) => policy["international"] == "1").toList();
});
print("Fetched services: $apiAllPolicy");
print("Domestic policies: $apiForDomestic");
print("International policies: $apiForInternational");
} else {
apiService.logout(context);
}
} catch (e) {
print('Error fetching role list: $e');
}
@ -263,10 +269,16 @@ class _groupState extends State<Group> {
if (response.statusCode == 200 || response.statusCode == 201) {
print("GRPDATA");
await apiService.handleTokenRefresh(userId!);
print("Group submitted successfully!");
print("Response: ${response.body}");
await apiService.handleTokenRefresh(context, userId!);
context.go('/group');
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit group. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -475,6 +487,9 @@ class _groupState extends State<Group> {
height: 40,
child: TextField(
controller: controllers["name"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
onChanged: (value) {
_clearError("name");
@ -521,6 +536,9 @@ class _groupState extends State<Group> {
height: 40,
child: TextField(
controller: controllers["description"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
_clearError("description");
},

View File

@ -177,18 +177,23 @@ class GroupDataState extends State<GroupData> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllPolicy();
final result = await apiService.fetchAllPolicy(context);
userId = await getUserId();
setState(() {
apiForDomestic =
result.where((policy) => policy["domestic"] == "1").toList();
apiForInternational =
result.where((policy) => policy["international"] == "1").toList();
});
print("Domestic policies: $apiForDomestic");
print("International policies: $apiForInternational");
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
setState(() {
apiForDomestic =
result.where((policy) => policy["domestic"] == "1").toList();
apiForInternational =
result.where((policy) => policy["international"] == "1").toList();
});
print("Domestic policies: $apiForDomestic");
print("International policies: $apiForInternational");
} else {
apiService.logout(context);
}
} catch (e) {
print('Error fetching role list: $e');
}
@ -284,9 +289,9 @@ class GroupDataState extends State<GroupData> {
print("Response: ${response.body}");
// _clearError();
_clearError();
await apiService.handleTokenRefresh(context, userId!);
await widget.fetchGetGroup();
await apiService.handleTokenRefresh(userId!);
if (context.mounted) {
Navigator.of(context).pop(); // Close modal only if mounted
}
@ -311,6 +316,11 @@ class GroupDataState extends State<GroupData> {
behavior: SnackBarBehavior.floating,
),
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -421,7 +431,11 @@ class GroupDataState extends State<GroupData> {
height: 40,
child: TextField(
focusNode: focusNodes["nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["name"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -774,7 +788,11 @@ class GroupDataState extends State<GroupData> {
child: TextField(
controller: controllers["description"],
focusNode: focusNodes["descriptionFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
maxLines: null,
expands: true,

View File

@ -118,19 +118,25 @@ class _GroupListState extends State<GroupList> {
Future<List<dynamic>> fetchGroups() async {
// return [];
final result = await apiService.fetchAllGroup();
final result = await apiService.fetchAllGroup(context);
return result; // Returning raw JSON list
}
Future<void> loadAllGroups() async {
try {
final result = await apiService.fetchAllGroup();
setState(() {
allGroups = result;
filteredGroups = result;
searchController.text = "";
});
print("Fetched services: $allGroups");
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
final result = await apiService.fetchAllGroup(context);
setState(() {
allGroups = result;
filteredGroups = result;
searchController.text = "";
});
print("Fetched services: $allGroups");
} else {
apiService.logout(context);
}
} catch (e) {
print('Error fetching role list: $e');
}
@ -200,6 +206,11 @@ class _GroupListState extends State<GroupList> {
if (response.statusCode == 200 || response.statusCode == 201) {
print("Group status updated successfully to $newStatus!");
loadAllGroups(); // Refresh groups list after update
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to update group status. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -713,6 +724,7 @@ class _GroupListState extends State<GroupList> {
if (newGroupID != null) {
final data = await apiService
.getGroupDetailsFind(
context,
newGroupID,
); // Always an int
showDialog(
@ -850,6 +862,7 @@ class _GroupListState extends State<GroupList> {
if (newGroupID != null) {
final data = await apiService
.getGroupDetailsFind(
context,
newGroupID,
); // Always an int
showDialog(

View File

@ -55,7 +55,7 @@ class _GroupListBackUpState extends State<GroupListBackUp> {
Future<void> loadAllGroups() async {
try {
final result = await apiService.fetchAllGroup();
final result = await apiService.fetchAllGroup(context);
setState(() {
apiAllGroups = result;
});
@ -410,6 +410,7 @@ class _GroupListBackUpState extends State<GroupListBackUp> {
);
if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind(
context,
newGroupID,
); // Always an int
showDialog(

View File

@ -151,7 +151,7 @@ class HotelsDataState extends State<HotelsData> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -269,6 +269,11 @@ class HotelsDataState extends State<HotelsData> {
isDisable = false;
});
// Do NOT re-enable here if success
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 404) {
if (context.mounted) {
Navigator.of(context).pop();
@ -367,6 +372,11 @@ class HotelsDataState extends State<HotelsData> {
height: 40,
child: TextField(
focusNode: focusNodes["hotel_nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["hotel_name"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -410,6 +420,11 @@ class HotelsDataState extends State<HotelsData> {
child: TextField(
focusNode: focusNodes["hotel_chainFocusNode"],
controller: controllers["hotel_chain"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Hotel Chain",
@ -453,9 +468,10 @@ class HotelsDataState extends State<HotelsData> {
child: TextField(
focusNode: focusNodes["categoryFocusNode"],
controller: controllers["category"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 ]'),
RegExp(r'[a-z A-Z0-9 ]'),
),
],
style: const TextStyle(fontSize: 12),
@ -660,6 +676,11 @@ class HotelsDataState extends State<HotelsData> {
height: 40,
child: TextField(
focusNode: focusNodes["cityFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["city"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -81,17 +82,22 @@ class HotelsDataListState extends State<HotelsDataList> {
if (!mounted) return;
try {
futureHotels = fetchGetHotels();
futureHotels?.then((objects) {
setState(() {
allHotels = objects;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureHotels?.then((objects) {
setState(() {
allHotels = objects;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCountryList();
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCountryList();
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -159,6 +165,11 @@ class HotelsDataListState extends State<HotelsDataList> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -209,6 +220,11 @@ class HotelsDataListState extends State<HotelsDataList> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -369,6 +385,11 @@ class HotelsDataListState extends State<HotelsDataList> {
height: 40,
child: TextField(
controller: searchController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
onChanged: filterHotels,
decoration: InputDecoration(
hintText: "Search ...",
@ -755,7 +776,10 @@ class HotelsDataListState extends State<HotelsDataList> {
if (hotelsId != null) {
print("HotelsId -- $hotelsId");
final data = await apiService
.getHotelsDetailsFind(hotelsId);
.getHotelsDetailsFind(
context,
hotelsId,
);
print("HotelsId -- $data");
showDialog(
@ -841,7 +865,10 @@ class HotelsDataListState extends State<HotelsDataList> {
if (hotelsId != null) {
print("HotelsId -- $hotelsId");
final data = await apiService
.getHotelsDetailsFind(hotelsId);
.getHotelsDetailsFind(
context,
hotelsId,
);
print("HotelsId -- $data");
showDialog(

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -182,7 +183,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
// }
WidgetsBinding.instance.addPostFrameCallback((_) {
loadCountryList();
loadCountryList(context);
final result = getFlightTripDateRange(widget.flightData);
@ -288,7 +289,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
// : Colors.redAccent;
// });
futureHotels = await apiService.fetchGetHotels();
futureHotels = await apiService.fetchGetHotels(context);
print("futureHotels - $futureHotels");
@ -489,8 +490,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
return errorMessages.isEmpty; // Valid if there are no errors
}
Future<void> loadCountryList() async {
final result = await apiService.fetchFlightsCountryList(widget.tripType);
Future<void> loadCountryList(BuildContext context) async {
final result = await apiService.fetchFlightsCountryList(
context,
widget.tripType,
);
print("ResultCountry : $result");
@ -661,6 +665,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
focusNode: _destinationFocusNode,
controller: _destinationController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Destination",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1500,6 +1507,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _commentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -466,6 +467,9 @@ class _BusScreenState extends State<BusScreen> {
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "From",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -503,6 +507,9 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _toFocusNode,
controller: _toController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "To",
@ -548,6 +555,7 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _dateFocusNode,
controller: _dateController,
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -656,6 +664,9 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _buscommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
@ -191,7 +192,7 @@ class FlightScreenState extends State<FlightScreen> {
if (tripTypeValue != null && tripTypeValue.isNotEmpty) {
print("🚀 Initial loadCountryList for tripType: $tripTypeValue");
loadCountryList(tripTypeValue);
loadCountryList(context, tripTypeValue);
} else {
print("⚠️ tripType is null or empty, skipping loadCountryList");
}
@ -253,14 +254,17 @@ class FlightScreenState extends State<FlightScreen> {
// isCountryLoading = false;
// });
// }
Future<void> loadCountryList(newTripType) async {
Future<void> loadCountryList(BuildContext context, newTripType) async {
print("🔄 loadCountryList called with tripType: ${newTripType}");
setState(() {
isCountryLoading = true;
});
final result = await apiService.fetchFlightsCountryList(newTripType);
final result = await apiService.fetchFlightsCountryList(
context,
newTripType,
);
print("ResultCountry : $result");
@ -2517,6 +2521,9 @@ class FlightScreenState extends State<FlightScreen> {
focusNode: focusNodes["_comments1FocusNode"],
// controller: _commentsController,
controller: textControllers["_comments1Controller"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
// maxLines: 6,
// keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),

View File

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -39,6 +40,7 @@ class ForexScreen extends StatefulWidget {
}
class _ForexScreenState extends State<ForexScreen> {
final ApiService apiService = ApiService();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late ValueNotifier<String?> flightFirstTripDateNotifier;
@ -245,6 +247,11 @@ class _ForexScreenState extends State<ForexScreen> {
} else {
print("Warning: Response does not contain expected fields.");
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -1140,6 +1147,11 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_forexStartDate"],
controller: textControllers["_forexStartDate"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
@ -1227,6 +1239,11 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_forexEndDate"],
controller: textControllers["_forexEndDate"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -1671,6 +1688,7 @@ class _ForexScreenState extends State<ForexScreen> {
height: 30,
child: TextField(
focusNode: focusNodes["_transport"],
controller: textControllers["_transport"],
onChanged: (value) {
setState(() {
@ -2225,6 +2243,9 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_comments"],
controller: textControllers["_comments"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",
@ -2333,6 +2354,11 @@ class _ForexScreenState extends State<ForexScreen> {
onChanged: (value) {
errorMessages.remove("delivery_location");
},
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Location",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -1180,7 +1181,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
height: 40,
child: TextField(
focusNode: focusNodes["nominee_nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
// focusNode: _nomineeFocusNode,
controller: _nomineeController,
style: TextStyle(fontSize: 12),
@ -1290,6 +1293,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
focusNode: focusNodes["nominee_relationshipFocusNode"],
controller: _nomineerelationController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Nominee Relationship",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1340,6 +1346,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
// focusNode: _commentsFocusNode,
focusNode: focusNodes["commentsFocusNode"],
controller: _insuranceCommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -125,9 +126,9 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
});
}
@ -309,106 +310,114 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: _hotelNameFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_hotelNameFocused = hasFocus;
});
child: Focus(
focusNode: _hotelNameFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_hotelNameFocused = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_hotelNameFocusNode?.requestFocus();
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_hotelNameFocusNode?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
// focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedSpecialType,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
child: DropdownSearch<Map<String, dynamic>>(
// focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedSpecialType,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4),
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
child: Text(
item['dropdown_value'] ?? '',
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4),
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
);
},
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedSpecialType = newValue as String?;
});
print("Updating form data: -> ${newValue ?? ""}");
}
: null,
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
);
},
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedSpecialType = newValue as String?;
});
print("Updating form data: -> ${newValue ?? ""}");
}
: null,
),),)
),
),
),
if (errorMessages["special_request"] != null) ...[
@ -439,10 +448,13 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: _commentsFocusNode,
controller: _commentsController,
style: TextStyle(fontSize: 12),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -11,8 +12,12 @@ class ForexScreen extends StatefulWidget {
final Function(String tab, String key, String value) updateFormData;
final Function(bool) onClose;
ForexScreen({required this.formData, required this.updateFormData,
required this.onClose, this.apiData});
ForexScreen({
required this.formData,
required this.updateFormData,
required this.onClose,
this.apiData,
});
@override
_ForexScreenState createState() => _ForexScreenState();
@ -95,57 +100,55 @@ class _ForexScreenState extends State<ForexScreen> {
});
});
_tripTypeController =
TextEditingController(text: widget.formData["tripType"] ?? "");
_hotelNameController =
TextEditingController(text: widget.formData["_hotelName"] ?? "");
_fromController =
TextEditingController(text: widget.formData["_from"] ?? "");
_toController =
TextEditingController(text: widget.formData["_Check_In_Time"] ?? "");
_dateController =
TextEditingController(text: widget.formData["_Check_Out"] ?? "");
_endDateController =
TextEditingController(text: widget.formData["_Check_In"] ?? "");
_timeController =
TextEditingController(text: widget.formData["_Check_Out_Time"] ?? "");
_commentsController =
TextEditingController(text: widget.formData["_comments"] ?? "");
_tripTypeController = TextEditingController(
text: widget.formData["tripType"] ?? "",
);
_hotelNameController = TextEditingController(
text: widget.formData["_hotelName"] ?? "",
);
_fromController = TextEditingController(
text: widget.formData["_from"] ?? "",
);
_toController = TextEditingController(
text: widget.formData["_Check_In_Time"] ?? "",
);
_dateController = TextEditingController(
text: widget.formData["_Check_Out"] ?? "",
);
_endDateController = TextEditingController(
text: widget.formData["_Check_In"] ?? "",
);
_timeController = TextEditingController(
text: widget.formData["_Check_Out_Time"] ?? "",
);
_commentsController = TextEditingController(
text: widget.formData["_comments"] ?? "",
);
// Save data when user types
_tripTypeController.addListener(() {
widget.updateFormData(
"Bus", "_tripType", _tripTypeController.text);
widget.updateFormData("Bus", "_tripType", _tripTypeController.text);
}); // Save data when user types
_hotelNameController.addListener(() {
widget.updateFormData(
"Bus", "_hotelName", _hotelNameController.text);
widget.updateFormData("Bus", "_hotelName", _hotelNameController.text);
});
_fromController.addListener(() {
widget.updateFormData(
"Bus", "_from", _fromController.text);
widget.updateFormData("Bus", "_from", _fromController.text);
});
_toController.addListener(() {
widget.updateFormData(
"Bus", "_Check_In_Time", _toController.text);
widget.updateFormData("Bus", "_Check_In_Time", _toController.text);
});
_dateController.addListener(() {
widget.updateFormData(
"Bus", "_Check_Out", _dateController.text);
widget.updateFormData("Bus", "_Check_Out", _dateController.text);
});
_endDateController.addListener(() {
widget.updateFormData(
"Bus", "_Check_In", _endDateController.text);
widget.updateFormData("Bus", "_Check_In", _endDateController.text);
});
_timeController.addListener(() {
widget.updateFormData(
"Bus", "_Check_Out_Time", _timeController.text);
widget.updateFormData("Bus", "_Check_Out_Time", _timeController.text);
});
_commentsController.addListener(() {
widget.updateFormData(
"Bus", "_comments", _commentsController.text);
widget.updateFormData("Bus", "_comments", _commentsController.text);
});
}
@ -163,56 +166,60 @@ class _ForexScreenState extends State<ForexScreen> {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container(
color: Color(0xFFF4F4FB),
child: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
widget.onClose(false);
},
child: Icon(
Icons.close,
size: 18,
return Container(
color: Color(0xFFF4F4FB),
child: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
widget.onClose(false);
},
child: Icon(
Icons.close,
size: 18,
color: Color(0xFF575A74),
),
),
),
Text(
"Forex List",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF575A74),
),
),
),
Text("Forex List",
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
SizedBox(
height: 6,
),
Padding(
padding: const EdgeInsets.all(28.0),
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
SizedBox(height: 6),
Padding(
padding: const EdgeInsets.all(28.0),
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
),
),
)
],
],
),
),
),
),
);
});
);
},
);
}
List<Widget> _buildAccomadtionForm (bool isDesktop) {
List<Widget> _buildAccomadtionForm(bool isDesktop) {
List<Widget> buildResponsiveRow(List<Widget> children) {
return [
isDesktop ? Row(children: children) : Column(children: children),
@ -222,14 +229,12 @@ class _ForexScreenState extends State<ForexScreen> {
List<List<Widget>> rowBuilders = [
_builClassType(isDesktop),
_buildSecondRow(isDesktop)
_buildSecondRow(isDesktop),
];
return [
...buildResponsiveRow(_buildFirstRow(isDesktop)),
// Iterate over rowBuilders and wrap each in a responsive container
...rowBuilders.expand((row) => buildResponsiveRow(row)),
@ -247,23 +252,21 @@ class _ForexScreenState extends State<ForexScreen> {
];
}
List<Widget> _buildFirstRow(isDesktop) {
DateTime? _selectedCheckOutDate;
DateTime? _selectedEndDate;
Future<void> _selectCheckOutDate(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate!
: today,
initialDate:
_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate!
: today,
firstDate: today,
lastDate: DateTime(2100),
);
@ -274,18 +277,20 @@ class _ForexScreenState extends State<ForexScreen> {
_dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
});
}
};
}
;
Future<void> _selectForexEndDate(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedEndDate != null && _selectedEndDate!.isAfter(today)
? _selectedEndDate!
: today,
initialDate:
_selectedEndDate != null && _selectedEndDate!.isAfter(today)
? _selectedEndDate!
: today,
firstDate: today,
lastDate: DateTime(2100),
);
@ -298,7 +303,6 @@ class _ForexScreenState extends State<ForexScreen> {
}
}
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -306,9 +310,10 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Forex Start Date",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -330,32 +335,30 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today,
size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Forex End Date",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -377,46 +380,50 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today,
size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
),
),
),
],
),
];
}
List<Widget> _buildTripType(bool isDesktop){
List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
CustomTextFieldWrapper(
@ -432,51 +439,62 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
widget.updateFormData("Flight", "trip_type", newValue ?? "");
}
: null,
widget.updateFormData(
"Flight",
"trip_type",
newValue ?? "",
);
}
: null,
items: dropdownItems,
),
),
),
];
}
List<Widget> _builClassType(bool isDesktop){
List<Widget> _builClassType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
Column(
@ -485,9 +503,10 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Class *",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -504,15 +523,17 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
items: dropdownItems,
),
@ -535,27 +556,30 @@ class _ForexScreenState extends State<ForexScreen> {
];
}
List<Widget> _buildSecondRow(bool isDesktop) {
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Transport",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: _fromFocus,
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -565,28 +589,23 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Accomodation",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -611,21 +630,17 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Telephone",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -633,7 +648,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -643,34 +658,29 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Other Expenses",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: _toFocus,
isDesktop: isDesktop,
color:Colors.transparent,
color: Colors.transparent,
child: SizedBox(
height: 40,
@ -680,7 +690,11 @@ class _ForexScreenState extends State<ForexScreen> {
"Rs ",
// focusNode: _toFocusNode,
// controller: _toController,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
// decoration: const InputDecoration(
// labelText: "To",
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -694,43 +708,48 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
];
}
List<Widget> _buildCardDetailsRow(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Card Number*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -738,7 +757,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -748,7 +767,6 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
@ -756,21 +774,17 @@ class _ForexScreenState extends State<ForexScreen> {
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Currency*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -787,36 +801,34 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
items: dropdownItems,
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Card*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -841,21 +853,17 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Cash*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -863,7 +871,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -873,16 +881,12 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
];
}
@ -894,17 +898,19 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Delivery Location",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width: isDesktop
? MediaQuery.of(context).size.width * 0.4
: MediaQuery.of(context).size.width * 0.66,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.4
: MediaQuery.of(context).size.width * 0.66,
child: TextField(
focusNode: _commentsFocusNode,
controller: _commentsController,
@ -921,7 +927,7 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
],
)
),
];
}
@ -944,10 +950,14 @@ class _ForexScreenState extends State<ForexScreen> {
),
Text(
"Check If You Don't Have a forex Account",
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
],
)
),
];
}
@ -960,9 +970,7 @@ class _ForexScreenState extends State<ForexScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
@ -971,7 +979,6 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
SizedBox(width: 10), // Space between buttons
// Save Changes Button
ElevatedButton(
onPressed: () {
@ -979,9 +986,7 @@ class _ForexScreenState extends State<ForexScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue, // Primary color for save
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
@ -991,4 +996,4 @@ class _ForexScreenState extends State<ForexScreen> {
),
];
}
}
}

View File

@ -348,6 +348,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _numPassengerFocusNode,
controller: _numPassengerController,
style: const TextStyle(fontSize: 12),
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
@ -850,6 +851,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _destinationFocusNode,
controller: _destinationController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "Destination",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -888,6 +892,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _locationFocusNode,
controller: _locationController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "Pickup Location",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -932,6 +939,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _dateFocusNode,
controller: _dateController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -985,6 +997,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _timeFocusNode,
controller: _timeController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -1045,6 +1062,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _commentsFocusNode,
controller: _taxiCommentsController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -287,7 +288,7 @@ class _TrainScreenState extends State<TrainScreen> {
isCountryLoading = true;
});
final result = await apiService.fetchTrainCountryList();
final result = await apiService.fetchTrainCountryList(context);
print("ResultCountry : $result");
@ -466,6 +467,9 @@ class _TrainScreenState extends State<TrainScreen> {
focusNode: _trainNoFocusNode,
controller: _trainNoController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
decoration: InputDecoration(
labelText: "Train number",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1356,6 +1360,9 @@ class _TrainScreenState extends State<TrainScreen> {
// maxLines: 6,
// keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -163,9 +164,9 @@ class _VisaScreenState extends State<VisaScreen> {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
});
}
@ -549,7 +550,7 @@ class _VisaScreenState extends State<VisaScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: Focus(
@ -566,104 +567,108 @@ class _VisaScreenState extends State<VisaScreen> {
// Request focus when user taps
_countryFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
print("contryItem - $item");
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
print("contryItem - $item");
final match = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(item);
final countryName = match?.group(1) ?? '';
final countryCode = match?.group(2) ?? '';
return Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Padding(
padding: const EdgeInsets.only(right: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
countryName,
style: GoogleFonts.poppins(fontSize: 11.5),
final match = RegExp(
r'^(.*)\s\((.*)\)$',
).firstMatch(item);
final countryName = match?.group(1) ?? '';
final countryCode = match?.group(2) ?? '';
return Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Padding(
padding: const EdgeInsets.only(right: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
countryName,
style: GoogleFonts.poppins(fontSize: 11.5),
),
Text(
countryCode,
style: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
),
],
),
Text(
countryCode,
style: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
),
],
),
),
);
},
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search ...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor!
: Colors.white,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select ",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search ...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
onChanged: (String? newValue) {
setState(() {
selectedCountry =
countryMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
});
},
),),),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor!
: Colors.white,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select ",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: (String? newValue) {
setState(() {
selectedCountry =
countryMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
});
},
),
),
),
),
),
if (errorMessages["country_code"] != null) ...[
@ -729,115 +734,120 @@ class _VisaScreenState extends State<VisaScreen> {
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: _tripTypeFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_tripTypeFocused = hasFocus;
});
child: Focus(
focusNode: _tripTypeFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_tripTypeFocused = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_tripTypeFocusNode?.requestFocus();
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_tripTypeFocusNode?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedPurpose,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedPurpose,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: layoutColor,
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
child: Text(
item['dropdown_value'] ?? '',
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
);
},
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
// value: selectedPurpose,
// style: TextStyle(fontSize: 12),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding:
// EdgeInsets.symmetric(horizontal: 10), // Proper padding
// ),
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) {
setState(() {
selectedPurpose = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedPurpose}");
});
}
: null,
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
// value: selectedPurpose,
// style: TextStyle(fontSize: 12),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding:
// EdgeInsets.symmetric(horizontal: 10), // Proper padding
// ),
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) {
setState(() {
selectedPurpose = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedPurpose}");
});
}
: null,
),),),
),
),
),
if (errorMessages["type_of_visa"] != null) ...[
@ -933,6 +943,9 @@ class _VisaScreenState extends State<VisaScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _visaCommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -96,7 +96,10 @@ class _FlightListWidgetState extends State<FlightListWidget> {
}
Future<void> loadCountryList() async {
final result = await apiService.fetchFlightsCountryList(widget.tripType);
final result = await apiService.fetchFlightsCountryList(
context,
widget.tripType,
);
print("ResultCountry : $result");

View File

@ -395,7 +395,7 @@ class _ForexListWidgetState extends State<ForexListWidget> {
final id = int.tryParse(forexIdString ?? '');
if (id != null) {
apiService.getForexPdfDownload(id);
apiService.getForexPdfDownload(context, id);
} else {
print("Invalid forex_id: $forexIdString");
}

View File

@ -127,7 +127,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
Future<void> loadCountryList() async {
// final result = await apiService.fetchFlightsCountryList();
final result = await apiService.fetchTrainCountryList();
final result = await apiService.fetchTrainCountryList(context);
print("ResultCountry : $result");

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom;
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
@ -139,13 +140,19 @@ class TemplateState extends State<Template> {
}
if (!mounted) return;
try {
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
updateData();
loadinitializeData();
loadInitialData();
updateData();
loadinitializeData();
loadInitialData();
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -487,6 +494,11 @@ class TemplateState extends State<Template> {
isDisable = false;
});
context.go('/templateList');
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -631,6 +643,9 @@ class TemplateState extends State<Template> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["subjectFocusNode"],
controller: controllers["subject"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
// _clearError("local_id_num");
},

View File

@ -4,6 +4,7 @@ import 'dart:async';
import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom;
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
@ -150,13 +151,19 @@ class TemplateForexState extends State<TemplateForex> {
}
if (!mounted) return;
try {
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
updateData();
loadinitializeData();
loadInitialData();
updateData();
loadinitializeData();
loadInitialData();
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -471,6 +478,11 @@ class TemplateForexState extends State<TemplateForex> {
selectedOrglogo = rawLogoPath;
});
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("❌ Failed to fetch signature: ${response.statusCode}");
}
@ -538,6 +550,11 @@ class TemplateForexState extends State<TemplateForex> {
setState(() {
isDisable = false;
});
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -561,6 +578,15 @@ class TemplateForexState extends State<TemplateForex> {
if (pickedFile != null && kIsWeb) {
try {
final allowedExtensions = ['jpg', 'jpeg', 'png'];
final fileExtension = pickedFile.name.split('.').last.toLowerCase();
if (!allowedExtensions.contains(fileExtension)) {
print('❌ Invalid file type. Please select a JPG or PNG image.');
return;
}
final bytes = await pickedFile.readAsBytes();
print('✅ Image loaded, size: ${bytes.length} bytes');
setState(() {
@ -744,6 +770,9 @@ class TemplateForexState extends State<TemplateForex> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["subjectFocusNode"],
controller: controllers["subject"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
// _clearError("local_id_num");
},
@ -776,7 +805,7 @@ class TemplateForexState extends State<TemplateForex> {
// color: Color(0xFF575A74),
// ),
// ),
const SizedBox(height: 10),
// const SizedBox(height: 10),
Container(
color: Color(0xFFFFFEF0),
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
@ -930,54 +959,74 @@ class TemplateForexState extends State<TemplateForex> {
),
),
),
SizedBox(height: 4),
SizedBox(height: 2),
Container(
child: Row(
// mainAxisAlignment: MainAxisAlignment.end,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Upload Signature",
style: GoogleFonts.poppins(fontSize: 11.5),
),
SizedBox(width: 5),
GestureDetector(
onTap: _pickImage,
Row(
// mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"Upload Signature",
style: GoogleFonts.poppins(fontSize: 11.5),
),
SizedBox(width: 5),
GestureDetector(
onTap: _pickImage,
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width: 50, // Use responsive width
height: 50,
fit: BoxFit.cover,
),
)
: selectedOrglogo != null
? ClipRect(
child: Image.network(
selectedOrglogo!,
width: 50, // Use responsive width
height: 50,
// width: 250,
// height: 55,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const CircleAvatar(
radius: 20,
backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10),
);
},
),
)
: const CircleAvatar(
radius: 20,
backgroundColor: Colors.amber,
child: Icon(Icons.add_a_photo, size: 10),
),
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width: 50, // Use responsive width
height: 50,
fit: BoxFit.cover,
),
)
: selectedOrglogo != null
? ClipRect(
child: Image.network(
selectedOrglogo!,
width: 50, // Use responsive width
height: 50,
// width: 250,
// height: 55,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const CircleAvatar(
radius: 20,
backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10),
);
},
),
)
: const CircleAvatar(
radius: 20,
backgroundColor: Color(0xFFFFFAA0),
// backgroundColor: Color(0xFFFFFEF0),
child: Icon(Icons.add_a_photo, size: 10),
),
),
],
),
SizedBox(
// width: 200,
child: Text(
"* Allow types jpg, jpeg, png",
// maxLines: 2,
// softWrap: true,
style: GoogleFonts.poppins(
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
),

View File

@ -80,17 +80,22 @@ class TemplatesListState extends State<TemplatesList> {
if (!mounted) return;
try {
futureTemplates = fetchGetForex();
futureTemplates?.then((users) {
setState(() {
allTemplate = users;
print("AlL tEMPLATESNIT - $allTemplate");
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureTemplates?.then((users) {
setState(() {
allTemplate = users;
print("AlL tEMPLATESNIT - $allTemplate");
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -187,6 +192,11 @@ class TemplatesListState extends State<TemplatesList> {
print("TemplateDATA--- $data");
return data['data']; // Returning raw JSON list
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -774,7 +784,10 @@ class TemplatesListState extends State<TemplatesList> {
if (templateId != null) {
print("templateId -- $templateId");
final data = await apiService
.getTemplateFind(templateId);
.getTemplateFind(
context,
templateId,
);
print("ForexId -- $data");
context.go(
@ -834,7 +847,10 @@ class TemplatesListState extends State<TemplatesList> {
UserActionsMenu(
user: forex,
getUserDetails:
(id) => apiService.getSingleUser(id),
(id) => apiService.getSingleUser(
context,
id,
),
),
],
),

View File

@ -1,5 +1,7 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -24,6 +26,7 @@ class MailSetting extends StatefulWidget {
}
class _MailSettingState extends State<MailSetting> {
final ApiService apiService = ApiService();
String? orgId;
String? userId;
@ -176,6 +179,11 @@ class _MailSettingState extends State<MailSetting> {
if (response.statusCode == 200 || response.statusCode == 201) {
print("Plan submitted successfully!");
print("Response: ${response.body}");
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -325,6 +333,9 @@ class _MailSettingState extends State<MailSetting> {
height: 40,
child: TextField(
// focusNode: _destinationFocusNode,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["userNameFocusNode"],
controller: controllers["userName"],
onChanged: (value) {
@ -570,6 +581,7 @@ class _MailSettingState extends State<MailSetting> {
child: TextField(
// focusNode: _destinationFocusNode,
focusNode: focusNodes["portFocusNode"],
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
controller: controllers["port"],
onChanged: (value) {
_clearError("mail_port");

View File

@ -1,7 +1,9 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/organization/mailSettings.dart';
import 'package:frontend/Screens/organization/themeColor.dart';
import 'package:go_router/go_router.dart';
@ -68,7 +70,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -76,10 +78,14 @@ class _OrgSetUpState extends State<OrgSetUp> {
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
loadAllServices();
getOrganizationData();
initializeData();
loadInitialData();
if (roleUser != null && (roleUser == 'Org Admin')) {
loadAllServices();
getOrganizationData();
initializeData();
loadInitialData();
} else {
apiService.logout(context);
}
}
void loadInitialData() async {
@ -143,7 +149,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
apiAllServices = result;
});
@ -384,7 +390,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
if (response.statusCode == 200 || response.statusCode == 201) {
print("✅ User submitted successfully!");
print("📨 Response Organizt Update: ${response.body}");
await apiService.handleTokenRefresh(context, userId!);
final data = json.decode(response.body);
if (!data.containsKey('data') || data['data'] is! Map) {
@ -400,7 +406,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
print(orgList);
await updateOrgDataWithNewValues(orgList);
await apiService.handleTokenRefresh(userId!);
print("📨 Response Organizt Update:");
// return orgList;
context.go('/OrganizationSettings');
@ -540,15 +546,13 @@ class _OrgSetUpState extends State<OrgSetUp> {
}
Future<void> logout(BuildContext context) async {
// Clear localStorage
final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // Clears all keys
await apiService.logout(context);
// Optional: clear sessionStorage if used
// html.window.sessionStorage.clear();
// Navigate to login or home page
context.go('/');
// context.go('/');
}
@override
@ -654,6 +658,45 @@ class _OrgSetUpState extends State<OrgSetUp> {
Future<void> _pickImage() async {
final picker = ImagePicker();
final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery,
// For web: allow only specific file types
// This only works on web
preferredCameraDevice: CameraDevice.rear, // optional
);
if (pickedFile != null) {
// Check the file extension manually
final allowedExtensions = ['jpg', 'jpeg', 'png'];
final fileExtension = pickedFile.name.split('.').last.toLowerCase();
if (!allowedExtensions.contains(fileExtension)) {
print('❌ Invalid file type. Please select a JPG or PNG image.');
return;
}
if (kIsWeb) {
try {
final bytes = await pickedFile.readAsBytes();
print('✅ Image loaded, size: ${bytes.length} bytes');
setState(() {
_imageBytes = bytes;
});
} catch (e) {
print('❌ Error reading image bytes: $e');
}
} else {
// Handle mobile image if needed
print('✅ Image picked: ${pickedFile.path}');
}
} else {
print('⚠️ Image picking canceled.');
}
}
Future<void> _pickImage2() async {
final picker = ImagePicker();
final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
@ -774,7 +817,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
Expanded(
child: TextFormField(
controller: _orgNameController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: GoogleFonts.poppins(
fontSize: 16,
color: Color(0xFF114D8B),
@ -789,6 +836,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
FloatingLabelBehavior.never,
border: InputBorder.none,
isDense: true,
// contentPadding:
// EdgeInsets.symmetric(vertical: 14),
),
@ -796,50 +844,74 @@ class _OrgSetUpState extends State<OrgSetUp> {
),
),
Spacer(),
GestureDetector(
onTap: _pickImage,
Column(
children: [
GestureDetector(
onTap: _pickImage,
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
fit: BoxFit.contain,
),
)
: selectedOrg?['logo'] != null
? ClipRect(
child: Image.network(
selectedOrg!['logo'],
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
// width: 250,
// height: 55,
fit: BoxFit.contain,
errorBuilder: (
context,
error,
stackTrace,
) {
return const CircleAvatar(
radius: 20,
backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10),
);
},
),
)
: const CircleAvatar(
radius: 20,
backgroundColor: Colors.amber,
child: Icon(Icons.add_a_photo, size: 10),
),
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
fit: BoxFit.contain,
),
)
: selectedOrg?['logo'] != null
? ClipRect(
child: Image.network(
selectedOrg!['logo'],
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
// width: 250,
// height: 55,
fit: BoxFit.contain,
errorBuilder: (
context,
error,
stackTrace,
) {
return const CircleAvatar(
radius: 20,
backgroundColor: Colors.redAccent,
child: Icon(
Icons.error,
size: 10,
),
);
},
),
)
: const CircleAvatar(
radius: 20,
backgroundColor: Colors.amber,
child: Icon(
Icons.add_a_photo,
size: 10,
),
),
),
SizedBox(
// width: 200,
child: Text(
"* Allow types jpg, jpeg, png",
// maxLines: 2,
// softWrap: true,
style: GoogleFonts.poppins(
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
),
],
),

View File

@ -27,7 +27,7 @@ class _OrganizationListState extends State<OrganizationList> {
Future<void> loadAllOrganization() async {
try {
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
setState(() {
apiAllOrganization = result;
});
@ -54,23 +54,26 @@ class _OrganizationListState extends State<OrganizationList> {
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Colors.white,
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(child: buildGroupListLayout(isDesktop))
],
),
);
});
return Scaffold(
backgroundColor: Colors.white,
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(child: buildGroupListLayout(isDesktop)),
],
),
);
},
);
}
Widget buildGroupListLayout(bool isDesktop) {
@ -86,9 +89,10 @@ class _OrganizationListState extends State<OrganizationList> {
children: [
Row(
children: [
const Text('Organization List',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const Text(
'Organization List',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.keyboard_arrow_down),
onPressed: () {},
@ -97,21 +101,17 @@ class _OrganizationListState extends State<OrganizationList> {
),
ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.blueAccent),
foregroundColor: Colors.white,
backgroundColor: Colors.blueAccent,
),
onPressed: () async {
// List<dynamic> users = await futureUsers;
// context.go('/CreateGroup');
},
child: Row(
children: [
Icon(
Icons.add_circle,
color: Colors.white,
),
SizedBox(
width: 5,
),
Icon(Icons.add_circle, color: Colors.white),
SizedBox(width: 5),
Text('Create Organization'),
],
),
@ -127,16 +127,12 @@ class _OrganizationListState extends State<OrganizationList> {
// color: Colors.red.shade100,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
buildGroupListView(isDesktop),
],
),
child: Column(children: [buildGroupListView(isDesktop)]),
),
),
),
],
)
),
],
),
);
@ -169,12 +165,20 @@ class _OrganizationListState extends State<OrganizationList> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Organization Name: ${group['name']}",
style: TextStyle(
fontSize: 13, fontWeight: FontWeight.bold)),
Text("Organization Name: ${group['name']}",
style: TextStyle(
fontSize: 13, fontWeight: FontWeight.bold)),
Text(
"Organization Name: ${group['name']}",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
Text(
"Organization Name: ${group['name']}",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
],
),
SizedBox(height: 4),

View File

@ -162,7 +162,7 @@ class ForexDataState extends State<ForexData> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -325,6 +325,11 @@ class ForexDataState extends State<ForexData> {
setState(() {
isDisable = false;
});
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 404) {
if (context.mounted) {
Navigator.of(context).pop();
@ -860,6 +865,7 @@ class ForexDataState extends State<ForexData> {
focusNode: focusNodes["perdiemAmountFocusNode"],
controller: controllers["perdiemAmount"],
style: const TextStyle(fontSize: 12),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: const InputDecoration(
labelText: "Perdiem Amount",
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),

View File

@ -81,17 +81,22 @@ class ForexDataListState extends State<ForexDataList> {
if (!mounted) return;
try {
futureForex = fetchGetForex();
futureForex?.then((users) {
setState(() {
allForex = users;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureForex?.then((users) {
setState(() {
allForex = users;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCountryList();
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCountryList();
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -175,6 +180,11 @@ class ForexDataListState extends State<ForexDataList> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -225,6 +235,11 @@ class ForexDataListState extends State<ForexDataList> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -843,7 +858,10 @@ class ForexDataListState extends State<ForexDataList> {
if (forexId != null) {
print("ForexId -- $forexId");
final data = await apiService
.getForexDetailsFind(forexId);
.getForexDetailsFind(
context,
forexId,
);
print("ForexId -- $data");
showDialog(
@ -930,7 +948,10 @@ class ForexDataListState extends State<ForexDataList> {
if (forexId != null) {
print("ForexId -- $forexId");
final data = await apiService
.getForexDetailsFind(forexId);
.getForexDetailsFind(
context,
forexId,
);
print("ForexId -- $data");
showDialog(

View File

@ -3,6 +3,7 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:super_tooltip/super_tooltip.dart';
import 'package:web/web.dart' as web;
@ -681,11 +682,19 @@ class CreateNewPlansState extends State<CreateNewPlan> {
void handleUpdateData() {
if (widget.selectedPlanData != null) {
setState(() {
print("updatedPlanDAta - ${widget.selectedPlanData}");
statusValue = widget.selectedPlanData['status_value'] ?? '';
print("STATUS____ : $statusValue");
print("STATUSplanUsrId____ : ${widget.selectedPlanData['user_id']}");
planUsrId =
widget.selectedPlanData['user_id'] != '0'
? widget.selectedPlanData['user_id']
: widget.selectedPlanData['traveller_id'];
print("STATUSplanUsrId____1 : $planUsrId");
planUsrId = widget.selectedPlanData['user_id'] ?? '';
_tripTitleController.text = widget.selectedPlanData['trip_title'] ?? '';
_descriptionController.text =
widget.selectedPlanData['description'] ?? '';
@ -850,6 +859,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 404) {
showDialog(
context: context,
@ -1015,6 +1029,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1087,6 +1106,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1141,18 +1165,30 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
}
Future<void> fetchTrainFlightClass(int tripId) async {
// final userId =
// (planUsrId?.toString().isNotEmpty == true)
// ? planUsrId.toString()
// : (planTravlrId?.toString().isNotEmpty == true)
// ? planTravlrId.toString()
// : '';
print("TfetchTrainFlightClass");
final userId =
(planUsrId?.toString().isNotEmpty == true)
? planUsrId.toString()
: (planTravlrId?.toString().isNotEmpty == true)
? planTravlrId.toString()
: '';
(planUsrId?.toString().isNotEmpty == true) ? planUsrId.toString() : '';
print("TfetchTrainFlightClass - $userId");
// final String apiUrldata = '$apiUrl/api/getDropdownMaster';
final String apiUrldata =
@ -1193,6 +1229,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1348,6 +1389,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
// Close loading dialog (ONLY if still mounted)
if (mounted) Navigator.of(context, rootNavigator: true).pop();
context.go('/approvallist');
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("$methodName failed. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -1559,6 +1605,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
// ? context.go('/approvallist')
// : context.go('/listPlan');
// }
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -3186,6 +3237,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
focusNode: focusNodes["so_numberFocusNode"],
controller: _soNumberController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
decoration: InputDecoration(
labelText: "SO Number",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -3325,9 +3381,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
_showInputDialog(selected["title"]!);
} else if (_selectedOption == "Option 1") {
otherUserName = userName;
await apiService.handleTripWiseToken(selfId!);
// await apiService.handleTripWiseToken(selfId!, context);
fetchUserDetails();
_selectedTripType = null;
getSelectedPlanFor();
fetchUsrDtlFromSelectedTripUser();
dynamicItineraryKey.currentState
?.loadOrgSelectedAlServices();
dynamicItineraryKey.currentState
@ -3378,6 +3436,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
TextField(
controller: _excepntldescriptionController,
maxLines: 3,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
decoration: InputDecoration(
hintText: "Enter reason...",
hintStyle: GoogleFonts.poppins(fontSize: 10),
@ -3472,6 +3533,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
child: SizedBox(
height: 55,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
focusNode: focusNodes["excepntldescriptionFocusNode"],
controller: _excepntldescriptionController,
maxLines: 2,
@ -3572,6 +3638,12 @@ class CreateNewPlansState extends State<CreateNewPlan> {
focusNode: focusNodes["descriptionFocusNode"],
controller: _descriptionController,
maxLines: 2,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
enabled: !widget.isViewMode,
@ -3705,6 +3777,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
color: Colors.black,
),
enabled: !widget.isViewMode,
decoration: InputDecoration(
labelText: "Trip Name *",
labelStyle: GoogleFonts.poppins(
@ -3726,6 +3799,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
),
keyboardType: TextInputType.text,
scrollPhysics: BouncingScrollPhysics(),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
),
),
),
@ -4237,18 +4313,36 @@ class CreateNewPlansState extends State<CreateNewPlan> {
selectedIstravelUser = isTraveller;
});
print("USer entered : $otherUserName $userId $isTraveller");
getSelectedPlanFor();
print('---UserSelectionDialog');
// NOTE : Traveller use same trip token for self user,
// Trip Token changed for Other Employee -Selects userId should pass
if (isTraveller) {
await apiService.handleTripWiseToken(
selfId!,
); // since userId is for traveller
print('---TRAVELLER');
print('---TRAVELLER- $userId');
fetchUserDetails();
_selectedTripType = null;
getSelectedPlanFor();
fetchUsrDtlFromSelectedTripUser();
dynamicItineraryKey.currentState?.loadOrgSelectedAlServices();
dynamicItineraryKey.currentState?.updateSelectedServices();
// await apiService.handleTripWiseToken(
// // selfId!,
// userId,
// context,
// ); // since userId is for traveller
} else {
print('---NONTRAVELLER');
print('---NONTRAVELLER $userId');
await apiService.handleTripWiseToken(
userId,
context,
); // fallback to selfId
}
print('UserSelectionDialog-1');
getSelectedPlanFor();
print('UserSelectionDialog-2');
fetchUsrDtlFromSelectedTripUser();
dynamicItineraryKey.currentState?.loadOrgSelectedAlServices();
@ -4256,7 +4350,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
},
onClose: () async {
print("Choosede Clsoes");
await apiService.handleTripWiseToken(selfId!);
// await apiService.handleTripWiseToken(selfId!, context);
fetchUserDetails();
},
layoutColorForUser: widget.layoutColor!,

View File

@ -849,6 +849,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 404) {
showDialog(
context: context,
@ -989,6 +994,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1061,6 +1071,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1115,6 +1130,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1167,6 +1187,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -1322,6 +1347,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
// Close loading dialog (ONLY if still mounted)
if (mounted) Navigator.of(context, rootNavigator: true).pop();
context.go('/approvallist');
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("$methodName failed. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -1533,6 +1563,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
// ? context.go('/approvallist')
// : context.go('/listPlan');
// }
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");

View File

@ -199,7 +199,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
selectedAllServices = result;
});
@ -213,7 +213,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
Future<void> loadOrgSelectedAlServices() async {
print('loadOrgSelectedAlServices');
try {
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
if (result != null && result is Map<String, dynamic>) {
final rawServices = result['services_ids'];

View File

@ -59,7 +59,7 @@ class _ListPlansState extends State<ListPlans> {
@override
void initState() {
super.initState();
print("LSIT PLan -1");
_checkAuthAndLoadData();
checkbackbutton();
@ -69,6 +69,7 @@ class _ListPlansState extends State<ListPlans> {
}
void checkbackbutton() async {
print("LSIT PLan -3");
roleUser = await getRoleUser();
print(roleUser);
if (roleUser == "User") {
@ -79,10 +80,29 @@ class _ListPlansState extends State<ListPlans> {
print("msUser - $msUser");
html.window.history.pushState(null, '', html.window.location.href);
print("locationLP - $location");
// if (location!.contains('/listPlan')) {
// // Do nothing or show "Press again to exit" toast
// print("Blocked back on /listPlan");
// } else {
// print("/listPlan ..");
// }
if (!msUser) {
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
print("locationLPw - 1");
print("locationLPw - ${html.window.location}");
final fullUrl = html.window.location.href;
final hashPart =
fullUrl.split('#/').last; // "OrganizationSettings"
print("Current route: $hashPart");
if (hashPart.contains('/listPlan')) {
print("locationLPw - 2r");
_showBackConfirmationDialog();
}
print("locationLPw - 2");
}
// Re-push to prevent leaving
@ -99,7 +119,8 @@ class _ListPlansState extends State<ListPlans> {
}
void _showBackConfirmationDialog() {
if (!mounted) return;
print('List planstt');
// if (!mounted) return;
_dialogShown = true;
@ -119,7 +140,7 @@ class _ListPlansState extends State<ListPlans> {
),
TextButton(
onPressed: () async {
Navigator.pop(context); // Close dialog
// Navigator.pop(context); // Close dialog
_dialogShown = false;
await _logoutAndRedirect(context);
},
@ -132,22 +153,24 @@ class _ListPlansState extends State<ListPlans> {
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0");
await apiService.logout(context);
// Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
// // Example: clear session or shared preferences
// final prefs = await SharedPreferences.getInstance();
// await prefs.clear();
context.go("/");
// context.go("/");
print("logue 1");
}
void _checkAuthAndLoadData() async {
print("LSIT PLan -2");
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
// apiService.logout(context);
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
@ -155,6 +178,7 @@ class _ListPlansState extends State<ListPlans> {
} else {
if (roleUser == "User") {
print("user");
print("roleUsers - $roleUser");
// After login is successful and navigation completes:
WidgetsBinding.instance.addPostFrameCallback((_) {
@ -304,6 +328,11 @@ class _ListPlansState extends State<ListPlans> {
// List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -337,6 +366,11 @@ class _ListPlansState extends State<ListPlans> {
print("Plan Deleted successfully!");
print("Response: ${response.body}");
initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -346,7 +380,7 @@ class _ListPlansState extends State<ListPlans> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
// try {
// Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
// print("ViewAAA - $planData");
@ -363,7 +397,11 @@ class _ListPlansState extends State<ListPlans> {
if (confirmed) {
try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
refresh();
// postPlanData(planData, planId);
@ -415,6 +453,11 @@ class _ListPlansState extends State<ListPlans> {
approverData = List<Map<String, dynamic>>.from(
data['data']['approver_data'] ?? [],
);
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print('Failed to load');
label = "Error - Failed to load data";
@ -1185,7 +1228,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
); // Close popup manually
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1211,7 +1254,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
);
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1235,6 +1278,7 @@ class _ListPlansState extends State<ListPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1255,6 +1299,7 @@ class _ListPlansState extends State<ListPlans> {
);
apiService
.getPdfDownload(
context,
plan.planId,
);
},
@ -1281,10 +1326,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),
IconButton(
@ -1529,7 +1574,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
); // Close popup manually
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1556,7 +1601,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
);
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode:
@ -1580,6 +1625,7 @@ class _ListPlansState extends State<ListPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1598,10 +1644,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
);
apiService
.getPdfDownload(
plan.planId,
);
apiService.getPdfDownload(
context,
plan.planId,
);
},
),
@ -1626,10 +1672,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
apiService.getForexPdfDownload(
context,
plan.forexId,
);
},
),
IconButton(

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@ import 'dart:ui' as html;
import 'dart:async';
import 'dart:html' as html;
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'dart:ui' as web;
@ -186,31 +187,38 @@ class _PolicyState extends State<Policy> {
}
if (!mounted) return;
try {
loadinitializeData();
final roleUser = await getRoleUser();
await updateSelectedServices();
updateData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadinitializeData();
loadInitialData();
await updateSelectedServices();
updateData();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.policy != null) {
final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'],
);
policyCriteriaKey.currentState?.loadPolicyDetails(details);
}
});
loadInitialData();
// if (widget.policy != null) {
// print("185");
// final details = List<Map<String, dynamic>>.from(
// widget.policy!['policy_details'],
// );
// policyCriteriaKey.currentState?.loadPolicyDetails(details);
//
// policyCriteriaKey.currentState?.fetchTrainFlightClass();
// }
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.policy != null) {
final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'],
);
policyCriteriaKey.currentState?.loadPolicyDetails(details);
}
});
// if (widget.policy != null) {
// print("185");
// final details = List<Map<String, dynamic>>.from(
// widget.policy!['policy_details'],
// );
// policyCriteriaKey.currentState?.loadPolicyDetails(details);
//
// policyCriteriaKey.currentState?.fetchTrainFlightClass();
// }
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -240,7 +248,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
selectedAllServices = result;
});
@ -252,7 +260,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadOrgSelectedAlServices() async {
try {
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
if (result != null && result is Map<String, dynamic>) {
final rawServices = result['services_ids'];
@ -504,7 +512,7 @@ class _PolicyState extends State<Policy> {
bool result = false;
try {
result = await createPolicyData(data);
result = await createPolicyData(context, data);
} catch (e) {
print("Unexpected error during policy creation: $e");
}
@ -586,7 +594,10 @@ class _PolicyState extends State<Policy> {
}
}
Future<bool> createPolicyData(Map<String, dynamic> policyData) async {
Future<bool> createPolicyData(
BuildContext context,
Map<String, dynamic> policyData,
) async {
final String apiUrldata = '$apiUrl/api/policy/createOrUpdate';
final token = await getToken(); // Fetch token
@ -616,9 +627,14 @@ class _PolicyState extends State<Policy> {
if (response.statusCode == 200) {
print("policyData submitted successfully!");
await apiService.handleTokenRefresh(userId!);
await apiService.handleTokenRefresh(context, userId!);
print("Response: ${response.body}");
return true;
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return false;
// throw Exception('Failed to load users');
} else {
print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -945,6 +961,9 @@ class _PolicyState extends State<Policy> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["policyFocusNode"],
controller: _policyController,
onChanged: (value) => _clearError("name"),

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -415,7 +416,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
Future<void> fetchTrainFlightClass() async {
print("ftech api");
try {
final data = await apiService.fetchMasterDropdown();
final data = await apiService.fetchMasterDropdown(context);
print("fetchTrainFlightClass - $data");
@ -3798,6 +3799,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
child: TextField(
style: GoogleFonts.poppins(fontSize: 12),
controller: costController[ServiceId],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
// enabled: !isViewMode,
onChanged: (value) {
printData();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,428 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:frontend/Screens/group/group.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:responsive_builder/responsive_builder.dart';
import '../../config/apiUrl.dart';
import '../../routes/custom_appBar.dart';
import '../../routes/custom_drawer.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
class PolicyListBackup extends StatefulWidget {
@override
_PolicyListBackupState createState() => _PolicyListBackupState();
}
class _PolicyListBackupState extends State<PolicyListBackup> {
final ApiService apiService = ApiService();
List<dynamic>? apiAllGroups;
Color? layoutColor;
Color? bodyColor;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
loadAllGroups();
loadInitialData();
});
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
}
Future<void> loadAllGroups() async {
try {
final result = await apiService.fetchAllPolicy();
// Sort by policy_id descending (latest first)
result.sort((a, b) {
int idA = int.tryParse(a['policy_id'].toString()) ?? 0;
int idB = int.tryParse(b['policy_id'].toString()) ?? 0;
return idB.compareTo(idA); // latest first
});
setState(() {
apiAllGroups = result;
});
print("Fetched services: $apiAllGroups");
} catch (e) {
print('Error fetching role list: $e');
}
}
void handleActiveStatus(
Map<String, dynamic> policyData,
String policyId,
String currentStatus,
) async {
print("Toggling user status - $policyId (Current: $currentStatus)");
final String apiUrlData =
'$apiUrl/api/policy/createOrUpdate'; // API for updating user
final String? token = await getToken();
if (token == null) {
print("Error: Token not found");
return;
}
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
String newStatus = (currentStatus == "1") ? "0" : "1";
print("STatus 1 - $newStatus");
final int? selectedPolicyId;
if (policyId.isNotEmpty) {
selectedPolicyId = int.tryParse(policyId);
policyData['policy_id'] = selectedPolicyId; // Add only if updating
policyData['is_active'] = newStatus; // Add only if updating
}
try {
final response = await http.post(
Uri.parse(apiUrlData),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: jsonEncode(policyData), // Convert map to JSON
);
if (response.statusCode == 200) {
print("policyData submitted successfully!");
print("Response: ${response.body}");
loadAllGroups();
} else {
print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}");
}
} catch (e) {
print(" Error submitting policyData: $e");
}
}
void deletePolicy(Map<String, dynamic> policydata, policyId, status) {
print("policyId : $policyId");
print("policystatus: $status");
print("policysData: $policydata");
// handleActiveStatus(groupdata, groupId, status);
print("Calling handleActiveStatus with: id=$policyId, status=$status");
handleActiveStatus(policydata, policyId.toString(), status.toString());
}
// Future<void> deleteGroupFromApi(int groupId) async {
// try {
// await apiService.deleteGroup(groupId); // your delete API call
// deleteGroup(groupId); // remove from UI list
// } catch (e) {
// print('Error deleting group: $e');
// }
// }'
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding
vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding
)
: EdgeInsets.all(0),
child: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(child: buildGroupList(isDesktop)),
],
),
),
);
},
);
}
Widget buildGroupList(bool isDesktop) {
return Container(
margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null,
padding: const EdgeInsets.only(left: 10, right: 10, top: 8),
decoration: BoxDecoration(
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
),
// decoration: BoxDecoration(
// // color: Colors.amber,
// color: Color(0xFFE1F5FE),
// // color: bodyColor,
// border: Border.all(
// // color: Color(0xFFF7F7FB),
// color: Colors.white,
// width: 3.5)),
child: buildGroupListLayout(isDesktop),
);
}
Widget buildGroupListLayout(bool isDesktop) {
return Container(
// margin: isDesktop
// ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10),
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
// decoration: BoxDecoration(
// border: isDesktop
// ? Border.all(
// width: 2,
// color: Colors.white,
// // color: Color(0xFFF7F7FB),
// )
// : null,
// color: Colors.white,
// // color: Color(0xFFF7F7FB),
//
// // color: Colors.amber,
// ),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
'Policy List',
style: GoogleFonts.poppins(
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
IconButton(
icon: const Icon(Icons.keyboard_arrow_down),
onPressed: () {},
),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Color(0xFF114D8B),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
// side: BorderSide(color: , width: 1),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: () async {
// List<dynamic> users = await futureUsers;
context.go('/Policy');
},
child: Row(
children: [
Text(
'New Policy',
style: GoogleFonts.poppins(fontSize: 12),
),
SizedBox(width: 5),
Icon(Icons.add_circle_outline_rounded, color: Colors.white),
],
),
),
],
),
SizedBox(height: 5),
Row(
children: [
Expanded(
child: Container(
height: MediaQuery.of(context).size.height * 0.8,
padding: const EdgeInsets.all(10),
// margin: const EdgeInsets.only(bottom: 10),
color: Colors.white,
// color: Colors.red.shade100,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(children: [buildGroupListView(isDesktop)]),
),
),
),
],
),
],
),
);
}
// Widget buildGroupListView(bool isDesktop) {
// return Container(
// child: Text("DAta"),
// );
// }
Widget buildGroupListView(bool isDesktop) {
if (apiAllGroups == null || apiAllGroups!.isEmpty) {
return Center(child: Text("No Policy Found."));
}
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: apiAllGroups!.length,
itemBuilder: (context, index) {
final policy = apiAllGroups![index];
return Card(
// color: bodyColor,
// color: Color(0xFFF5F5F5),
color: Colors.white,
margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
flex: 1,
child: Text(
"Policy Name",
style: GoogleFonts.poppins(
fontSize: 11.5,
fontWeight: FontWeight.w400,
),
),
),
Expanded(
flex: 1,
child: Text(
"Policy Type",
style: GoogleFonts.poppins(
fontSize: 11.5,
fontWeight: FontWeight.w400,
),
),
),
// Expanded(flex: 1, child: Text("${policy['created_by']}")),
],
),
SizedBox(height: 4),
Row(
children: [
Expanded(
flex: 1,
child: Text(
"${policy['name']}",
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
Expanded(
flex: 1,
child: Text(
policy['domestic'] == "1"
? "Domestic"
: "International",
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
// Expanded(flex: 1, child: Text("${policy['created_by']}")),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () async {
final rawId = policy['policy_id'];
final intPolicyId =
rawId is int
? rawId
: int.tryParse(rawId.toString()) ?? 0;
Map<String, dynamic> policyData = await apiService
.getSinglePolicy(intPolicyId);
print("PolicyDATa: $policyData");
context.go("/Policy", extra: policyData);
},
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
),
SizedBox(width: 5),
GestureDetector(
onTap: () {
final idStr = policy['policy_id'];
final id = int.tryParse(idStr.toString());
if (id == null) {
print("group_id is null");
return;
}
final status = policy['is_active'];
deletePolicy(policy, id, status);
},
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
],
),
],
),
),
);
},
);
}
}

View File

@ -217,7 +217,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
selectedAllServices = result;
});
@ -229,7 +229,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadOrgSelectedAlServices() async {
try {
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
if (result != null && result is Map<String, dynamic>) {
final rawServices = result['services_ids'];

View File

@ -74,16 +74,23 @@ class _PolicyListState extends State<PolicyList> {
}
if (!mounted) return;
try {
futurePolicy = fetchPolicy();
final roleUser = await getRoleUser();
futurePolicy?.then((object) {
setState(() {
allPolicy = object;
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futurePolicy = fetchPolicy();
futurePolicy?.then((object) {
setState(() {
allPolicy = object;
});
});
});
loadInitialData();
fetchPolicy();
loadInitialData();
fetchPolicy();
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -112,7 +119,7 @@ class _PolicyListState extends State<PolicyList> {
}
Future<List<dynamic>> fetchPolicy() async {
final data = await apiService.fetchAllPolicy();
final data = await apiService.fetchAllPolicy(context);
return data; // Returning raw JSON list
}
@ -196,6 +203,11 @@ class _PolicyListState extends State<PolicyList> {
print("policyData submitted successfully!");
print("Response: ${response.body}");
loadAllGroups();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -219,7 +231,7 @@ class _PolicyListState extends State<PolicyList> {
Future<void> loadAllGroups() async {
try {
final result = await apiService.fetchAllPolicy();
final result = await apiService.fetchAllPolicy(context);
setState(() {
allPolicy = result;
filteredPolicy = result;
@ -679,6 +691,7 @@ class _PolicyListState extends State<PolicyList> {
await apiService
.getSinglePolicy(
intPolicyId,
context,
);
print("PolicyDATa: $policyData");
@ -805,6 +818,7 @@ class _PolicyListState extends State<PolicyList> {
await apiService
.getSinglePolicy(
intPolicyId,
context,
);
print("PolicyDATa: $policyData");
@ -971,6 +985,7 @@ class _PolicyListState extends State<PolicyList> {
Map<String, dynamic> policyData =
await apiService.getSinglePolicy(
intPolicyId,
context,
);
print("PolicyDATa: $policyData");

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -311,6 +312,11 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
child: TextField(
controller: controllers["dropdown_value"],
focusNode: focusNodes["dropdown_valueFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Name",

View File

@ -79,15 +79,21 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
try {
futurePurposeOfTravel = fetchGetPurposeOfTravel();
futurePurposeOfTravel?.then((object) {
setState(() {
allPurposeOfTravel = object;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futurePurposeOfTravel?.then((object) {
setState(() {
allPurposeOfTravel = object;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -156,6 +162,11 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -657,6 +668,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
);
final data = await apiService
.getPurposeOfTravelDetailsFind(
context,
purposeOfTravelId,
);
print("PurposeOfTravelId -- $data");
@ -752,6 +764,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
);
final data = await apiService
.getPurposeOfTravelDetailsFind(
context,
purposeOfTravelId,
);
print("PurposeOfTravelId -- $data");

View File

@ -185,7 +185,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -193,10 +193,17 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("advance report : $e");
@ -290,6 +297,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'advancePurchaseReport',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -319,7 +327,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
domesticData = [];
internationalData = [];
dataAvailableDomesticFlag = 0;
dataAvailableInternationFlag = 0;
dataAvailableInternationFlag = 0;
});
}
}
@ -329,7 +337,6 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
if (textControllers["from_date"]!.text.isEmpty ||
textControllers["to_date"]!.text.isEmpty) {
Fluttertoast.showToast(
msg: "Please choose a valid date range.",
toastLength: Toast.LENGTH_SHORT,
@ -356,8 +363,6 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), '');
final excelName = '$safeName';
Map<String, dynamic> result = {
"status": false,
"message": "Data Not Found",
@ -365,6 +370,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'advancePurchaseReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -374,8 +380,10 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
excelName,
);
}
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) {
if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'advancePurchaseReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -386,21 +394,23 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
);
}
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}
@ -416,7 +426,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
try {
final parsedDate = DateTime.parse(fromDateRaw);
newFromDate =
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
} catch (e) {
// fallback if date is not parsable
newFromDate = fromDateRaw;
@ -429,7 +439,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
try {
final parsedDate = DateTime.parse(fromDateRaw);
newToDate =
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
} catch (e) {
// fallback if date is not parsable
newToDate = toDateRaw;
@ -441,17 +451,18 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['Service']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['created_on']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['created_time']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['FirstTravelDt']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['created_on']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['created_time']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['FirstTravelDt']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['AdvPurch']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage1 = 0;
@ -473,7 +484,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
try {
final parsedDate = DateTime.parse(fromDateRaw);
newFromDate =
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
} catch (e) {
// fallback if date is not parsable
newFromDate = fromDateRaw;
@ -486,7 +497,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
try {
final parsedDate = DateTime.parse(fromDateRaw);
newToDate =
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
'${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}';
} catch (e) {
// fallback if date is not parsable
newToDate = toDateRaw;
@ -498,17 +509,18 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['Service']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['created_on']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['created_time']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['FirstTravelDt']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['created_on']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['created_time']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['FirstTravelDt']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['AdvPurch']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage2 = 0;
@ -1037,12 +1049,12 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
label: Text(
'Created Time',
style:
GoogleFonts.poppins(
fontSize: 12,
fontWeight:
FontWeight
.w600,
),
GoogleFonts.poppins(
fontSize: 12,
fontWeight:
FontWeight
.w600,
),
),
),
DataColumn(
@ -1074,8 +1086,10 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
paginatedDomestic.map((
entry,
) {
final FromDate = entry['created_on'];
final ToDate = entry['FirstTravelDt'];
final FromDate =
entry['created_on'];
final ToDate =
entry['FirstTravelDt'];
return DataRow(
cells: [
DataCell(
@ -1147,7 +1161,7 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
'${entry['created_time']}',
style: GoogleFonts.poppins(
fontSize:
12,
12,
),
),
),
@ -1647,8 +1661,10 @@ class _AdvancePurchaseState extends State<AdvancePurchase>
paginatedInternational.map((
entry,
) {
final FromDate = entry['created_on'];
final ToDate = entry['FirstTravelDt'];
final FromDate =
entry['created_on'];
final ToDate =
entry['FirstTravelDt'];
return DataRow(
cells: [
DataCell(

View File

@ -149,7 +149,7 @@ class _GuestHouseState extends State<GuestHouse>
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -157,10 +157,17 @@ class _GuestHouseState extends State<GuestHouse>
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("guest report : $e");
@ -266,6 +273,7 @@ class _GuestHouseState extends State<GuestHouse>
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'guestHouseReport',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -303,9 +311,8 @@ class _GuestHouseState extends State<GuestHouse>
if (textControllers["from_date"]!.text.isEmpty ||
textControllers["to_date"]!.text.isEmpty) {
Fluttertoast.showToast(
msg: "Please choose a valid date range." ,
msg: "Please choose a valid date range.",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
@ -332,6 +339,7 @@ class _GuestHouseState extends State<GuestHouse>
final excelName = '$safeName';
final result = await apiService.reportExcelDownload(
context,
'guestHouseReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -341,20 +349,23 @@ class _GuestHouseState extends State<GuestHouse>
excelName,
);
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}
@ -385,9 +396,7 @@ class _GuestHouseState extends State<GuestHouse>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_trip_type']?.toLowerCase().contains(
lowerQuery,
@ -433,9 +442,7 @@ class _GuestHouseState extends State<GuestHouse>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_trip_type']?.toLowerCase().contains(
lowerQuery,

View File

@ -150,7 +150,7 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -158,10 +158,17 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("Air report : $e");
@ -267,6 +274,7 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'misAirReport',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -308,7 +316,6 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
if (textControllers["from_date"]!.text.isEmpty ||
textControllers["to_date"]!.text.isEmpty) {
Fluttertoast.showToast(
msg: "Please choose a valid date range.",
toastLength: Toast.LENGTH_SHORT,
@ -335,7 +342,6 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), '');
final excelName = '$safeName';
Map<String, dynamic> result = {
"status": false,
"message": "Data Not Found",
@ -343,6 +349,7 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misAirReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -352,8 +359,10 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
excelName,
);
}
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) {
if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misAirReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -364,20 +373,23 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
);
}
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}
@ -408,9 +420,7 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_trip_type']?.toLowerCase().contains(
lowerQuery,
@ -420,7 +430,10 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
false) ||
(object['flight_class']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_travel_date']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['flight_travel_date']?.toLowerCase().contains(
lowerQuery,
) ??
false) ||
(object['sector']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage1 = 0;
@ -457,9 +470,7 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_trip_type']?.toLowerCase().contains(
lowerQuery,
@ -469,7 +480,10 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
false) ||
(object['flight_class']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['flight_travel_date']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['flight_travel_date']?.toLowerCase().contains(
lowerQuery,
) ??
false) ||
(object['sector']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage2 = 0;
@ -1024,7 +1038,8 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
paginatedDomestic.map((
entry,
) {
final TravelDate = entry['flight_travel_date'];
final TravelDate =
entry['flight_travel_date'];
return DataRow(
cells: [
DataCell(
@ -1537,7 +1552,8 @@ class _MISairState extends State<MISair> with SingleTickerProviderStateMixin {
paginatedInternational.map((
entry,
) {
final TravelDate = entry['flight_travel_date'];
final TravelDate =
entry['flight_travel_date'];
return DataRow(
cells: [
DataCell(

View File

@ -120,7 +120,7 @@ class _MISforexState extends State<MISforex>
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -128,10 +128,17 @@ class _MISforexState extends State<MISforex>
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("Forex report : $e");
@ -234,6 +241,7 @@ class _MISforexState extends State<MISforex>
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'misForexReport',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -296,8 +304,10 @@ class _MISforexState extends State<MISforex>
"message": "Data Not Found",
};
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) {
if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misForexReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -308,21 +318,23 @@ class _MISforexState extends State<MISforex>
);
}
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}
@ -367,9 +379,7 @@ class _MISforexState extends State<MISforex>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['visiting_country']?.toLowerCase().contains(
lowerQuery,
@ -822,22 +832,24 @@ class _MISforexState extends State<MISforex>
paginatedInternational.map((
entry,
) {
final forexFromDate = entry['forex_from_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['forex_from_date'],
// ),
// );
final forexToDate = entry['forex_to_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['forex_to_date'],
// ),
// );
final forexFromDate =
entry['forex_from_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['forex_from_date'],
// ),
// );
final forexToDate =
entry['forex_to_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['forex_to_date'],
// ),
// );
return DataRow(
cells: [
DataCell(

View File

@ -134,7 +134,7 @@ class _MIShotelState extends State<MIShotel>
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -142,10 +142,17 @@ class _MIShotelState extends State<MIShotel>
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("hotel report : $e");
@ -268,6 +275,7 @@ class _MIShotelState extends State<MIShotel>
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'misHotelReport',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -309,7 +317,6 @@ class _MIShotelState extends State<MIShotel>
if (textControllers["from_date"]!.text.isEmpty ||
textControllers["to_date"]!.text.isEmpty) {
Fluttertoast.showToast(
msg: "Please choose a valid date range.",
toastLength: Toast.LENGTH_SHORT,
@ -343,6 +350,7 @@ class _MIShotelState extends State<MIShotel>
if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misHotelReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -352,8 +360,10 @@ class _MIShotelState extends State<MIShotel>
excelName,
);
}
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) {
if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misHotelReport',
jsonEncode({
"fromDate": formattedFromDate,
@ -364,20 +374,23 @@ class _MIShotelState extends State<MIShotel>
);
}
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}
@ -421,16 +434,16 @@ class _MIShotelState extends State<MIShotel>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['hotel_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['check_in_date'].toLowerCase().contains(lowerQuery) ?? false) ||
(object['check_out_date'].toLowerCase().contains(lowerQuery) ?? false) ||
(object['check_in_date'].toLowerCase().contains(lowerQuery) ??
false) ||
(object['check_out_date'].toLowerCase().contains(lowerQuery) ??
false) ||
(object['hotel_city']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage1 = 0;
@ -479,16 +492,16 @@ class _MIShotelState extends State<MIShotel>
false) ||
(object['so_number']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['cost_center']?.toLowerCase().contains(
lowerQuery,
) ??
(object['cost_center']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['plan_trip_type']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['hotel_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['check_in_date']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['check_out_date'].toLowerCase().contains(lowerQuery) ?? false) ||
(object['check_in_date']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['check_out_date'].toLowerCase().contains(lowerQuery) ??
false) ||
(object['hotel_city']?.toLowerCase().contains(lowerQuery));
}).toList();
currentPage2 = 0;
@ -1067,9 +1080,11 @@ class _MIShotelState extends State<MIShotel>
paginatedDomestic.map((
entry,
) {
final checkInDate = entry['check_in_date'];
final checkInDate =
entry['check_in_date'];
final checkOutDate = entry['check_out_date'];
final checkOutDate =
entry['check_out_date'];
return DataRow(
cells: [
@ -1674,22 +1689,24 @@ class _MIShotelState extends State<MIShotel>
paginatedInternational.map((
entry,
) {
final checkInDate = entry['check_in_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['check_in_date'],
// ),
// );
final checkOutDate = entry['check_out_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['check_out_date'],
// ),
// );
final checkInDate =
entry['check_in_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['check_in_date'],
// ),
// );
final checkOutDate =
entry['check_out_date'];
// DateFormat(
// 'dd-MM-yyyy',
// ).format(
// DateTime.parse(
// entry['check_out_date'],
// ),
// );
return DataRow(
cells: [
DataCell(
@ -1840,24 +1857,24 @@ class _MIShotelState extends State<MIShotel>
Widget buildTitle(bool isDesktop) {
return // Left side: Breadcrumb inside a Container (optional)
Row(
children: [
BreadcrumbNavigation(
isDesktop: isDesktop,
breadcrumbItems: [
BreadcrumbItem(
title: 'Report List',
tooltip: 'Go To Report List',
onTap: (context) {
// Navigator.pushNamed(context, '/report');
context.go("/report");
},
),
BreadcrumbItem(title: 'MIS Hotel Report '),
],
),
],
);
Row(
children: [
BreadcrumbNavigation(
isDesktop: isDesktop,
breadcrumbItems: [
BreadcrumbItem(
title: 'Report List',
tooltip: 'Go To Report List',
onTap: (context) {
// Navigator.pushNamed(context, '/report');
context.go("/report");
},
),
BreadcrumbItem(title: 'MIS Hotel Report '),
],
),
],
);
}
Widget buildExports(bool isDesktop) {

View File

@ -47,7 +47,7 @@ class _ReportListState extends State<ReportList> {
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -55,10 +55,17 @@ class _ReportListState extends State<ReportList> {
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
print('_checkAuthAndLoadDataSS - $roleUser');
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("service report : $e");
@ -177,8 +184,8 @@ class _ReportListState extends State<ReportList> {
color: Colors.white,
child: InkWell(
onTap: () async {
final route = item['value'] as String;
context.go(route);
final route = item['value'] as String;
context.go(route);
},
child: Padding(
padding: EdgeInsets.all(12),

View File

@ -163,7 +163,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -171,10 +171,16 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
});
} catch (e) {
print("service report : $e");
@ -270,6 +276,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
loaderFlag = true;
try {
final result = await apiService.CallReports(
context,
'misServicesAnalysis',
jsonEncode({
"fromDate": '$formattedfromDate',
@ -338,7 +345,6 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), '');
final excelName = '$safeName';
Map<String, dynamic> result = {
"status": false,
"message": "Data Not Found",
@ -346,6 +352,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misServicesAnalysis',
jsonEncode({
"fromDate": formattedFromDate,
@ -355,8 +362,10 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
excelName,
);
}
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) {
if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload(
context,
'misServicesAnalysis',
jsonEncode({
"fromDate": formattedFromDate,
@ -368,20 +377,23 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
}
// Now you can safely access result
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent;
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message'];
// final bool status = result['status'] == true;
Fluttertoast.showToast(
msg: displayMessage ,
msg: displayMessage,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: displayColor,
textColor: Colors.white,
fontSize: 18.0,
webBgColor: "linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
webBgColor:
"linear-gradient(to right, $displayBackgroundColor, $displayBackgroundColor)",
);
}

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -270,6 +271,12 @@ class TravellerDataState extends State<TravellerData> {
});
break;
case 403:
print("403-FORB");
await apiService.logout(context);
break;
// throw Exception('Failed to load users');
default:
print("Failed to submit traveller. Status: ${response.statusCode}");
print("Error: ${response.body}");
@ -334,6 +341,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["first_name"],
focusNode: focusNodes["first_nameFocusNode"],
style: const TextStyle(fontSize: 12),
@ -379,6 +391,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["last_name"],
focusNode: focusNodes["last_nameFocusNode"],
style: const TextStyle(fontSize: 12),

View File

@ -78,16 +78,21 @@ class TravellerListState extends State<TravellerList> {
if (!mounted) return;
try {
futureTraveller = fetchGetTraveller();
futureTraveller?.then((object) {
setState(() {
allTraveller = object;
final roleUser = await getRoleUser();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureTraveller?.then((object) {
setState(() {
allTraveller = object;
});
});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
} else {
apiService.logout(context);
}
} catch (e) {
print("group : $e");
}
@ -158,6 +163,11 @@ class TravellerListState extends State<TravellerList> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -670,6 +680,7 @@ class TravellerListState extends State<TravellerList> {
);
final data = await apiService
.getTravellerDetailsFind(
context,
travellerId,
);
print("TravellerId -- $data");
@ -758,6 +769,7 @@ class TravellerListState extends State<TravellerList> {
print("travellerId -- $travellerId");
final data = await apiService
.getTravellerDetailsFind(
context,
travellerId,
);
print("TravellerId -- $data");

View File

@ -355,6 +355,7 @@ class _CreateTravelAgentFormDetialsState
}
void _checkAuthAndLoadData() async {
final roleUser = await getRoleUser();
setState(() {
isCheckingToken = true;
});
@ -367,44 +368,50 @@ class _CreateTravelAgentFormDetialsState
return;
}
setState(() {
isCheckingToken = false;
});
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
setState(() {
isCheckingToken = false;
});
prepareForNewEntry();
selectedTab = "personal";
prepareForNewEntry();
selectedTab = "personal";
apiCountryData = null;
apiUserData = null;
apiCostData = null;
apiRoleData = null;
apiCountryData = null;
apiUserData = null;
apiCostData = null;
apiRoleData = null;
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
/// Now this is safe here
try {
final extraData = GoRouterState.of(context).extra;
if (extraData != null && extraData is Map<String, dynamic>) {
setState(() {
apiselectedUser = extraData['selectedUser'] as Map<String, dynamic>?;
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
updateData();
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
/// Now this is safe here
try {
final extraData = GoRouterState.of(context).extra;
if (extraData != null && extraData is Map<String, dynamic>) {
setState(() {
apiselectedUser =
extraData['selectedUser'] as Map<String, dynamic>?;
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
updateData();
}
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
} else {
apiService.logout(context);
}
}
void _checkAuthAndLoadData22() async {
@ -507,7 +514,7 @@ class _CreateTravelAgentFormDetialsState
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -518,7 +525,7 @@ class _CreateTravelAgentFormDetialsState
Future<void> fetchDepartment() async {
try {
List<dynamic> department = await apiService.fetchCostCenter();
List<dynamic> department = await apiService.fetchCostCenter(context);
setState(() {
apiCostData = department;
});
@ -529,7 +536,7 @@ class _CreateTravelAgentFormDetialsState
Future<void> fetchUsers() async {
try {
List<dynamic> users = await apiService.fetchUsers();
List<dynamic> users = await apiService.fetchUsers(context);
setState(() {
// apiUserData = users;
@ -552,7 +559,7 @@ class _CreateTravelAgentFormDetialsState
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown();
final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list

View File

@ -66,7 +66,7 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -75,18 +75,22 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
return;
} else {
futureUsers = fetchUsers();
futureUsers.then((users) {
setState(() {
allUsers = users;
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureUsers.then((users) {
setState(() {
allUsers = users;
});
});
});
fetchCountryList();
loadInitialData();
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
// });
fetchCountryList();
loadInitialData();
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
// });
} else {
apiService.logout(context);
}
}
}
@ -140,6 +144,11 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
print('Failed to load users');
return [];
@ -192,6 +201,11 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -836,7 +850,10 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
.getSingleUser(
context,
userId,
);
context.go(
"/CreateTravelAgent",
extra: {
@ -912,7 +929,7 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
.getSingleUser(context, userId);
context.go(
"/CreateTravelAgent",
extra: {

View File

@ -207,6 +207,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
}
final response = await apiService.CheckDuplicate(
context,
label,
field,
value,
@ -252,7 +253,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown();
final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list
@ -274,7 +275,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -287,7 +288,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
try {
print("getUpdatedServices");
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
print("UUPdatedServices - $result");
setState(() {
final servicesRaw = selectedOrg?['services_ids'];
@ -367,7 +368,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
// apiAllServices = result;
setState(() {
@ -814,6 +815,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["FnameFocusNode"],
controller: widget.controllers["Fname"],
enabled: !widget.isViewMode,
@ -868,6 +872,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: focusNodes["LnameFocusNode"],
controller: widget.controllers["Lname"],
@ -915,6 +922,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: focusNodes["CnameFocusNode"],
controller: widget.controllers["Cname"],
@ -1715,6 +1725,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
enabled: !widget.isViewMode,
maxLines: 2,
keyboardType: TextInputType.multiline,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z0-9\s,.\-/#']"),
),
],
decoration: InputDecoration(
labelText: "Address",
labelStyle: GoogleFonts.poppins(

View File

@ -167,6 +167,11 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
print("Response: ${response.body}");
_clearError();
Navigator.of(context).pop();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 404) {
Navigator.of(context).pop();
final message = jsonDecode(response.body)['message'] ?? 'Unknown error';

View File

@ -445,6 +445,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
}
void _checkAuthAndLoadData() async {
final roleUser = await getRoleUser();
setState(() {
isCheckingToken = true;
});
@ -457,44 +458,50 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return;
}
setState(() {
isCheckingToken = false;
});
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
setState(() {
isCheckingToken = false;
});
prepareForNewEntry();
selectedTab = "personal";
prepareForNewEntry();
selectedTab = "personal";
apiCountryData = null;
apiUserData = null;
apiCostData = null;
apiRoleData = null;
apiCountryData = null;
apiUserData = null;
apiCostData = null;
apiRoleData = null;
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
/// Now this is safe here
try {
final extraData = GoRouterState.of(context).extra;
if (extraData != null && extraData is Map<String, dynamic>) {
setState(() {
apiselectedUser = extraData['selectedUser'] as Map<String, dynamic>?;
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
updateData();
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
/// Now this is safe here
try {
final extraData = GoRouterState.of(context).extra;
if (extraData != null && extraData is Map<String, dynamic>) {
setState(() {
apiselectedUser =
extraData['selectedUser'] as Map<String, dynamic>?;
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
updateData();
}
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
} else {
apiService.logout(context);
}
}
void _checkAuthAndLoadData22() async {
@ -597,7 +604,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -608,7 +615,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchDepartment() async {
try {
List<dynamic> department = await apiService.fetchCostCenter();
List<dynamic> department = await apiService.fetchCostCenter(context);
setState(() {
apiCostData = department;
});
@ -619,7 +626,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchUsers() async {
try {
List<dynamic> users = await apiService.fetchUsers();
List<dynamic> users = await apiService.fetchUsers(context);
setState(() {
// apiUserData = users;
@ -642,7 +649,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown();
final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list
@ -1033,7 +1040,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String value,
String? userId,
) {
return apiService.CheckDuplicate(label, field, value, userId)
return apiService.CheckDuplicate(context, label, field, value, userId)
.then((response) {
if (response.isNotEmpty) {
errorMessages[field] =
@ -1345,6 +1352,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("📨 Response: ${response.body}");
await apiService.handleTokenRefresh(context, userId!);
if (roleId == "4") {
context.go('/listPlan');
} else {

File diff suppressed because it is too large Load Diff

View File

@ -256,6 +256,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
// Basic validation: Check mobile number length
final response = await apiService.CheckDuplicate(
context,
label,
field,
value,
@ -315,7 +316,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchUsers() async {
try {
print("Test Users");
List<dynamic> users = await apiService.fetchUsers();
List<dynamic> users = await apiService.fetchUsers(context);
setState(() {
// apiUserData = users;
@ -341,7 +342,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchDepartment() async {
try {
print("Test department");
List<dynamic> department = await apiService.fetchDepartmentCostCenter();
List<dynamic> department = await apiService.fetchDepartmentCostCenter(
context,
);
setState(() {
apiCostData = department;
});
@ -354,7 +357,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchFindGroup() async {
try {
print("Test Groups");
final result = await apiService.fetchAllGroup();
final result = await apiService.fetchAllGroup(context);
setState(() {
apiAllGroups = result;
@ -548,6 +551,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: _employeeCodeFocusNode,
controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode,

View File

@ -247,6 +247,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
}
final response = await apiService.CheckDuplicate(
context,
label,
field,
value,
@ -292,7 +293,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> fetchRoles() async {
try {
final response = await apiService.fetchMasterDropdown();
final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list
@ -312,7 +313,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -325,7 +326,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
try {
print("getUpdatedServices");
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
print("UUPdatedServices - $result");
setState(() {
final servicesRaw = selectedOrg?['services_ids'];
@ -426,7 +427,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Future<void> loadAllServices() async {
try {
final result = await apiService.fetchAllServices();
final result = await apiService.fetchAllServices(context);
setState(() {
// apiAllServices = result;
setState(() {
@ -860,6 +861,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
// focusNode: focusNodes["FnameFocusNode"],
focusNode: _fnameFocusNode, // 👈 Use it here
controller: widget.controllers["Fname"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
autofocus: true,
enabled: !widget.isViewMode,
onChanged: (value) {
@ -909,6 +913,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: _lnameFocusNode,
autofocus: true,
@ -1963,6 +1970,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: _addressFocusNode,
controller: widget.controllers["address"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z0-9\s,.\-/#']"),
),
],
enabled: !widget.isViewMode,
maxLines: 2,
keyboardType: TextInputType.multiline,

View File

@ -138,7 +138,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
Color layoutColor = Colors.grey;
Color? bodyColor;
@override
void initState() {
super.initState();
@ -186,8 +185,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
}
});
_addFocusListener(_iSeatPrefFocusNode, (focus) => _iSeatPrefFocus = focus);
_addFocusListener(_dSeatPrefFocusNode, (focus) => _dSeatPrefFocus = focus);
_addFocusListener(_iSeatPrefFocusNode, (focus) => _iSeatPrefFocus = focus);
_addFocusListener(_dSeatPrefFocusNode, (focus) => _dSeatPrefFocus = focus);
// _addFocusListener(_groupFocusNode, (focus) => _groupFocus = focus);
// _addFocusListener(_firstApprovalFocusNode, (focus) => _firstApprovalFocus = focus);
// _addFocusListener(_secondApprovalFocusNode, (focus) => _secondApprovalFocus = focus);
@ -212,14 +211,14 @@ class TravellerDetailsState extends State<TravellerDetails> {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
}
@ -346,6 +345,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
) async {
try {
final response = await apiService.CheckDuplicate(
context,
label,
field,
value,
@ -871,7 +871,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Future<void> fetchCountries() async {
try {
List<dynamic> countries = await apiService.fetchCountryList();
List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() {
apiCountryData = countries;
});
@ -882,7 +882,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Future<void> fetchHotels() async {
try {
List<dynamic> countries = await apiService.fetchHotelsList();
List<dynamic> countries = await apiService.fetchHotelsList(context);
setState(() {
apiHotelsData = countries;
});
@ -893,7 +893,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Future<void> loadCountryList() async {
final newTripType = "2";
final result = await apiService.fetchAirlineList();
final result = await apiService.fetchAirlineList(context);
// final result = await apiService.fetchFlightsCountryList(newTripType);
print("resultFlight: $result ");
@ -923,7 +923,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Future<void> fetchApiData() async {
try {
final data = await apiService.fetchMasterDropdown();
final data = await apiService.fetchMasterDropdown(context);
print("fetchApiData - $data");
@ -1221,6 +1221,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["FnameFocusNode"],
controller: controllers["Fname"],
enabled: !widget.isViewMode,
@ -1264,6 +1267,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["MnameFocusNode"],
controller: controllers["Mname"],
enabled: !widget.isViewMode,
@ -1310,6 +1316,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["LnameFocusNode"],
controller: controllers["Lname"],
@ -1338,7 +1347,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
List<String> nationalityOptions = [
"Indian",
"International",
"other nationality",
"Other Nationality",
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -1375,84 +1384,89 @@ class TravellerDetailsState extends State<TravellerDetails> {
// Request focus when user taps
focusNodes["nationalityFocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: _selectedTripType,
enabled: !widget.isViewMode,
child: DropdownSearch<String>(
selectedItem: _selectedTripType,
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: false, // Set true if you want search
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
popupProps: PopupProps.menu(
showSearchBox: false, // Set true if you want search
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
),
items: nationalityOptions,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(1),
borderSide: BorderSide(
color:
(focusStates["nationalityFocused"] ?? false)
? (layoutColor)
: Colors.white,
width: 1,
),
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["nationalityFocused"] ?? false)
? (layoutColor)
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 1,
),
),
),
items: nationalityOptions,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(1),
borderSide: BorderSide(
color:
(focusStates["nationalityFocused"] ?? false)
? (layoutColor)
: Colors.white,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["nationalityFocused"] ?? false)
? (layoutColor)
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color : (layoutColor), width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 1,
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (String? newValue) {
setState(() {
_selectedTripType = newValue;
controllers["passportNumber"]?.clear();
print("_selectedTripType - $_selectedTripType");
});
},
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (String? newValue) {
setState(() {
_selectedTripType = newValue;
controllers["passportNumber"]?.clear();
print("_selectedTripType - $_selectedTripType");
});
},
),),),
),
),
),
],
@ -1543,6 +1557,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["placeOfIssueFocusNode"],
controller: controllers["placeOfIssue"],
enabled: !widget.isViewMode,
@ -2041,21 +2058,53 @@ class TravellerDetailsState extends State<TravellerDetails> {
// }
Widget buildPassportDocument() {
void pickPDFWeb() {
// void pickPDFWeb() {
// html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
// uploadInput.accept = '.pdf';
// uploadInput.click();
//
// uploadInput.onChange.listen((e) {
// final file = uploadInput.files!.first;
//
// // Ensure the file is a PDF
// if (!file.type.contains("pdf")) {
// print("Error: Not a PDF file");
// return;
// }
//
// // 🔹 File size check: Ensure it does not exceed 3MB
// int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
// if (file.size > maxFileSize) {
// print('Error: File size exceeds 3MB');
// return;
// }
//
// setState(() {
// selectedFileNames = file.name;
// passportFile = file;
// passportFileUrlFromApi = null;
// });
//
// print('PDF File selected: ${file.name}');
// });
// }
void pickFileWeb() {
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
uploadInput.accept = '.pdf';
// Accept PDFs and common image formats
uploadInput.accept = '.pdf,.jpg,.jpeg,.png';
uploadInput.click();
uploadInput.onChange.listen((e) {
final file = uploadInput.files!.first;
// Ensure the file is a PDF
if (!file.type.contains("pdf")) {
print("Error: Not a PDF file");
// Ensure the file is PDF or image
if (!(file.type.contains("pdf") || file.type.contains("image"))) {
print("Error: Not a PDF or image file");
return;
}
// 🔹 File size check: Ensure it does not exceed 3MB
// File size check: Ensure it does not exceed 3MB
int maxFileSize = 3 * 1024 * 1024; // 3MB in bytes
if (file.size > maxFileSize) {
print('Error: File size exceeds 3MB');
@ -2068,7 +2117,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
passportFileUrlFromApi = null;
});
print('PDF File selected: ${file.name}');
print('File selected: ${file.name}');
});
}
@ -2090,7 +2139,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: GestureDetector(
onTap: pickPDFWeb,
onTap: pickFileWeb,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
alignment: Alignment.centerLeft,
@ -2103,6 +2152,18 @@ class TravellerDetailsState extends State<TravellerDetails> {
),
),
),
SizedBox(height: 5),
Center(
child: Text(
" * Allow types pdf, jpg, jpeg, png and max size 3MB ",
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
SizedBox(height: 10),
if (passportFile != null || passportFileUrlFromApi != null)
// Centers the text
@ -2118,7 +2179,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
children: [
GestureDetector(
onTap: () {
print('DOWNLOAD - $passportFile');
print('DOWNLOAD - $passportFile - ${widget.userIdApi} ');
if (passportFile != null) {
try {
@ -2167,23 +2228,27 @@ class TravellerDetailsState extends State<TravellerDetails> {
}
} else if (passportFileUrlFromApi != null) {
print("Raw file path: $passportFileUrlFromApi");
apiService.getPassportDocDownload(
context,
widget.userIdApi!,
);
// Extract public part of the path starting from "/assets"
String cleanedPath = passportFileUrlFromApi!;
final index = passportFileUrlFromApi!.indexOf("/assets");
if (index != -1) {
cleanedPath = passportFileUrlFromApi!.substring(index);
}
final fullUrl =
'https://apitest.tripapprovaltool.com$cleanedPath';
print("Final download URL: $fullUrl");
final anchor =
html.AnchorElement(href: fullUrl)
..target = '_blank'
..download = selectedFileNames ?? "document.pdf"
..click();
// // Extract public part of the path starting from "/assets"
// String cleanedPath = passportFileUrlFromApi!;
// final index = passportFileUrlFromApi!.indexOf("/assets");
// if (index != -1) {
// cleanedPath = passportFileUrlFromApi!.substring(index);
// }
//
// final fullUrl =
// 'https://apitest.tripapprovaltool.com$cleanedPath';
// print("Final download URL: $fullUrl");
//
// final anchor =
// html.AnchorElement(href: fullUrl)
// ..target = '_blank'
// ..download = selectedFileNames ?? "document.pdf"
// ..click();
} else {
print("No file available to download.");
}
@ -2286,6 +2351,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["local_id_num"],
enabled: !widget.isViewMode,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
_clearError("local_id_num");
},
@ -2423,6 +2491,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
controller: controllers["full_name_as_id"],
enabled: !widget.isViewMode,
onChanged: (value) {
@ -2529,101 +2600,105 @@ class TravellerDetailsState extends State<TravellerDetails> {
// Request focus when user taps
_dSeatPrefFocusNode.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
child: DropdownSearch<Map<String, dynamic>>(
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
child: Text(
item['dropdown_value'] ?? "Select Seat",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_dSeatPrefFocus) ? (layoutColor) : Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_dSeatPrefFocus) ? (layoutColor) : Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor),
width: 0.5,
),
),
hintText: "Select Seat",
hintStyle: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
child: Text(
item['dropdown_value'] ?? "Select Seat",
),
dropdownButtonProps: const DropdownButtonProps(
icon: Icon(Icons.arrow_drop_down),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null ||
selectedItem.isEmpty ||
selectedItem['dropdown_value'].toString().isEmpty) {
return Text(
"Select Seat", // fallback text
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_dSeatPrefFocus)
? (layoutColor)
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_dSeatPrefFocus)
? (layoutColor)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor), width: 0.5),
),
hintText: "Select Seat",
hintStyle: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
);
},
items: seatOptions,
selectedItem:
selectedDomesticSeat == null
? null
: {"dropdown_value": selectedDomesticSeat},
onChanged:
widget.isViewMode
? null
: (Map<String, dynamic>? newItem) {
if (newItem != null) {
setState(() {
selectedDomesticSeat =
newItem['dropdown_value'];
});
}
},
),
),
dropdownButtonProps: const DropdownButtonProps(
icon: Icon(Icons.arrow_drop_down),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null ||
selectedItem.isEmpty ||
selectedItem['dropdown_value'].toString().isEmpty) {
return Text(
"Select Seat", // fallback text
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
);
},
items: seatOptions,
selectedItem:
selectedDomesticSeat == null
? null
: {"dropdown_value": selectedDomesticSeat},
onChanged:
widget.isViewMode
? null
: (Map<String, dynamic>? newItem) {
if (newItem != null) {
setState(() {
selectedDomesticSeat = newItem['dropdown_value'];
});
}
},
),),),
),
),
),
],
@ -2653,6 +2728,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["d_meal_prefFocusNode"],
controller: controllers["d_meal_pref"],
@ -2698,6 +2776,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["d_additonal_Info"],
focusNode: focusNodes["d_additonal_InfoFocusNode"],
@ -2804,102 +2885,105 @@ class TravellerDetailsState extends State<TravellerDetails> {
// Request focus when user taps
_iSeatPrefFocusNode.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
child: DropdownSearch<Map<String, dynamic>>(
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
child: Text(
item['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_iSeatPrefFocus) ? (layoutColor) : Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_iSeatPrefFocus) ? (layoutColor) : Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
),
child: Text(
item['dropdown_value'] ?? 'Select Seat',
),
// selectedItem: purposeList.cast<Map<String, dynamic>>().firstWhere(
// (item) => item['dropdown_key'] == _selectedIsBillable,
// orElse: () => {},
// ),
dropdownButtonProps: const DropdownButtonProps(
icon: Icon(Icons.arrow_drop_down),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null ||
selectedItem.isEmpty ||
selectedItem['dropdown_value'].toString().isEmpty) {
return Text(
"Select Seat", // fallback text
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_iSeatPrefFocus)
? (layoutColor)
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_iSeatPrefFocus)
? (layoutColor)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor), width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
);
},
items: seatOptionsInt,
selectedItem:
selectedIntenationalSeat == null
? null
: {"dropdown_value": selectedIntenationalSeat},
onChanged:
widget.isViewMode
? null
: (Map<String, dynamic>? newItem) {
if (newItem != null) {
setState(() {
selectedIntenationalSeat =
newItem['dropdown_value'];
});
}
},
),
),
// selectedItem: purposeList.cast<Map<String, dynamic>>().firstWhere(
// (item) => item['dropdown_key'] == _selectedIsBillable,
// orElse: () => {},
// ),
dropdownButtonProps: const DropdownButtonProps(
icon: Icon(Icons.arrow_drop_down),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null ||
selectedItem.isEmpty ||
selectedItem['dropdown_value'].toString().isEmpty) {
return Text(
"Select Seat", // fallback text
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
);
},
items: seatOptionsInt,
selectedItem:
selectedIntenationalSeat == null
? null
: {"dropdown_value": selectedIntenationalSeat},
onChanged:
widget.isViewMode
? null
: (Map<String, dynamic>? newItem) {
if (newItem != null) {
setState(() {
selectedIntenationalSeat =
newItem['dropdown_value'];
});
}
},
),),),
),
),
),
],
@ -2928,7 +3012,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["i_meal_pref"],
focusNode: focusNodes["i_meal_prefFocusNode"],
@ -2974,6 +3062,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["i_additonal_Info"],
focusNode: focusNodes["i_additonal_InfoFocusNode"],
@ -3200,7 +3291,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
widget.isViewMode
? null
: () async {
focusNodes["forex_expiry_dateFocusNode"]?.requestFocus();
focusNodes["forex_expiry_dateFocusNode"]
?.requestFocus();
await _selectExpiryDate(context);
},
child: AbsorbPointer(
@ -3568,6 +3660,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: entry["controller_flier_number"],
enabled: !widget.isViewMode,
@ -3832,6 +3927,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: entry["controller_membership"],
enabled: !widget.isViewMode,
@ -3884,7 +3982,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
" * confirm your passport is valid for next 6 months",
" * Confirm your passport is valid for next 6 months ",
style: GoogleFonts.poppins(fontSize: 10),
),
IconForVisa(),

View File

@ -51,7 +51,7 @@ class _UserListScreenState extends State<UserListScreen> {
@override
void initState() {
super.initState();
// futureUsers = fetchUsers();
futureUsers = fetchUsers();
//
// futureUsers.then((users) {
// setState(() {
@ -63,12 +63,13 @@ class _UserListScreenState extends State<UserListScreen> {
// fetchCountryList();
// loadInitialData();
// });
_checkAuthAndLoadData();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
@ -76,15 +77,20 @@ class _UserListScreenState extends State<UserListScreen> {
); // or use: router.go("/") if you're using `GoRouter` directly
return;
} else {
futureUsers = fetchUsers();
if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
futureUsers = fetchUsers();
futureUsers.then((users) {
setState(() {
allUsers = users;
futureUsers.then((users) {
setState(() {
allUsers = users;
});
});
});
fetchCountryList();
loadInitialData();
fetchCountryList();
loadInitialData();
} else {
apiService.logout(context);
}
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
@ -139,6 +145,11 @@ class _UserListScreenState extends State<UserListScreen> {
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 apiService.logout(context);
return [];
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load users');
}
@ -189,6 +200,11 @@ class _UserListScreenState extends State<UserListScreen> {
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load plans');
}
@ -464,7 +480,7 @@ class _UserListScreenState extends State<UserListScreen> {
}
Future<void> handleDownload() async {
final result = await apiService.getDownloadUserTemplateForUpload();
final result = await apiService.getDownloadUserTemplateForUpload(context);
final String displayBackgroundColor =
result['status'] ? '#28a745' : '#dc1c13';
@ -985,7 +1001,7 @@ class _UserListScreenState extends State<UserListScreen> {
),
tooltip: 'Sample Template Download',
onPressed: () {
apiService.getDownloadUserTemplateForUpload();
apiService.getDownloadUserTemplateForUpload(context);
},
),
SizedBox(width: 5),
@ -1354,7 +1370,10 @@ class _UserListScreenState extends State<UserListScreen> {
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
.getSingleUser(
context,
userId,
);
context.go(
"/CreateUserDetails",
extra: {
@ -1611,7 +1630,7 @@ class _UserListScreenState extends State<UserListScreen> {
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
.getSingleUser(context, userId);
context.go(
"/CreateUserDetails",
extra: {

View File

@ -34,8 +34,9 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// SemanticsBinding.instance
// .ensureSemantics(); // -only for testing uncomment, Otherwise Email Template wont allow to type
// .ensureSemantics(); // -NOTE:only for testing uncomment, Otherwise Email Template wont allow to type
if (kIsWeb) {
final uri = Uri.parse(html.window.location.href);
print("URI - $uri");
@ -191,7 +192,7 @@ class _MyAppState extends State<MyApp> {
print("MicroSoft UserData ROLE FECTHED - $userRole");
}
print("MicroSoft Started");
await apiService.getOrganizationData();
await apiService.getOrganizationData(context);
print("MicroSoft end");
} catch (e) {
print('Error decoding token MS: $e');

View File

@ -1,5 +1,7 @@
//api url
//---- NOTE : RELEASE 29 OCT 2025 - Except AUJAS LIVE EVERYTHING MOVED ---
/** Note : TSTAT TEST BE URL
* incase "adfactor" or "aujas" href means changed to "tstat"
* File : web/index.html - change below

View File

@ -1,9 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:http/http.dart' as http;
import 'app.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void main() {
// setUrlStrategy(PathUrlStrategy());
// await fetchAllApiStatuses();
runApp(const MyApp());
}
// Future<void> fetchAllApiStatuses() async {
// final res = await http.get(Uri.parse('https://example.com/api'));
// print("API status: ${res.statusCode}");
// ApiStatusCache.latestStatus = res.statusCode;
// }

View File

@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:frontend/config/apiUrl.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart'; // don't forget
import '../services/apiService.dart';
import '../utils/auth_utils.dart';
@ -37,6 +40,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
late TabSelection selectedTab;
final ImagePicker _picker = ImagePicker();
String? token;
Map<String, dynamic>? userData;
Map<String, dynamic>? fetchedUserData;
@ -48,6 +53,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
Color? layoutColor = Colors.white10;
Color? bodyColor;
File? _pickedImageFile;
String? _errorMessage;
void initState() {
super.initState();
// initializeData();
@ -74,7 +82,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
userIdRaw is int ? userIdRaw : int.tryParse(userIdRaw.toString());
if (userId != null) {
profileUserDetails = await apiService.getSingleUser(userId);
profileUserDetails = await apiService.getSingleUser(context, userId);
print("getProfileUser-$profileUserDetails");
} else {
print("❌ Invalid user_id: $userIdRaw");
@ -104,6 +112,14 @@ class _CustomAppBarState extends State<CustomAppBar> {
return prefs.getString("auth_token");
}
bool isValidImageUrl(String? url) {
if (url == null) return false;
final lowerUrl = url.toLowerCase();
return lowerUrl.endsWith('.jpg') ||
lowerUrl.endsWith('.jpeg') ||
lowerUrl.endsWith('.png');
}
Future<Map<String, dynamic>?> getUserData() async {
final prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data');
@ -194,7 +210,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
try {
print("getUpdatedServices");
final result = await apiService.fetchOrganization();
final result = await apiService.fetchOrganization(context);
final prefs = await SharedPreferences.getInstance();
print("UUPdatedServices - $result");
@ -291,15 +307,15 @@ class _CustomAppBarState extends State<CustomAppBar> {
}
Future<void> logout(BuildContext context) async {
// Clear localStorage
final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // Clears all keys
await apiService.logout(context);
// Optional: clear sessionStorage if used
// html.window.sessionStorage.clear();
// Navigate to login or home page
context.go('/');
// 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('/');
}
void _handleBackButton() {

View File

@ -17,6 +17,7 @@ import 'package:frontend/Screens/userManagement/user_List.dart';
import 'package:frontend/routes/organizationSetting.dart';
import 'package:go_router/go_router.dart';
import 'package:responsive_builder/responsive_builder.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../Screens/allTrips/list_all_plans.dart';
import '../Screens/allTrips/travel_agent_list.dart';
@ -43,9 +44,27 @@ import '../Screens/reports/misForex.dart';
import '../Screens/reports/guestHouse.dart';
import '../Screens/userManagement/create_traveller_agent/listTravelAgent.dart';
import '../utils/auth_utils.dart';
import 'mainLayout.dart';
// class AuthState extends ChangeNotifier {
// String? role;
//
// Future<void> loadRole() async {
// final prefs = await SharedPreferences.getInstance();
// final userData = prefs.getString('user_data');
// if (userData != null) {
// final decoded = jsonDecode(userData);
// role = decoded["role"];
// notifyListeners();
// }
// }
// }
//
// final authState = AuthState();
final GoRouter router = GoRouter(
// refreshListenable: authState,
routes: [
// Public routes without app bar
GoRoute(path: '/', builder: (context, state) => LoginPage()),
@ -65,7 +84,7 @@ final GoRouter router = GoRouter(
// );
},
routes: [
GoRoute(path: '/home', builder: (context, state) => HomePage()),
// GoRoute(path: '/home', builder: (context, state) => HomePage()),
GoRoute(
path: '/listAllPlan',
builder: (context, state) => ListAllPlans(),
@ -148,6 +167,13 @@ final GoRouter router = GoRouter(
path: '/statusdashboard',
builder: (context, state) => StatusDashboard(),
),
GoRoute(
path: '/unauthorized',
builder:
(context, state) =>
const Scaffold(body: Center(child: Text("🚫 Access Denied"))),
),
GoRoute(
path: '/traveller',
builder: (context, state) => TravellerList(),
@ -194,100 +220,30 @@ final GoRouter router = GoRouter(
],
),
],
// redirect: (context, state) async {
// print('Check REDIRECTION');
// final apiStatus = ApiStatusCache.latestStatus;
//
// print('Check apiStatus - $apiStatus');
// return null;
// if (apiStatus == 404) return '/';
// return null;
// final role = await getRoleUser(); // async not allowed here per-route
// print('Check REDIRECTION');
// print('getRoleUser1 - $role');
// // for top-level GoRouter, you can use async redirect
// if (role == null) return '/'; // not logged in
// if (state.matchedLocation == '/statusdashboard' &&
// role != 'Org Admin' &&
// role != 'Travel Admin') {
// return '/unauthorized';
// }
// return null; //
// },
);
// final GoRouter router = GoRouter(
// routes: [
// GoRoute(path: '/', builder: (context, state) => LoginPage()),
// // GoRoute(
// // path: '/authredirection',
// // builder: (context, state) {
// // final code = state.uri.queryParameters['code'];
// // return MicrosoftPage(code: code);
// // },
// // ),
// GoRoute(path: '/home', builder: (context, state) => HomePage()),
// GoRoute(path: '/listAllPlan', builder: (context, state) => ListAllPlans()),
// GoRoute(
// path: '/listTravelAgentPlan',
// builder: (context, state) => TravelAgentListPlans(),
// ),
// GoRoute(path: '/listPlan', builder: (context, state) => ListPlans()),
// GoRoute(path: '/createPlan', builder: (context, state) => CreatePlan()),
// GoRoute(path: '/allTrips/trips', builder: (context, state) => CreatePlan()),
// GoRoute(path: '/approver/plans', builder: (context, state) => CreatePlan()),
// GoRoute(path: '/listUser', builder: (context, state) => UserListScreen()),
// GoRoute(
// path: '/CreateUserDetails',
// builder: (context, state) => CreateUserFormDetials(),
// // builder: (context, state) {
// // final userParam = state.uri.queryParameters['user'];
// //
// // final isEditProfile =
// // state.uri.queryParameters['isEditProfile'] == 'true';
// // final isViewMode = state.uri.queryParameters['isViewMode'] == 'true';
// //
// // final user = userParam != null
// // ? jsonDecode(Uri.decodeComponent(userParam))
// // : null;
// //
// // return CreateUserForm(
// // apiselectedUser: user,
// // isEditProfile: isEditProfile,
// // isViewMode: isViewMode,
// // );
// // }
// ),
// GoRoute(
// path: '/Policy',
// // builder: (context, state) => Policy(),
// pageBuilder:
// (context, state) => MaterialPage(child: Policy.fromState(state)),
// ),
// GoRoute(path: '/PolicyList', builder: (context, state) => PolicyList()),
// GoRoute(
// path: '/OrganizationSetup',
// builder: (context, state) => OrgSetUp(),
// ),
// GoRoute(
// path: '/OrganizationSettings',
// builder: (context, state) => OrganizationSetting(),
// ),
// GoRoute(path: '/group', builder: (context, state) => GroupList()),
// GoRoute(path: '/getPerdiem', builder: (context, state) => ForexDataList()),
// GoRoute(
// path: '/templateList',
// builder: (context, state) => TemplatesList(),
// ),
// // GoRoute(
// // path: '/template',
// // builder: (context, state) => MyHomePage(),
// // ),
// GoRoute(
// path: '/template',
// // builder: (context, state) => Template(),
// pageBuilder:
// (context, state) => MaterialPage(child: Template.fromState(state)),
// ),
// GoRoute(
// path: '/templateForex',
// pageBuilder:
// (context, state) =>
// MaterialPage(child: TemplateForex.fromState(state)),
// ),
// GoRoute(path: '/approvallist', builder: (context, state) => ApprovalList()),
// GoRoute(path: '/department', builder: (context, state) => DepartmentList()),
// GoRoute(path: '/costcenter', builder: (context, state) => CostCenterList()),
// GoRoute(path: '/hotels', builder: (context, state) => HotelsDataList()),
// GoRoute(
// path: '/statusdashboard',
// builder: (context, state) => StatusDashboard(),
// ),
// GoRoute(path: '/traveller', builder: (context, state) => TravellerList()),
// GoRoute(
// path: '/CreateGroup',
// pageBuilder:
// (context, state) => MaterialPage(child: Group.fromState(state)),
// ),
// ],
// );
class ApiStatusCache {
static int? latestStatus;
}

View File

@ -36,26 +36,31 @@ class OrganizationSettingState extends State<OrganizationSetting> {
// String? bodyStringColor = await getBodyColor();
roleUser = await getRoleUser();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
if (roleUser == 'Org Admin' || roleUser == 'Travel Admin') {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
} else {
apiService.logout(context);
}
}
@override

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,8 @@ Future<String?> getRoleUser() async {
final prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data');
print('getRoleUser');
// print("UserDataSTr - $userDataString");
if (userDataString != null) {

View File

@ -6,6 +6,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import '../config/apiUrl.dart';
import '../services/apiService.dart';
class CommentModal extends StatefulWidget {
final String planId;
@ -32,6 +33,8 @@ class CommentModalState extends State<CommentModal> {
bool editRemarks = false;
TextEditingController commentController = TextEditingController();
final ApiService apiService = ApiService();
// Map<String, dynamic> getData() {
// final map = {
// "plan_id": int.parse(widget.planId),
@ -74,12 +77,14 @@ class CommentModalState extends State<CommentModal> {
role = await getRoleUser();
print("Role - $role");
print("RoleuserId - $userId");
userId = int.tryParse(userIdString);
if (userId == null) {
throw Exception('Invalid user ID format.');
}
// if (role != null && (role == 'Org Admin' || role == 'Travel Admin' || role == )) {
final data = await getRemarks(userId);
setState(() {
@ -89,6 +94,9 @@ class CommentModalState extends State<CommentModal> {
});
print("Remarks -");
print("Remarks - ${jsonEncode(remarksData)}");
// } else {
// apiService.logout(context);
// }
} catch (e) {
setState(() {
errorMessage = e.toString();
@ -148,6 +156,11 @@ class CommentModalState extends State<CommentModal> {
);
}
return data['data'];
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
// throw Exception('Failed to load users');
} else {
throw Exception('Failed to load remarks');
}
@ -195,6 +208,11 @@ class CommentModalState extends State<CommentModal> {
if (response.statusCode == 200) {
print("Plan submitted successfully!");
print("Response: ${response.body}");
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");

View File

@ -45,7 +45,7 @@ class PlanPopupMenu extends StatelessWidget {
icon: Icon(Icons.remove_red_eye, size: 18),
onPressed: () {
Navigator.pop(context);
ApiService.viewPlan(
ApiService().viewPlan(
context,
plan.planId,
isViewMode: true,
@ -77,7 +77,7 @@ class PlanPopupMenu extends StatelessWidget {
),
onPressed: () {
Navigator.pop(context);
apiService.getPdfDownload(plan.planId);
apiService.getPdfDownload(context,plan.planId);
},
),
@ -93,7 +93,7 @@ class PlanPopupMenu extends StatelessWidget {
tooltip: 'Download Forex PDF',
onPressed: () {
Navigator.pop(context);
apiService.getPdfDownload(plan.forexId);
apiService.getPdfDownload(context,plan.forexId);
},
),
IconButton(

View File

@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.7.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024"
url: "https://pub.dev"
source: hosted
version: "1.6.5"
async:
dependency: transitive
description:
@ -209,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.8.5+1"
encrypt:
dependency: "direct main"
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
fake_async:
dependency: transitive
description:
@ -813,6 +829,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
pool:
dependency: transitive
description:

View File

@ -65,6 +65,7 @@ dependencies:
flutter_launcher_icons: ^0.14.4
dotted_border: ^3.1.0
flutter_riverpod: ^3.0.0
encrypt: ^5.0.3