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 { Future<List<Plan>> fetchPlans() async {
late String apiUrldata; 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") { // if (roleUser == "Org Admin") {
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId'; // apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
@ -231,6 +232,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
// List<dynamic> plansJson = []; // List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data']; List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList(); 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 { } else {
throw Exception('Failed to load plans'); throw Exception('Failed to load plans');
} }
@ -264,6 +270,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
print("Plan Deleted successfully!"); print("Plan Deleted successfully!");
print("Response: ${response.body}"); print("Response: ${response.body}");
initializeData(); initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else { } else {
print("Failed to submit plan. Status: ${response.statusCode}"); print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}"); 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( bool confirmed = await apiService.showCancelConfirmationDialog(
context, context,
layoutColor, layoutColor,
@ -281,7 +292,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
if (confirmed) { if (confirmed) {
try { try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId); Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData"); print("ViewAAA - $planData");
refresh(); refresh();
// postPlanData(planData, planId); // postPlanData(planData, planId);
@ -321,6 +336,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
approverData = List<Map<String, dynamic>>.from( approverData = List<Map<String, dynamic>>.from(
data['data']['approver_data'] ?? [], 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 { } else {
print('Failed to load'); print('Failed to load');
label = "Error - Failed to load data"; label = "Error - Failed to load data";
@ -1071,7 +1091,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1095,7 +1115,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1117,6 +1137,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
); );
deletePlan( deletePlan(
plan.planId, plan.planId,
userId,
); );
}, },
), ),
@ -1137,6 +1158,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
); );
apiService apiService
.getPdfDownload( .getPdfDownload(
context,
plan.planId, plan.planId,
); );
}, },
@ -1162,10 +1184,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getForexPdfDownload(
.getForexPdfDownload( context,
plan.forexId, plan.forexId,
); );
}, },
), ),
IconButton( IconButton(
@ -1389,7 +1411,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1414,7 +1436,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1436,6 +1458,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
); );
deletePlan( deletePlan(
plan.planId, plan.planId,
userId,
); );
}, },
), ),
@ -1454,10 +1477,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getPdfDownload(
.getPdfDownload( context,
plan.planId, plan.planId,
); );
}, },
), ),
@ -1482,10 +1505,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getForexPdfDownload(
.getForexPdfDownload( context,
plan.forexId, 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:flutter/material.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -22,6 +23,7 @@ class TripInformation extends StatefulWidget {
} }
class _TripInformationState extends State<TripInformation> { class _TripInformationState extends State<TripInformation> {
final ApiService apiService = ApiService();
late Future<Map<String, dynamic>> _tripInfoFuture; late Future<Map<String, dynamic>> _tripInfoFuture;
Future<Map<String, dynamic>> fetchComments() async { Future<Map<String, dynamic>> fetchComments() async {
@ -48,6 +50,11 @@ class _TripInformationState extends State<TripInformation> {
final Map<String, dynamic> dataMap = final Map<String, dynamic> dataMap =
jsonData['data'] as Map<String, dynamic>; jsonData['data'] as Map<String, dynamic>;
return dataMap; return dataMap;
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return {};
// throw Exception('Failed to load users');
} else { } else {
throw Exception('Failed to load comments'); throw Exception('Failed to load comments');
} }
@ -136,14 +143,17 @@ class _TripInformationState extends State<TripInformation> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
keyValueRow("Action", item["action"]), keyValueRow("Action", item["action"] ?? '-'),
keyValueRow("Approver", item["approver"]), keyValueRow("Approver", item["approver"] ?? '-'),
keyValueRow( keyValueRow(
"Is Action Done", "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 'package:intl/intl.dart';
import '../../config/apiUrl.dart'; import '../../config/apiUrl.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart'; import '../../utils/auth_utils.dart';
class CommentModalList extends StatefulWidget { class CommentModalList extends StatefulWidget {
@ -24,6 +25,7 @@ class CommentModalList extends StatefulWidget {
} }
class _CommentModalListState extends State<CommentModalList> { class _CommentModalListState extends State<CommentModalList> {
final ApiService apiService = ApiService();
late Future<List<Map<String, dynamic>>> _commentsFuture; late Future<List<Map<String, dynamic>>> _commentsFuture;
// Future<List<Map<String, dynamic>>> fetchComments1() async { // Future<List<Map<String, dynamic>>> fetchComments1() async {
@ -68,6 +70,11 @@ class _CommentModalListState extends State<CommentModalList> {
final jsonData = json.decode(response.body); final jsonData = json.decode(response.body);
final List<dynamic> dataList = jsonData['data']; final List<dynamic> dataList = jsonData['data'];
return dataList.cast<Map<String, dynamic>>(); 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 { } else {
throw Exception('Failed to load comments'); throw Exception('Failed to load comments');
} }

View File

@ -1,5 +1,7 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:core'; import 'dart:core';
import 'dart:html' as html;
import 'package:frontend/Screens/allTrips/plan_info_mdl.dart'; import 'package:frontend/Screens/allTrips/plan_info_mdl.dart';
import 'package:frontend/data/models/plan.dart'; import 'package:frontend/data/models/plan.dart';
import 'package:frontend/utils/travelAgent_remarks.dart'; import 'package:frontend/utils/travelAgent_remarks.dart';
@ -29,6 +31,7 @@ class TravelAgentListPlans extends StatefulWidget {
class _TravelAgentListPlansState extends State<TravelAgentListPlans> { class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late StreamSubscription<html.PopStateEvent> _popStateListener;
int currentPage = 0; int currentPage = 0;
int itemsPerPage = 10; int itemsPerPage = 10;
@ -39,6 +42,8 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
String? token; String? token;
String? TripPlanAction; String? TripPlanAction;
late bool _dialogShown = false;
Color? layoutColor; Color? layoutColor;
Color? bodyColor; Color? bodyColor;
late Future<List<Plan>> futurePlans; late Future<List<Plan>> futurePlans;
@ -50,6 +55,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData(); _checkAuthAndLoadData();
checkbackbutton();
// getToken(); // getToken();
// //
// WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
@ -82,6 +88,81 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
loadInitialData(); 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) { void filterPlans(String query) {
print("allPlans before filtering: $allPlans"); print("allPlans before filtering: $allPlans");
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
@ -221,6 +302,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
// List<dynamic> plansJson = []; // List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data']; List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList(); 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 { } else {
throw Exception('Failed to load plans'); throw Exception('Failed to load plans');
} }
@ -254,6 +340,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
print("Plan Deleted successfully!"); print("Plan Deleted successfully!");
print("Response: ${response.body}"); print("Response: ${response.body}");
initializeData(); initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else { } else {
print("Failed to submit plan. Status: ${response.statusCode}"); print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
@ -271,7 +362,11 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
if (confirmed) { if (confirmed) {
try { try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId); Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData"); print("ViewAAA - $planData");
refresh(); refresh();
// postPlanData(planData, planId); // postPlanData(planData, planId);
@ -839,12 +934,13 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlanTravelAgent( ApiService()
context, .viewPlanTravelAgent(
plan.planId, context,
isViewMode: plan.planId,
true, isViewMode:
); true,
);
}, },
), ),
// IconButton( // IconButton(
@ -888,6 +984,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
); );
apiService apiService
.getPdfDownload( .getPdfDownload(
context,
plan.planId, plan.planId,
); );
}, },
@ -915,6 +1012,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
); );
apiService apiService
.getForexPdfDownload( .getForexPdfDownload(
context,
plan.forexId, plan.forexId,
); );
}, },

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -40,6 +40,7 @@ class StatusDashboardState extends State<StatusDashboard> {
List<int> flightData = []; List<int> flightData = [];
List<int> accommodationData = []; List<int> accommodationData = [];
List<int> forexData = []; List<int> forexData = [];
final ApiService apiService = ApiService();
final categoryIcons = { final categoryIcons = {
"flight": Icons.flight, "flight": Icons.flight,
@ -96,8 +97,10 @@ class StatusDashboardState extends State<StatusDashboard> {
_dialogShown = true; _dialogShown = true;
final parentContext = context; // <-- save parent context
showDialog( showDialog(
context: context, context: parentContext,
builder: builder:
(context) => AlertDialog( (context) => AlertDialog(
title: Text("Confirm"), title: Text("Confirm"),
@ -105,16 +108,20 @@ class StatusDashboardState extends State<StatusDashboard> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.pop(context); // Close dialog Navigator.pop(parentContext); // Close dialog
_dialogShown = false; _dialogShown = false;
}, },
child: Text("Cancel"), child: Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
Navigator.pop(context); // Close dialog // Navigator.pop(parentContext); // Close dialog
_dialogShown = false; _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"), 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 { Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue _logoutAndRedirect");
// Navigator.pop(context); // closes dialog
_dialogShown = false;
print("logue 0"); print("logue 0");
await apiService.logout(context);
// Example: clear session or shared preferences // Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // await prefs.clear();
context.go("/"); // context.go("/");
print("logue 1"); print("logue 1");
} }
@ -214,6 +259,11 @@ class StatusDashboardState extends State<StatusDashboard> {
final apiData = json.decode(response.body); final apiData = json.decode(response.body);
print("Fetch StatusDashboard -- Reponse Here : $apiData"); print("Fetch StatusDashboard -- Reponse Here : $apiData");
return apiData; // Returning raw JSON list 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 { } else {
throw Exception('Failed to load users'); throw Exception('Failed to load users');
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@ import 'dart:async';
import 'dart:io' as io show Directory, File; import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart'; import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom; import 'package:flutter/cupertino.dart' as dom;
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text; import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text; import 'package:flutter_quill/flutter_quill.dart' hide Text;
@ -150,13 +151,19 @@ class TemplateForexState extends State<TemplateForex> {
} }
if (!mounted) return; if (!mounted) return;
try { try {
for (var field in dataHeader) { final roleUser = await getRoleUser();
controllers[field] = TextEditingController(); if (roleUser != null &&
} (roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
updateData(); updateData();
loadinitializeData(); loadinitializeData();
loadInitialData(); loadInitialData();
} else {
apiService.logout(context);
}
} catch (e) { } catch (e) {
print("group : $e"); print("group : $e");
} }
@ -471,6 +478,11 @@ class TemplateForexState extends State<TemplateForex> {
selectedOrglogo = rawLogoPath; selectedOrglogo = rawLogoPath;
}); });
} }
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else { } else {
print("❌ Failed to fetch signature: ${response.statusCode}"); print("❌ Failed to fetch signature: ${response.statusCode}");
} }
@ -538,6 +550,11 @@ class TemplateForexState extends State<TemplateForex> {
setState(() { setState(() {
isDisable = false; isDisable = false;
}); });
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else { } else {
print("Failed to submit policyData. Status: ${response.statusCode}"); print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
@ -561,6 +578,15 @@ class TemplateForexState extends State<TemplateForex> {
if (pickedFile != null && kIsWeb) { if (pickedFile != null && kIsWeb) {
try { 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(); final bytes = await pickedFile.readAsBytes();
print('✅ Image loaded, size: ${bytes.length} bytes'); print('✅ Image loaded, size: ${bytes.length} bytes');
setState(() { setState(() {
@ -744,6 +770,9 @@ class TemplateForexState extends State<TemplateForex> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["subjectFocusNode"], focusNode: focusNodes["subjectFocusNode"],
controller: controllers["subject"], controller: controllers["subject"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) { onChanged: (value) {
// _clearError("local_id_num"); // _clearError("local_id_num");
}, },
@ -776,7 +805,7 @@ class TemplateForexState extends State<TemplateForex> {
// color: Color(0xFF575A74), // color: Color(0xFF575A74),
// ), // ),
// ), // ),
const SizedBox(height: 10), // const SizedBox(height: 10),
Container( Container(
color: Color(0xFFFFFEF0), color: Color(0xFFFFFEF0),
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null, 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( Container(
child: Row( child: Column(
// mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Row(
"Upload Signature", // mainAxisAlignment: MainAxisAlignment.end,
style: GoogleFonts.poppins(fontSize: 11.5), children: [
), Text(
SizedBox(width: 5), "Upload Signature",
GestureDetector( style: GoogleFonts.poppins(fontSize: 11.5),
onTap: _pickImage, ),
SizedBox(width: 5),
GestureDetector(
onTap: _pickImage,
child: child:
_imageBytes != null _imageBytes != null
? ClipOval( ? ClipOval(
child: Image.memory( child: Image.memory(
_imageBytes!, _imageBytes!,
// width: 50, // width: 50,
// height: 50, // height: 50,
width: 50, // Use responsive width width: 50, // Use responsive width
height: 50, height: 50,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
) )
: selectedOrglogo != null : selectedOrglogo != null
? ClipRect( ? ClipRect(
child: Image.network( child: Image.network(
selectedOrglogo!, selectedOrglogo!,
width: 50, // Use responsive width width: 50, // Use responsive width
height: 50, height: 50,
// width: 250, // width: 250,
// height: 55, // height: 55,
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
return const CircleAvatar( return const CircleAvatar(
radius: 20, radius: 20,
backgroundColor: Colors.redAccent, backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10), child: Icon(Icons.error, size: 10),
); );
}, },
), ),
) )
: const CircleAvatar( : const CircleAvatar(
radius: 20, radius: 20,
backgroundColor: Colors.amber, backgroundColor: Color(0xFFFFFAA0),
child: Icon(Icons.add_a_photo, size: 10), // 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; if (!mounted) return;
try { try {
futureTemplates = fetchGetForex(); futureTemplates = fetchGetForex();
final roleUser = await getRoleUser();
futureTemplates?.then((users) { if (roleUser != null &&
setState(() { (roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
allTemplate = users; futureTemplates?.then((users) {
print("AlL tEMPLATESNIT - $allTemplate"); setState(() {
allTemplate = users;
print("AlL tEMPLATESNIT - $allTemplate");
});
}); });
});
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
}); });
} else {
apiService.logout(context);
}
} catch (e) { } catch (e) {
print("group : $e"); print("group : $e");
} }
@ -187,6 +192,11 @@ class TemplatesListState extends State<TemplatesList> {
print("TemplateDATA--- $data"); print("TemplateDATA--- $data");
return data['data']; // Returning raw JSON list 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 { } else {
throw Exception('Failed to load users'); throw Exception('Failed to load users');
} }
@ -774,7 +784,10 @@ class TemplatesListState extends State<TemplatesList> {
if (templateId != null) { if (templateId != null) {
print("templateId -- $templateId"); print("templateId -- $templateId");
final data = await apiService final data = await apiService
.getTemplateFind(templateId); .getTemplateFind(
context,
templateId,
);
print("ForexId -- $data"); print("ForexId -- $data");
context.go( context.go(
@ -834,7 +847,10 @@ class TemplatesListState extends State<TemplatesList> {
UserActionsMenu( UserActionsMenu(
user: forex, user: forex,
getUserDetails: getUserDetails:
(id) => apiService.getSingleUser(id), (id) => apiService.getSingleUser(
context,
id,
),
), ),
], ],
), ),

View File

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

View File

@ -1,7 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/organization/mailSettings.dart'; import 'package:frontend/Screens/organization/mailSettings.dart';
import 'package:frontend/Screens/organization/themeColor.dart'; import 'package:frontend/Screens/organization/themeColor.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -68,7 +70,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
void _checkAuthAndLoadData() async { void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) { if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login // Token doesn't exist → redirect to login
context.go( context.go(
@ -76,10 +78,14 @@ class _OrgSetUpState extends State<OrgSetUp> {
); // or use: router.go("/") if you're using `GoRouter` directly ); // or use: router.go("/") if you're using `GoRouter` directly
return; return;
} }
loadAllServices(); if (roleUser != null && (roleUser == 'Org Admin')) {
getOrganizationData(); loadAllServices();
initializeData(); getOrganizationData();
loadInitialData(); initializeData();
loadInitialData();
} else {
apiService.logout(context);
}
} }
void loadInitialData() async { void loadInitialData() async {
@ -143,7 +149,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
Future<void> loadAllServices() async { Future<void> loadAllServices() async {
try { try {
final result = await apiService.fetchAllServices(); final result = await apiService.fetchAllServices(context);
setState(() { setState(() {
apiAllServices = result; apiAllServices = result;
}); });
@ -384,7 +390,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
if (response.statusCode == 200 || response.statusCode == 201) { if (response.statusCode == 200 || response.statusCode == 201) {
print("✅ User submitted successfully!"); print("✅ User submitted successfully!");
print("📨 Response Organizt Update: ${response.body}"); print("📨 Response Organizt Update: ${response.body}");
await apiService.handleTokenRefresh(context, userId!);
final data = json.decode(response.body); final data = json.decode(response.body);
if (!data.containsKey('data') || data['data'] is! Map) { if (!data.containsKey('data') || data['data'] is! Map) {
@ -400,7 +406,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
print(orgList); print(orgList);
await updateOrgDataWithNewValues(orgList); await updateOrgDataWithNewValues(orgList);
await apiService.handleTokenRefresh(userId!);
print("📨 Response Organizt Update:"); print("📨 Response Organizt Update:");
// return orgList; // return orgList;
context.go('/OrganizationSettings'); context.go('/OrganizationSettings');
@ -540,15 +546,13 @@ class _OrgSetUpState extends State<OrgSetUp> {
} }
Future<void> logout(BuildContext context) async { Future<void> logout(BuildContext context) async {
// Clear localStorage await apiService.logout(context);
final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // Clears all keys
// Optional: clear sessionStorage if used // Optional: clear sessionStorage if used
// html.window.sessionStorage.clear(); // html.window.sessionStorage.clear();
// Navigate to login or home page // Navigate to login or home page
context.go('/'); // context.go('/');
} }
@override @override
@ -654,6 +658,45 @@ class _OrgSetUpState extends State<OrgSetUp> {
Future<void> _pickImage() async { Future<void> _pickImage() async {
final picker = ImagePicker(); 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( final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery, source: ImageSource.gallery,
); );
@ -774,7 +817,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
Expanded( Expanded(
child: TextFormField( child: TextFormField(
controller: _orgNameController, controller: _orgNameController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, fontSize: 16,
color: Color(0xFF114D8B), color: Color(0xFF114D8B),
@ -789,6 +836,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
FloatingLabelBehavior.never, FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
isDense: true, isDense: true,
// contentPadding: // contentPadding:
// EdgeInsets.symmetric(vertical: 14), // EdgeInsets.symmetric(vertical: 14),
), ),
@ -796,50 +844,74 @@ class _OrgSetUpState extends State<OrgSetUp> {
), ),
), ),
Spacer(), Spacer(),
GestureDetector( Column(
onTap: _pickImage, children: [
GestureDetector(
onTap: _pickImage,
child: child:
_imageBytes != null _imageBytes != null
? ClipOval( ? ClipOval(
child: Image.memory( child: Image.memory(
_imageBytes!, _imageBytes!,
// width: 50, // width: 50,
// height: 50, // height: 50,
width: width:
responsiveLogoWidth, // Use responsive width responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight, height: responsiveLogoHeight,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
) )
: selectedOrg?['logo'] != null : selectedOrg?['logo'] != null
? ClipRect( ? ClipRect(
child: Image.network( child: Image.network(
selectedOrg!['logo'], selectedOrg!['logo'],
width: width:
responsiveLogoWidth, // Use responsive width responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight, height: responsiveLogoHeight,
// width: 250, // width: 250,
// height: 55, // height: 55,
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: ( errorBuilder: (
context, context,
error, error,
stackTrace, stackTrace,
) { ) {
return const CircleAvatar( return const CircleAvatar(
radius: 20, radius: 20,
backgroundColor: Colors.redAccent, backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10), child: Icon(
); Icons.error,
}, size: 10,
), ),
) );
: const CircleAvatar( },
radius: 20, ),
backgroundColor: Colors.amber, )
child: Icon(Icons.add_a_photo, 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 { Future<void> loadAllOrganization() async {
try { try {
final result = await apiService.fetchOrganization(); final result = await apiService.fetchOrganization(context);
setState(() { setState(() {
apiAllOrganization = result; apiAllOrganization = result;
}); });
@ -54,23 +54,26 @@ class _OrganizationListState extends State<OrganizationList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'), // appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false), // drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Row( body: Row(
children: [ children: [
// if (isDesktop) CustomDrawer(isDesktop: true), // if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(child: buildGroupListLayout(isDesktop)) Expanded(child: buildGroupListLayout(isDesktop)),
], ],
), ),
); );
}); },
);
} }
Widget buildGroupListLayout(bool isDesktop) { Widget buildGroupListLayout(bool isDesktop) {
@ -86,9 +89,10 @@ class _OrganizationListState extends State<OrganizationList> {
children: [ children: [
Row( Row(
children: [ children: [
const Text('Organization List', const Text(
style: 'Organization List',
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton( IconButton(
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
onPressed: () {}, onPressed: () {},
@ -97,21 +101,17 @@ class _OrganizationListState extends State<OrganizationList> {
), ),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor: Colors.blueAccent), backgroundColor: Colors.blueAccent,
),
onPressed: () async { onPressed: () async {
// List<dynamic> users = await futureUsers; // List<dynamic> users = await futureUsers;
// context.go('/CreateGroup'); // context.go('/CreateGroup');
}, },
child: Row( child: Row(
children: [ children: [
Icon( Icon(Icons.add_circle, color: Colors.white),
Icons.add_circle, SizedBox(width: 5),
color: Colors.white,
),
SizedBox(
width: 5,
),
Text('Create Organization'), Text('Create Organization'),
], ],
), ),
@ -127,16 +127,12 @@ class _OrganizationListState extends State<OrganizationList> {
// color: Colors.red.shade100, // color: Colors.red.shade100,
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Column( child: Column(children: [buildGroupListView(isDesktop)]),
children: [
buildGroupListView(isDesktop),
],
),
), ),
), ),
), ),
], ],
) ),
], ],
), ),
); );
@ -169,12 +165,20 @@ class _OrganizationListState extends State<OrganizationList> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Organization Name: ${group['name']}", Text(
style: TextStyle( "Organization Name: ${group['name']}",
fontSize: 13, fontWeight: FontWeight.bold)), style: TextStyle(
Text("Organization Name: ${group['name']}", fontSize: 13,
style: TextStyle( fontWeight: FontWeight.bold,
fontSize: 13, fontWeight: FontWeight.bold)), ),
),
Text(
"Organization Name: ${group['name']}",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
], ],
), ),
SizedBox(height: 4), SizedBox(height: 4),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,7 +59,7 @@ class _ListPlansState extends State<ListPlans> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
print("LSIT PLan -1");
_checkAuthAndLoadData(); _checkAuthAndLoadData();
checkbackbutton(); checkbackbutton();
@ -69,6 +69,7 @@ class _ListPlansState extends State<ListPlans> {
} }
void checkbackbutton() async { void checkbackbutton() async {
print("LSIT PLan -3");
roleUser = await getRoleUser(); roleUser = await getRoleUser();
print(roleUser); print(roleUser);
if (roleUser == "User") { if (roleUser == "User") {
@ -79,10 +80,29 @@ class _ListPlansState extends State<ListPlans> {
print("msUser - $msUser"); print("msUser - $msUser");
html.window.history.pushState(null, '', html.window.location.href); 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) { if (!msUser) {
_popStateListener = html.window.onPopState.listen((event) { _popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) { 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 // Re-push to prevent leaving
@ -99,7 +119,8 @@ class _ListPlansState extends State<ListPlans> {
} }
void _showBackConfirmationDialog() { void _showBackConfirmationDialog() {
if (!mounted) return; print('List planstt');
// if (!mounted) return;
_dialogShown = true; _dialogShown = true;
@ -119,7 +140,7 @@ class _ListPlansState extends State<ListPlans> {
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
Navigator.pop(context); // Close dialog // Navigator.pop(context); // Close dialog
_dialogShown = false; _dialogShown = false;
await _logoutAndRedirect(context); await _logoutAndRedirect(context);
}, },
@ -132,22 +153,24 @@ class _ListPlansState extends State<ListPlans> {
Future<void> _logoutAndRedirect(BuildContext context) async { Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0"); print("logue 0");
await apiService.logout(context);
// Example: clear session or shared preferences // // Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // await prefs.clear();
context.go("/"); // context.go("/");
print("logue 1"); print("logue 1");
} }
void _checkAuthAndLoadData() async { void _checkAuthAndLoadData() async {
print("LSIT PLan -2");
final String? token = await getToken(); // Your async function to get token final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) { if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login // Token doesn't exist → redirect to login
// apiService.logout(context);
context.go( context.go(
"/", "/",
); // or use: router.go("/") if you're using `GoRouter` directly ); // or use: router.go("/") if you're using `GoRouter` directly
@ -155,6 +178,7 @@ class _ListPlansState extends State<ListPlans> {
} else { } else {
if (roleUser == "User") { if (roleUser == "User") {
print("user"); print("user");
print("roleUsers - $roleUser");
// After login is successful and navigation completes: // After login is successful and navigation completes:
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@ -304,6 +328,11 @@ class _ListPlansState extends State<ListPlans> {
// List<dynamic> plansJson = []; // List<dynamic> plansJson = [];
List<dynamic> plansJson = data['data']; List<dynamic> plansJson = data['data'];
return plansJson.map((json) => Plan.fromJson(json)).toList(); 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 { } else {
throw Exception('Failed to load plans'); throw Exception('Failed to load plans');
} }
@ -337,6 +366,11 @@ class _ListPlansState extends State<ListPlans> {
print("Plan Deleted successfully!"); print("Plan Deleted successfully!");
print("Response: ${response.body}"); print("Response: ${response.body}");
initializeData(); initializeData();
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else { } else {
print("Failed to submit plan. Status: ${response.statusCode}"); print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}"); 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 { // try {
// Map<String, dynamic> planData = await ApiService.getViewPlan(planId); // Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
// print("ViewAAA - $planData"); // print("ViewAAA - $planData");
@ -363,7 +397,11 @@ class _ListPlansState extends State<ListPlans> {
if (confirmed) { if (confirmed) {
try { try {
Map<String, dynamic> planData = await ApiService.getViewPlan(planId); Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData"); print("ViewAAA - $planData");
refresh(); refresh();
// postPlanData(planData, planId); // postPlanData(planData, planId);
@ -415,6 +453,11 @@ class _ListPlansState extends State<ListPlans> {
approverData = List<Map<String, dynamic>>.from( approverData = List<Map<String, dynamic>>.from(
data['data']['approver_data'] ?? [], 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 { } else {
print('Failed to load'); print('Failed to load');
label = "Error - Failed to load data"; label = "Error - Failed to load data";
@ -1185,7 +1228,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1211,7 +1254,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1235,6 +1278,7 @@ class _ListPlansState extends State<ListPlans> {
); );
deletePlan( deletePlan(
plan.planId, plan.planId,
userId,
); );
}, },
), ),
@ -1255,6 +1299,7 @@ class _ListPlansState extends State<ListPlans> {
); );
apiService apiService
.getPdfDownload( .getPdfDownload(
context,
plan.planId, plan.planId,
); );
}, },
@ -1281,10 +1326,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getForexPdfDownload(
.getForexPdfDownload( context,
plan.forexId, plan.forexId,
); );
}, },
), ),
IconButton( IconButton(
@ -1529,7 +1574,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1556,7 +1601,7 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
ApiService.viewPlan( ApiService().viewPlan(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:
@ -1580,6 +1625,7 @@ class _ListPlansState extends State<ListPlans> {
); );
deletePlan( deletePlan(
plan.planId, plan.planId,
userId,
); );
}, },
), ),
@ -1598,10 +1644,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getPdfDownload(
.getPdfDownload( context,
plan.planId, plan.planId,
); );
}, },
), ),
@ -1626,10 +1672,10 @@ class _ListPlansState extends State<ListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); );
apiService apiService.getForexPdfDownload(
.getForexPdfDownload( context,
plan.forexId, plan.forexId,
); );
}, },
), ),
IconButton( 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:async';
import 'dart:html' as html; import 'dart:html' as html;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'dart:ui' as web; import 'dart:ui' as web;
@ -186,31 +187,38 @@ class _PolicyState extends State<Policy> {
} }
if (!mounted) return; if (!mounted) return;
try { try {
loadinitializeData(); final roleUser = await getRoleUser();
await updateSelectedServices(); if (roleUser != null &&
updateData(); (roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadinitializeData();
loadInitialData(); await updateSelectedServices();
updateData();
WidgetsBinding.instance.addPostFrameCallback((_) { loadInitialData();
if (widget.policy != null) {
final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'],
);
policyCriteriaKey.currentState?.loadPolicyDetails(details);
}
});
// if (widget.policy != null) { WidgetsBinding.instance.addPostFrameCallback((_) {
// print("185"); if (widget.policy != null) {
// final details = List<Map<String, dynamic>>.from( final details = List<Map<String, dynamic>>.from(
// widget.policy!['policy_details'], widget.policy!['policy_details'],
// ); );
// policyCriteriaKey.currentState?.loadPolicyDetails(details); policyCriteriaKey.currentState?.loadPolicyDetails(details);
// }
// policyCriteriaKey.currentState?.fetchTrainFlightClass(); });
// }
// 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) { } catch (e) {
print("group : $e"); print("group : $e");
} }
@ -240,7 +248,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadAllServices() async { Future<void> loadAllServices() async {
try { try {
final result = await apiService.fetchAllServices(); final result = await apiService.fetchAllServices(context);
setState(() { setState(() {
selectedAllServices = result; selectedAllServices = result;
}); });
@ -252,7 +260,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadOrgSelectedAlServices() async { Future<void> loadOrgSelectedAlServices() async {
try { try {
final result = await apiService.fetchOrganization(); final result = await apiService.fetchOrganization(context);
if (result != null && result is Map<String, dynamic>) { if (result != null && result is Map<String, dynamic>) {
final rawServices = result['services_ids']; final rawServices = result['services_ids'];
@ -504,7 +512,7 @@ class _PolicyState extends State<Policy> {
bool result = false; bool result = false;
try { try {
result = await createPolicyData(data); result = await createPolicyData(context, data);
} catch (e) { } catch (e) {
print("Unexpected error during policy creation: $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 String apiUrldata = '$apiUrl/api/policy/createOrUpdate';
final token = await getToken(); // Fetch token final token = await getToken(); // Fetch token
@ -616,9 +627,14 @@ class _PolicyState extends State<Policy> {
if (response.statusCode == 200) { if (response.statusCode == 200) {
print("policyData submitted successfully!"); print("policyData submitted successfully!");
await apiService.handleTokenRefresh(userId!); await apiService.handleTokenRefresh(context, userId!);
print("Response: ${response.body}"); print("Response: ${response.body}");
return true; return true;
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return false;
// throw Exception('Failed to load users');
} else { } else {
print("Failed to submit policyData. Status: ${response.statusCode}"); print("Failed to submit policyData. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
@ -945,6 +961,9 @@ class _PolicyState extends State<Policy> {
height: 40, height: 40,
child: TextField( child: TextField(
style: GoogleFonts.poppins(fontSize: 12), style: GoogleFonts.poppins(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["policyFocusNode"], focusNode: focusNodes["policyFocusNode"],
controller: _policyController, controller: _policyController,
onChanged: (value) => _clearError("name"), onChanged: (value) => _clearError("name"),

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart'; import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -415,7 +416,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
Future<void> fetchTrainFlightClass() async { Future<void> fetchTrainFlightClass() async {
print("ftech api"); print("ftech api");
try { try {
final data = await apiService.fetchMasterDropdown(); final data = await apiService.fetchMasterDropdown(context);
print("fetchTrainFlightClass - $data"); print("fetchTrainFlightClass - $data");
@ -3798,6 +3799,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
child: TextField( child: TextField(
style: GoogleFonts.poppins(fontSize: 12), style: GoogleFonts.poppins(fontSize: 12),
controller: costController[ServiceId], controller: costController[ServiceId],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
// enabled: !isViewMode, // enabled: !isViewMode,
onChanged: (value) { onChanged: (value) {
printData(); 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 { Future<void> loadAllServices() async {
try { try {
final result = await apiService.fetchAllServices(); final result = await apiService.fetchAllServices(context);
setState(() { setState(() {
selectedAllServices = result; selectedAllServices = result;
}); });
@ -229,7 +229,7 @@ class _PolicyState extends State<Policy> {
Future<void> loadOrgSelectedAlServices() async { Future<void> loadOrgSelectedAlServices() async {
try { try {
final result = await apiService.fetchOrganization(); final result = await apiService.fetchOrganization(context);
if (result != null && result is Map<String, dynamic>) { if (result != null && result is Map<String, dynamic>) {
final rawServices = result['services_ids']; final rawServices = result['services_ids'];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -163,7 +163,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
void _checkAuthAndLoadData() async { void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token final String? token = await getToken(); // Your async function to get token
final roleUser = await getRoleUser();
if (token == null || token.isEmpty) { if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login // Token doesn't exist → redirect to login
context.go( context.go(
@ -171,10 +171,16 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
); // or use: router.go("/") if you're using `GoRouter` directly ); // or use: router.go("/") if you're using `GoRouter` directly
return; return;
} }
if (!mounted) return; if (!mounted) return;
try { try {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); if (roleUser != null &&
(roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
loadInitialData();
} else {
apiService.logout(context);
}
}); });
} catch (e) { } catch (e) {
print("service report : $e"); print("service report : $e");
@ -270,6 +276,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
loaderFlag = true; loaderFlag = true;
try { try {
final result = await apiService.CallReports( final result = await apiService.CallReports(
context,
'misServicesAnalysis', 'misServicesAnalysis',
jsonEncode({ jsonEncode({
"fromDate": '$formattedfromDate', "fromDate": '$formattedfromDate',
@ -338,7 +345,6 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), '');
final excelName = '$safeName'; final excelName = '$safeName';
Map<String, dynamic> result = { Map<String, dynamic> result = {
"status": false, "status": false,
"message": "Data Not Found", "message": "Data Not Found",
@ -346,6 +352,7 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) { if (selectedTabName == 'domestic' && dataAvailableDomesticFlag == 1) {
result = await apiService.reportExcelDownload( result = await apiService.reportExcelDownload(
context,
'misServicesAnalysis', 'misServicesAnalysis',
jsonEncode({ jsonEncode({
"fromDate": formattedFromDate, "fromDate": formattedFromDate,
@ -355,8 +362,10 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
excelName, excelName,
); );
} }
if (selectedTabName == 'international' && dataAvailableInternationFlag == 1) { if (selectedTabName == 'international' &&
dataAvailableInternationFlag == 1) {
result = await apiService.reportExcelDownload( result = await apiService.reportExcelDownload(
context,
'misServicesAnalysis', 'misServicesAnalysis',
jsonEncode({ jsonEncode({
"fromDate": formattedFromDate, "fromDate": formattedFromDate,
@ -368,20 +377,23 @@ class _ServicesAnalysisState extends State<ServicesAnalysis>
} }
// Now you can safely access result // Now you can safely access result
final String displayBackgroundColor = result['status'] ? '#28a745' : '#dc1c13'; final String displayBackgroundColor =
final Color displayColor = result['status'] ? Colors.green : Colors.redAccent; result['status'] ? '#28a745' : '#dc1c13';
final Color displayColor =
result['status'] ? Colors.green : Colors.redAccent;
final String displayMessage = result['message']; final String displayMessage = result['message'];
// final bool status = result['status'] == true; // final bool status = result['status'] == true;
Fluttertoast.showToast( Fluttertoast.showToast(
msg: displayMessage , msg: displayMessage,
toastLength: Toast.LENGTH_SHORT, toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER, gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2, timeInSecForIosWeb: 2,
backgroundColor: displayColor, backgroundColor: displayColor,
textColor: Colors.white, textColor: Colors.white,
fontSize: 18.0, 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/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -270,6 +271,12 @@ class TravellerDataState extends State<TravellerData> {
}); });
break; break;
case 403:
print("403-FORB");
await apiService.logout(context);
break;
// throw Exception('Failed to load users');
default: default:
print("Failed to submit traveller. Status: ${response.statusCode}"); print("Failed to submit traveller. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
@ -334,6 +341,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["first_name"], controller: controllers["first_name"],
focusNode: focusNodes["first_nameFocusNode"], focusNode: focusNodes["first_nameFocusNode"],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
@ -379,6 +391,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["last_name"], controller: controllers["last_name"],
focusNode: focusNodes["last_nameFocusNode"], focusNode: focusNodes["last_nameFocusNode"],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),

View File

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

View File

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

View File

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

View File

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

View File

@ -167,6 +167,11 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
print("Response: ${response.body}"); print("Response: ${response.body}");
_clearError(); _clearError();
Navigator.of(context).pop(); 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) { } else if (response.statusCode == 404) {
Navigator.of(context).pop(); Navigator.of(context).pop();
final message = jsonDecode(response.body)['message'] ?? 'Unknown error'; final message = jsonDecode(response.body)['message'] ?? 'Unknown error';

View File

@ -445,6 +445,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
} }
void _checkAuthAndLoadData() async { void _checkAuthAndLoadData() async {
final roleUser = await getRoleUser();
setState(() { setState(() {
isCheckingToken = true; isCheckingToken = true;
}); });
@ -457,44 +458,50 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return; return;
} }
setState(() { if (roleUser != null &&
isCheckingToken = false; (roleUser == 'Org Admin' || roleUser == 'Travel Admin')) {
}); setState(() {
isCheckingToken = false;
});
prepareForNewEntry(); prepareForNewEntry();
selectedTab = "personal"; selectedTab = "personal";
apiCountryData = null; apiCountryData = null;
apiUserData = null; apiUserData = null;
apiCostData = null; apiCostData = null;
apiRoleData = null; apiRoleData = null;
for (var field in dataHeader) { for (var field in dataHeader) {
controllers[field] = TextEditingController(); 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();
} }
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches /// Now this is safe here
initializeData(); try {
fetchCountries(); final extraData = GoRouterState.of(context).extra;
fetchDepartment(); if (extraData != null && extraData is Map<String, dynamic>) {
fetchUsers(); setState(() {
fetchRoles(); apiselectedUser =
loadInitialData(); 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 { void _checkAuthAndLoadData22() async {
@ -597,7 +604,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchCountries() async { Future<void> fetchCountries() async {
try { try {
List<dynamic> countries = await apiService.fetchCountryList(); List<dynamic> countries = await apiService.fetchCountryList(context);
setState(() { setState(() {
apiCountryData = countries; apiCountryData = countries;
}); });
@ -608,7 +615,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchDepartment() async { Future<void> fetchDepartment() async {
try { try {
List<dynamic> department = await apiService.fetchCostCenter(); List<dynamic> department = await apiService.fetchCostCenter(context);
setState(() { setState(() {
apiCostData = department; apiCostData = department;
}); });
@ -619,7 +626,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchUsers() async { Future<void> fetchUsers() async {
try { try {
List<dynamic> users = await apiService.fetchUsers(); List<dynamic> users = await apiService.fetchUsers(context);
setState(() { setState(() {
// apiUserData = users; // apiUserData = users;
@ -642,7 +649,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> fetchRoles() async { Future<void> fetchRoles() async {
try { try {
final response = await apiService.fetchMasterDropdown(); final response = await apiService.fetchMasterDropdown(context);
if (response is Map<String, dynamic> && response.containsKey("role")) { if (response is Map<String, dynamic> && response.containsKey("role")) {
List<dynamic> roleList = response["role"]; // Extract the list List<dynamic> roleList = response["role"]; // Extract the list
@ -1033,7 +1040,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String value, String value,
String? userId, String? userId,
) { ) {
return apiService.CheckDuplicate(label, field, value, userId) return apiService.CheckDuplicate(context, label, field, value, userId)
.then((response) { .then((response) {
if (response.isNotEmpty) { if (response.isNotEmpty) {
errorMessages[field] = errorMessages[field] =
@ -1345,6 +1352,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("📨 Response: ${response.body}"); print("📨 Response: ${response.body}");
await apiService.handleTokenRefresh(context, userId!);
if (roleId == "4") { if (roleId == "4") {
context.go('/listPlan'); context.go('/listPlan');
} else { } 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 // Basic validation: Check mobile number length
final response = await apiService.CheckDuplicate( final response = await apiService.CheckDuplicate(
context,
label, label,
field, field,
value, value,
@ -315,7 +316,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchUsers() async { Future<void> fetchUsers() async {
try { try {
print("Test Users"); print("Test Users");
List<dynamic> users = await apiService.fetchUsers(); List<dynamic> users = await apiService.fetchUsers(context);
setState(() { setState(() {
// apiUserData = users; // apiUserData = users;
@ -341,7 +342,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchDepartment() async { Future<void> fetchDepartment() async {
try { try {
print("Test department"); print("Test department");
List<dynamic> department = await apiService.fetchDepartmentCostCenter(); List<dynamic> department = await apiService.fetchDepartmentCostCenter(
context,
);
setState(() { setState(() {
apiCostData = department; apiCostData = department;
}); });
@ -354,7 +357,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
Future<void> fetchFindGroup() async { Future<void> fetchFindGroup() async {
try { try {
print("Test Groups"); print("Test Groups");
final result = await apiService.fetchAllGroup(); final result = await apiService.fetchAllGroup(context);
setState(() { setState(() {
apiAllGroups = result; apiAllGroups = result;
@ -548,6 +551,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
height: 40, height: 40,
child: TextField( child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: _employeeCodeFocusNode, focusNode: _employeeCodeFocusNode,
controller: widget.controllers["employeeCode"], controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,

View File

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

View File

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

View File

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

View File

@ -34,8 +34,9 @@ class _MyAppState extends State<MyApp> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// SemanticsBinding.instance // 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) { if (kIsWeb) {
final uri = Uri.parse(html.window.location.href); final uri = Uri.parse(html.window.location.href);
print("URI - $uri"); print("URI - $uri");
@ -191,7 +192,7 @@ class _MyAppState extends State<MyApp> {
print("MicroSoft UserData ROLE FECTHED - $userRole"); print("MicroSoft UserData ROLE FECTHED - $userRole");
} }
print("MicroSoft Started"); print("MicroSoft Started");
await apiService.getOrganizationData(); await apiService.getOrganizationData(context);
print("MicroSoft end"); print("MicroSoft end");
} catch (e) { } catch (e) {
print('Error decoding token MS: $e'); print('Error decoding token MS: $e');

View File

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

View File

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

View File

@ -17,6 +17,7 @@ import 'package:frontend/Screens/userManagement/user_List.dart';
import 'package:frontend/routes/organizationSetting.dart'; import 'package:frontend/routes/organizationSetting.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:responsive_builder/responsive_builder.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/list_all_plans.dart';
import '../Screens/allTrips/travel_agent_list.dart'; import '../Screens/allTrips/travel_agent_list.dart';
@ -43,9 +44,27 @@ import '../Screens/reports/misForex.dart';
import '../Screens/reports/guestHouse.dart'; import '../Screens/reports/guestHouse.dart';
import '../Screens/userManagement/create_traveller_agent/listTravelAgent.dart'; import '../Screens/userManagement/create_traveller_agent/listTravelAgent.dart';
import '../utils/auth_utils.dart';
import 'mainLayout.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( final GoRouter router = GoRouter(
// refreshListenable: authState,
routes: [ routes: [
// Public routes without app bar // Public routes without app bar
GoRoute(path: '/', builder: (context, state) => LoginPage()), GoRoute(path: '/', builder: (context, state) => LoginPage()),
@ -65,7 +84,7 @@ final GoRouter router = GoRouter(
// ); // );
}, },
routes: [ routes: [
GoRoute(path: '/home', builder: (context, state) => HomePage()), // GoRoute(path: '/home', builder: (context, state) => HomePage()),
GoRoute( GoRoute(
path: '/listAllPlan', path: '/listAllPlan',
builder: (context, state) => ListAllPlans(), builder: (context, state) => ListAllPlans(),
@ -148,6 +167,13 @@ final GoRouter router = GoRouter(
path: '/statusdashboard', path: '/statusdashboard',
builder: (context, state) => StatusDashboard(), builder: (context, state) => StatusDashboard(),
), ),
GoRoute(
path: '/unauthorized',
builder:
(context, state) =>
const Scaffold(body: Center(child: Text("🚫 Access Denied"))),
),
GoRoute( GoRoute(
path: '/traveller', path: '/traveller',
builder: (context, state) => TravellerList(), 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( class ApiStatusCache {
// routes: [ static int? latestStatus;
// 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)),
// ),
// ],
// );

View File

@ -36,26 +36,31 @@ class OrganizationSettingState extends State<OrganizationSetting> {
// String? bodyStringColor = await getBodyColor(); // String? bodyStringColor = await getBodyColor();
roleUser = await getRoleUser(); roleUser = await getRoleUser();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor = if (roleUser == 'Org Admin' || roleUser == 'Travel Admin') {
layoutString != null setState(() {
? Color(int.parse(secondString!)) layoutColor =
: Colors.orange; layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
thridColor = secondColor =
layoutString != null layoutString != null
? Color(int.parse(thridString!)) ? Color(int.parse(secondString!))
: Colors.orangeAccent; : Colors.orange;
// bodyColor =
// bodyStringColor != null thridColor =
// ? Color(int.parse(bodyStringColor)) layoutString != null
// : Colors.white; ? Color(int.parse(thridString!))
}); : Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
} else {
apiService.logout(context);
}
} }
@override @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 prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data'); final String? userDataString = prefs.getString('user_data');
print('getRoleUser');
// print("UserDataSTr - $userDataString"); // print("UserDataSTr - $userDataString");
if (userDataString != null) { if (userDataString != null) {

View File

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

View File

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

View File

@ -33,6 +33,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.7.0" version: "2.7.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024"
url: "https://pub.dev"
source: hosted
version: "1.6.5"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -209,6 +217,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.5+1" 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: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -813,6 +829,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
pool: pool:
dependency: transitive dependency: transitive
description: description:

View File

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