authentication

This commit is contained in:
venbaittech 2025-06-18 18:39:02 +05:30
parent 08f80a8afa
commit 6bb37994de
29 changed files with 2310 additions and 1227 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

View File

@ -50,20 +50,37 @@ class _ListAllPlansState extends State<ListAllPlans> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getToken(); _checkAuthAndLoadData();
WidgetsBinding.instance.addPostFrameCallback((_) { // // If token exists, load the dashboard data
// WidgetsBinding.instance.addPostFrameCallback((_) {
// initializeData();
// loadInitialData();
//
// // futurePlans.then((plans) {
// // setState(() {
// // allPlans = plans;
// // filteredPlans = plans;
// // });
// // });
// });
// // futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
} else {
getToken();
initializeData(); initializeData();
loadInitialData(); loadInitialData();
}
// futurePlans.then((plans) {
// setState(() {
// allPlans = plans;
// filteredPlans = plans;
// });
// });
});
// futurePlans = fetchPlans();
} }
void filterPlans(String query) { void filterPlans(String query) {

View File

@ -48,23 +48,39 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getToken(); _checkAuthAndLoadData();
// getToken();
WidgetsBinding.instance.addPostFrameCallback((_) { //
initializeData(); // WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); // initializeData();
// loadInitialData();
// futurePlans.then((plans) { //
// setState(() { // // futurePlans.then((plans) {
// allPlans = plans; // // setState(() {
// filteredPlans = plans; // // allPlans = plans;
// // filteredPlans = plans;
// // });
// // });
// }); // });
// });
});
// futurePlans = fetchPlans(); // futurePlans = fetchPlans();
} }
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
getToken();
initializeData();
loadInitialData();
}
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();

View File

@ -46,16 +46,32 @@ class _ApprovalListState extends State<ApprovalList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getToken(); _checkAuthAndLoadData();
// getToken();
WidgetsBinding.instance.addPostFrameCallback((_) { //
initializeData(); // WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); // initializeData();
}); // loadInitialData();
// });
// futurePlans = fetchPlans(); // futurePlans = fetchPlans();
} }
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
getToken();
initializeData();
loadInitialData();
}
void loadInitialData() async { void loadInitialData() async {
String? layoutString = await getLayoutColor(); String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();

View File

@ -135,16 +135,10 @@ class _LoginWidgetState extends State<LoginWidget> {
timeInSecForIosWeb: 2, timeInSecForIosWeb: 2,
backgroundColor: Colors.green, backgroundColor: Colors.green,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.0, fontSize: 18.0,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
); );
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text("Login Successful"),
// backgroundColor: Colors.green, // Set background to green
// ),
// );
if (userRole == "Travel Agent") { if (userRole == "Travel Agent") {
context.go('/listTravelAgentPlan'); context.go('/listTravelAgentPlan');
} else if (userRole == "Org Admin" || userRole == "Travel Admin") { } else if (userRole == "Org Admin" || userRole == "Travel Admin") {
@ -225,12 +219,6 @@ class _LoginWidgetState extends State<LoginWidget> {
_showOtpResetFields = true; _showOtpResetFields = true;
// _clearAllFields(); // _clearAllFields();
}); });
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text("OTP sent to your email"),
// backgroundColor: Colors.green,
// ),
// );
Fluttertoast.showToast( Fluttertoast.showToast(
msg: "OTP sent to your email", msg: "OTP sent to your email",
@ -240,18 +228,10 @@ class _LoginWidgetState extends State<LoginWidget> {
backgroundColor: Colors.green, backgroundColor: Colors.green,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.0, fontSize: 16.0,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
); );
} else { } else {
print(response); print(response);
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// "${jsonDecode(response.body)['messages']['error']}",
// ),
//
// backgroundColor: Colors.red,
// ),
// );
Fluttertoast.showToast( Fluttertoast.showToast(
msg: "${jsonDecode(response.body)['messages']['error']}", msg: "${jsonDecode(response.body)['messages']['error']}",
@ -304,12 +284,6 @@ class _LoginWidgetState extends State<LoginWidget> {
_showOtpResetFields = false; _showOtpResetFields = false;
_clearAllFields(); _clearAllFields();
}); });
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text("Password reset successfully"),
// backgroundColor: Colors.green,
// ),
// );
Fluttertoast.showToast( Fluttertoast.showToast(
msg: "Password reset successfully", msg: "Password reset successfully",
@ -319,6 +293,7 @@ class _LoginWidgetState extends State<LoginWidget> {
backgroundColor: Colors.green, backgroundColor: Colors.green,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.0, fontSize: 16.0,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
); );
} else { } else {
print('23'); print('23');
@ -521,6 +496,7 @@ class _LoginWidgetState extends State<LoginWidget> {
fontSize: widget.isDesktop ? 20 : 18, fontSize: widget.isDesktop ? 20 : 18,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: Colors.green, color: Colors.green,
// color: Color(0xFF212121), // color: Color(0xFF212121),
), ),
), ),

View File

@ -28,7 +28,8 @@ class CostCenterListState extends State<CostCenterList> {
GlobalKey<CostCenterListState>(); GlobalKey<CostCenterListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureCostCenter; Future<List<dynamic>>? futureCostCenter;
// late Future<List<dynamic>> futureCostCenter;
late Map<String, dynamic> depSingleData; late Map<String, dynamic> depSingleData;
String? selectedCostCenterId; String? selectedCostCenterId;
@ -47,9 +48,37 @@ class CostCenterListState extends State<CostCenterList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureCostCenter = fetchGetCostCenter();
//
// futureCostCenter.then((object) {
// setState(() {
// allCostCenter = object;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureCostCenter = fetchGetCostCenter(); futureCostCenter = fetchGetCostCenter();
futureCostCenter.then((object) { futureCostCenter?.then((object) {
setState(() { setState(() {
allCostCenter = object; allCostCenter = object;
}); });
@ -58,8 +87,9 @@ class CostCenterListState extends State<CostCenterList> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
void loadInitialData() async { void loadInitialData() async {
@ -89,7 +119,7 @@ class CostCenterListState extends State<CostCenterList> {
futureCostCenter = fetchGetCostCenter(); futureCostCenter = fetchGetCostCenter();
return futureCostCenter.then((object) { return futureCostCenter!.then((object) {
print("Calling Refresh Data $object"); print("Calling Refresh Data $object");
setState(() { setState(() {
allCostCenter = object; allCostCenter = object;
@ -406,6 +436,10 @@ class CostCenterListState extends State<CostCenterList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureCostCenter, future: futureCostCenter,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureCostCenter == null) {
return CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -1,7 +1,11 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:html' as html;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:frontend/routes/custom_router.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;
@ -16,7 +20,6 @@ import '../../utils/auth_utils.dart';
import '../../utils/pagination.dart'; import '../../utils/pagination.dart';
class StatusDashboard extends StatefulWidget { class StatusDashboard extends StatefulWidget {
const StatusDashboard({super.key}); const StatusDashboard({super.key});
@override @override
@ -24,15 +27,101 @@ class StatusDashboard extends StatefulWidget {
} }
class StatusDashboardState extends State<StatusDashboard> { class StatusDashboardState extends State<StatusDashboard> {
Map<String, dynamic>? apiData; Map<String, dynamic>? apiData;
String? organizationId; String? organizationId;
late bool _dialogShown = false;
late StreamSubscription<html.PopStateEvent> _popStateListener;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadDashboardData(); _checkAuthAndLoadData();
checkbackbutton();
// loadDashboardData();
}
void checkbackbutton() async {
// Push a dummy state so back button triggers popstate instead of navigating
html.window.history.pushState(null, 'home', html.window.location.href);
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
}
// Re-push to prevent leaving
html.window.history.pushState(null, 'home', html.window.location.href);
});
}
@override
void dispose() {
_popStateListener.cancel(); // Remove the browser popstate listener
super.dispose();
}
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"),
),
],
),
);
}
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0");
// Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
context.go("/");
print("logue 1");
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
WidgetsBinding.instance.addPostFrameCallback((_) {
checkbackbutton();
});
// If token exists, load the dashboard data
loadDashboardData();
} }
Future<void> loadDashboardData() async { Future<void> loadDashboardData() async {
@ -66,13 +155,11 @@ class StatusDashboardState extends State<StatusDashboard> {
return null; return null;
} }
Future<Map<String, dynamic>> fetchStatusDashboard() async { Future<Map<String, dynamic>> fetchStatusDashboard() async {
organizationId = await getOrgId(); organizationId = await getOrgId();
final String apiUrlData = '$apiUrl/api/plans/statusDashboard?org_id=$organizationId'; final String apiUrlData =
'$apiUrl/api/plans/statusDashboard?org_id=$organizationId';
final String? token = await getToken(); final String? token = await getToken();
print("Fetch StatusDashboard -- 2KN Here : $token"); print("Fetch StatusDashboard -- 2KN Here : $token");
@ -132,17 +219,18 @@ class StatusDashboardState extends State<StatusDashboard> {
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final typeBasedCount = List<Map<String, dynamic>>.from( final typeBasedCount = List<Map<String, dynamic>>.from(
(apiData?['data']?['typeBasedCount']) ?? []); (apiData?['data']?['typeBasedCount']) ?? [],
);
print("apiData - => $apiData"); print("apiData - => $apiData");
print("typeBasedCount => $typeBasedCount"); print("typeBasedCount => $typeBasedCount");
final statusBasedCount = List<Map<String, dynamic>>.from( final statusBasedCount = List<Map<String, dynamic>>.from(
(apiData?['data']?['statusBasedCount']) ?? []); (apiData?['data']?['statusBasedCount']) ?? [],
);
print("statusBasedCount - => $statusBasedCount"); print("statusBasedCount - => $statusBasedCount");
// 👇 Local function to create the card widget // 👇 Local function to create the card widget
Widget buildInfoCard(String title, int count, double width) { Widget buildInfoCard(String title, int count, double width) {
@ -159,14 +247,24 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(icon, size: 32, color: (title == 'Domestic' || title == 'International') ? Colors.green : Colors.black54), // 👈 Add Icon here Icon(
icon,
size: 32,
color:
(title == 'Domestic' || title == 'International')
? Colors.green
: Colors.black54,
), // 👈 Add Icon here
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
title, title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: (title == 'Domestic' || title == 'International') ? 16 : 14, fontSize:
(title == 'Domestic' || title == 'International')
? 16
: 14,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -182,36 +280,60 @@ class StatusDashboardState extends State<StatusDashboard> {
), ),
), ),
); );
} }
return ResponsiveBuilder(builder: (context, sizingInfo) { void _handleBackButton() {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; final location = GoRouterState.of(context).uri.toString();
return Scaffold( print("location - $location");
if (location.contains('/StatusDashboard')) {
// Do nothing or show "Press again to exit" toast
print("Blocked back on dashboard");
} else {
print("dashboard ..");
}
}
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return PopScope(
canPop: false, // Allow back navigation only if not login screen
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
_handleBackButton(); // Show exit confirmation dialog
},
child: Scaffold(
backgroundColor: const Color(0xFFf5f5f5), backgroundColor: const Color(0xFFf5f5f5),
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.1, // 30% of screen width as horizontal padding horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding
vertical: 10, // 5% of screen height as vertical padding vertical: 10, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
child : LayoutBuilder( child: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
return SingleChildScrollView( return SingleChildScrollView(
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: constraints.maxHeight, minHeight: constraints.maxHeight,
), ),
child: IntrinsicHeight( // Only needed if child layout depends on height child: IntrinsicHeight(
// Only needed if child layout depends on height
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDesktop ? Colors.white : const Color(0xFFFCFCFC), color:
isDesktop
? Colors.white
: const Color(0xFFFCFCFC),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Row( child: Row(
@ -220,19 +342,34 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(30.0), padding: const EdgeInsets.all(30.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
CrossAxisAlignment.center,
children: [ children: [
Wrap( Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
children: typeBasedCount.map((item) { children:
double cardWidth = isDesktop typeBasedCount.map((item) {
? (MediaQuery.of(context).size.width * 0.75 - 10) / 2 // 80% width padding adjusted double cardWidth =
: MediaQuery.of(context).size.width - 24; // full width with padding isDesktop
? (MediaQuery.of(
context,
).size.width *
0.75 -
10) /
2 // 80% width padding adjusted
: MediaQuery.of(
context,
).size.width -
24; // full width with padding
return SizedBox( return SizedBox(
width: cardWidth, width: cardWidth,
child: buildInfoCard(item['value'], item['count'], cardWidth), child: buildInfoCard(
item['value'],
item['count'],
cardWidth,
),
); );
}).toList(), }).toList(),
), ),
@ -240,18 +377,31 @@ class StatusDashboardState extends State<StatusDashboard> {
Wrap( Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
children: statusBasedCount.map((item) { children:
double cardWidth = isDesktop statusBasedCount.map((item) {
? (MediaQuery.of(context).size.width * 0.90 - 50) / 6 // desktop layout: 6 cards per row double cardWidth =
: MediaQuery.of(context).size.width - 24; // mobile: full width isDesktop
? (MediaQuery.of(
context,
).size.width *
0.90 -
50) /
6 // desktop layout: 6 cards per row
: MediaQuery.of(
context,
).size.width -
24; // mobile: full width
return SizedBox( return SizedBox(
width: cardWidth, width: cardWidth,
child: buildInfoCard(item['value'], item['count'], cardWidth), child: buildInfoCard(
item['value'],
item['count'],
cardWidth,
),
); );
}).toList(), }).toList(),
), ),
], ],
), ),
), ),
@ -263,14 +413,11 @@ class StatusDashboardState extends State<StatusDashboard> {
), ),
); );
}, },
) ),
),
), ),
); );
}); },
);
} }
} }

View File

@ -28,7 +28,8 @@ class DepartmentListState extends State<DepartmentList> {
GlobalKey<DepartmentListState>(); GlobalKey<DepartmentListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureDepartment; // late Future<List<dynamic>> futureDepartment;
Future<List<dynamic>>? futureDepartment;
late Map<String, dynamic> depSingleData; late Map<String, dynamic> depSingleData;
String? selectedDepartmentId; String? selectedDepartmentId;
@ -47,9 +48,37 @@ class DepartmentListState extends State<DepartmentList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureDepartment = fetchGetDepartment();
//
// futureDepartment.then((object) {
// setState(() {
// allDepartment = object;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureDepartment = fetchGetDepartment(); futureDepartment = fetchGetDepartment();
futureDepartment.then((object) { futureDepartment?.then((object) {
setState(() { setState(() {
allDepartment = object; allDepartment = object;
}); });
@ -58,8 +87,9 @@ class DepartmentListState extends State<DepartmentList> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
void loadInitialData() async { void loadInitialData() async {
@ -89,7 +119,7 @@ class DepartmentListState extends State<DepartmentList> {
futureDepartment = fetchGetDepartment(); futureDepartment = fetchGetDepartment();
return futureDepartment.then((object) { return futureDepartment!.then((object) {
print("Calling Refresh Data $object"); print("Calling Refresh Data $object");
setState(() { setState(() {
allDepartment = object; allDepartment = object;
@ -405,6 +435,10 @@ class DepartmentListState extends State<DepartmentList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureDepartment, future: futureDepartment,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureDepartment == null) {
CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -14,7 +14,7 @@ import '../../widgets/custom_text_forex.dart';
import 'forex_list.dart'; import 'forex_list.dart';
class ForexData extends StatefulWidget { class ForexData extends StatefulWidget {
final Future<List<dynamic>> Function() fetchGetForex; final Future<List<dynamic>?> Function() fetchGetForex;
final bool isDesktop; final bool isDesktop;
final Color? layoutColor; final Color? layoutColor;

View File

@ -29,7 +29,8 @@ class ForexDataListState extends State<ForexDataList> {
GlobalKey<ForexDataListState>(); GlobalKey<ForexDataListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureForex; // late Future<List<dynamic>> futureForex;
Future<List<dynamic>>? futureForex;
late Map<String, dynamic> userSingleData; late Map<String, dynamic> userSingleData;
List<dynamic>? apiCountryData; List<dynamic>? apiCountryData;
@ -49,9 +50,38 @@ class ForexDataListState extends State<ForexDataList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureForex = fetchGetForex();
//
// futureForex.then((users) {
// setState(() {
// allForex = users;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureForex = fetchGetForex(); futureForex = fetchGetForex();
futureForex.then((users) { futureForex?.then((users) {
setState(() { setState(() {
allForex = users; allForex = users;
}); });
@ -61,16 +91,33 @@ class ForexDataListState extends State<ForexDataList> {
fetchCountryList(); fetchCountryList();
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
Future<List<dynamic>> refreshData() { // Future<List<dynamic>?> refreshData() {
// print("Calling Refresh Data");
//
// // futureForex = fetchGetForex();
// futureForex = fetchGetForex() ?? Future.value([]);
//
// return futureForex.then((users) {
// setState(() {
// allForex = users;
// filteredForex = users;
// searchController.text = "";
// });
// return users;
// });
// }
Future<List<dynamic>?> refreshData() {
print("Calling Refresh Data"); print("Calling Refresh Data");
futureForex = fetchGetForex(); futureForex = fetchGetForex();
return futureForex.then((users) { return futureForex!.then((users) {
setState(() { setState(() {
allForex = users; allForex = users;
filteredForex = users; filteredForex = users;
@ -557,6 +604,9 @@ class ForexDataListState extends State<ForexDataList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureForex, future: futureForex,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureForex == null) {
return const CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||
@ -748,7 +798,8 @@ class ForexDataListState extends State<ForexDataList> {
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
color: forex['is_active'] == "1" color:
forex['is_active'] == "1"
? Colors.green ? Colors.green
: Colors.grey, : Colors.grey,
), ),

View File

@ -23,7 +23,9 @@ class GroupList extends StatefulWidget {
class _GroupListState extends State<GroupList> { class _GroupListState extends State<GroupList> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureGroups; // late Future<List<dynamic>> futureGroups;
Future<List<dynamic>>? futureGroups;
late Map<String, dynamic> groupSingleData; late Map<String, dynamic> groupSingleData;
List<dynamic>? apiCountryData; List<dynamic>? apiCountryData;
@ -45,21 +47,50 @@ class _GroupListState extends State<GroupList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureGroups = fetchGroups();
//
// futureGroups.then((object) {
// setState(() {
// allGroups = object;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// fetchGroups();
// loadAllGroups();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureGroups = fetchGroups(); futureGroups = fetchGroups();
futureGroups.then((object) { futureGroups?.then((object) {
setState(() { setState(() {
allGroups = object; allGroups = object;
}); });
}); });
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
fetchGroups(); fetchGroups();
loadAllGroups(); loadAllGroups();
}); } catch (e) {
print("group : $e");
// futurePlans = fetchPlans(); }
} }
void loadInitialData() async { void loadInitialData() async {
@ -420,9 +451,14 @@ class _GroupListState extends State<GroupList> {
], ],
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureGroups, future: futureGroups,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureGroups == null) {
return const CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -29,7 +29,8 @@ class HotelsDataListState extends State<HotelsDataList> {
GlobalKey<HotelsDataListState>(); GlobalKey<HotelsDataListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureHotels; Future<List<dynamic>>? futureHotels;
// late Future<List<dynamic>> futureHotels;
late Map<String, dynamic> userSingleData; late Map<String, dynamic> userSingleData;
List<dynamic>? apiCountryData; List<dynamic>? apiCountryData;
@ -49,9 +50,38 @@ class HotelsDataListState extends State<HotelsDataList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureHotels = fetchGetHotels();
//
// futureHotels.then((objects) {
// setState(() {
// allHotels = objects;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureHotels = fetchGetHotels(); futureHotels = fetchGetHotels();
futureHotels.then((objects) { futureHotels?.then((objects) {
setState(() { setState(() {
allHotels = objects; allHotels = objects;
}); });
@ -61,8 +91,9 @@ class HotelsDataListState extends State<HotelsDataList> {
fetchCountryList(); fetchCountryList();
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
Future<List<dynamic>> refreshData() { Future<List<dynamic>> refreshData() {
@ -70,7 +101,7 @@ class HotelsDataListState extends State<HotelsDataList> {
futureHotels = fetchGetHotels(); futureHotels = fetchGetHotels();
return futureHotels.then((objects) { return futureHotels!.then((objects) {
setState(() { setState(() {
allHotels = objects; allHotels = objects;
filteredHotels = objects; filteredHotels = objects;
@ -454,6 +485,10 @@ class HotelsDataListState extends State<HotelsDataList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureHotels, future: futureHotels,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureHotels == null) {
return CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -102,7 +102,29 @@ class TemplateState extends State<Template> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
//
// for (var field in dataHeader) {
// controllers[field] = TextEditingController();
// }
//
// updateData();
// loadinitializeData();
// loadInitialData();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
for (var field in dataHeader) { for (var field in dataHeader) {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
@ -110,6 +132,9 @@ class TemplateState extends State<Template> {
updateData(); updateData();
loadinitializeData(); loadinitializeData();
loadInitialData(); loadInitialData();
} catch (e) {
print("group : $e");
}
} }
@override @override

View File

@ -108,7 +108,29 @@ class TemplateForexState extends State<TemplateForex> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
//
// for (var field in dataHeader) {
// controllers[field] = TextEditingController();
// }
//
// updateData();
// loadinitializeData();
// loadInitialData();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
for (var field in dataHeader) { for (var field in dataHeader) {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
@ -116,6 +138,9 @@ class TemplateForexState extends State<TemplateForex> {
updateData(); updateData();
loadinitializeData(); loadinitializeData();
loadInitialData(); loadInitialData();
} catch (e) {
print("group : $e");
}
} }
@override @override

View File

@ -28,7 +28,8 @@ class TemplatesListState extends State<TemplatesList> {
// GlobalKey<TemplatesListState>(); // GlobalKey<TemplatesListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureTemplates; Future<List<dynamic>>? futureTemplates;
// late Future<List<dynamic>> futureTemplates;
late Map<String, dynamic> userSingleData; late Map<String, dynamic> userSingleData;
List<dynamic>? apiCountryData; List<dynamic>? apiCountryData;
@ -48,9 +49,38 @@ class TemplatesListState extends State<TemplatesList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureTemplates = fetchGetForex();
//
// futureTemplates.then((users) {
// setState(() {
// allTemplate = users;
// print("AlL tEMPLATESNIT - $allTemplate");
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureTemplates = fetchGetForex(); futureTemplates = fetchGetForex();
futureTemplates.then((users) { futureTemplates?.then((users) {
setState(() { setState(() {
allTemplate = users; allTemplate = users;
print("AlL tEMPLATESNIT - $allTemplate"); print("AlL tEMPLATESNIT - $allTemplate");
@ -60,16 +90,17 @@ class TemplatesListState extends State<TemplatesList> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
Future<List<dynamic>> refreshData() { Future<List<dynamic>?> refreshData() {
print("Calling Refresh Data"); print("Calling Refresh Data");
futureTemplates = fetchGetForex(); futureTemplates = fetchGetForex();
return futureTemplates.then((users) { return futureTemplates!.then((users) {
setState(() { setState(() {
allTemplate = users; allTemplate = users;
}); });
@ -82,11 +113,13 @@ class TemplatesListState extends State<TemplatesList> {
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
@ -95,9 +128,12 @@ class TemplatesListState extends State<TemplatesList> {
String formatTemplateName(String input) { String formatTemplateName(String input) {
return input return input
.split('_') // split by underscore .split('_') // split by underscore
.map((word) => word.isNotEmpty .map(
(word) =>
word.isNotEmpty
? '${word[0].toUpperCase()}${word.substring(1)}' ? '${word[0].toUpperCase()}${word.substring(1)}'
: '') : '',
)
.join(' '); .join(' ');
} }
@ -106,7 +142,8 @@ class TemplatesListState extends State<TemplatesList> {
try { try {
final List<dynamic> decoded = json.decode(raw); final List<dynamic> decoded = json.decode(raw);
final List<String> values = decoded final List<String> values =
decoded
.map((e) => e['value'].toString().replaceAll('%', '')) .map((e) => e['value'].toString().replaceAll('%', ''))
.toList(); .toList();
return values.join(', '); return values.join(', ');
@ -157,7 +194,10 @@ class TemplatesListState extends State<TemplatesList> {
} }
Future<void> createTemplateData( Future<void> createTemplateData(
Map<String, dynamic> userData, String userId, String newStatus) async { Map<String, dynamic> userData,
String userId,
String newStatus,
) async {
final uri = Uri.parse('$apiUrl/api/users/update/$userId'); final uri = Uri.parse('$apiUrl/api/users/update/$userId');
final String? token = await getToken(); final String? token = await getToken();
@ -207,8 +247,11 @@ class TemplatesListState extends State<TemplatesList> {
} }
} }
void handleToggleUserStatus(String userId, String currentStatus, void handleToggleUserStatus(
Map<String, dynamic> userData) async { String userId,
String currentStatus,
Map<String, dynamic> userData,
) async {
print("Toggling user status - $userId (Current: $currentStatus)"); print("Toggling user status - $userId (Current: $currentStatus)");
final String apiUrlData = final String apiUrlData =
@ -251,7 +294,7 @@ class TemplatesListState extends State<TemplatesList> {
// } // }
} }
// Refresh user list after update // Refresh user list after update
void refreshUserList() { void refreshUserList() {
setState(() { setState(() {
futureTemplates = fetchGetForex(); // Re-fetch users after status update futureTemplates = fetchGetForex(); // Re-fetch users after status update
@ -264,7 +307,8 @@ class TemplatesListState extends State<TemplatesList> {
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
setState(() { setState(() {
filteredTemplates = allTemplate.where((user) { filteredTemplates =
allTemplate.where((user) {
// Match template_name // Match template_name
final templateName = final templateName =
(user['template_name'] ?? '').toString().toLowerCase(); (user['template_name'] ?? '').toString().toLowerCase();
@ -277,13 +321,20 @@ class TemplatesListState extends State<TemplatesList> {
if (placeholderRaw != null && placeholderRaw is String) { if (placeholderRaw != null && placeholderRaw is String) {
try { try {
final List<dynamic> decoded = json.decode(placeholderRaw); final List<dynamic> decoded = json.decode(placeholderRaw);
final List<String> placeholderValues = decoded final List<String> placeholderValues =
.map((e) => decoded
e['value'].toString().replaceAll('%', '').toLowerCase()) .map(
(e) =>
e['value']
.toString()
.replaceAll('%', '')
.toLowerCase(),
)
.toList(); .toList();
matchesPlaceholder = matchesPlaceholder = placeholderValues.any(
placeholderValues.any((value) => value.contains(lowerQuery)); (value) => value.contains(lowerQuery),
);
} catch (e) { } catch (e) {
// ignore invalid placeholder format // ignore invalid placeholder format
} }
@ -298,8 +349,10 @@ class TemplatesListState extends State<TemplatesList> {
@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: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
@ -308,11 +361,14 @@ class TemplatesListState extends State<TemplatesList> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height * vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
@ -325,7 +381,8 @@ class TemplatesListState extends State<TemplatesList> {
), ),
), ),
); );
}); },
);
} }
Widget buildGroupList(bool isDesktop) { Widget buildGroupList(bool isDesktop) {
@ -353,7 +410,8 @@ class TemplatesListState extends State<TemplatesList> {
// ? EdgeInsets.all(10.0) // ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: isDesktop height:
isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
@ -385,9 +443,7 @@ class TemplatesListState extends State<TemplatesList> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox( SizedBox(width: MediaQuery.of(context).size.width * 0.23),
width: MediaQuery.of(context).size.width * 0.23,
),
if (isDesktop) if (isDesktop)
Container( Container(
@ -399,7 +455,9 @@ class TemplatesListState extends State<TemplatesList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -411,17 +469,19 @@ class TemplatesListState extends State<TemplatesList> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5), color: Colors.grey.shade200,
width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -464,10 +524,7 @@ class TemplatesListState extends State<TemplatesList> {
], ],
), ),
if (!isDesktop) if (!isDesktop) SizedBox(height: 5),
SizedBox(
height: 5,
),
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
@ -482,7 +539,9 @@ class TemplatesListState extends State<TemplatesList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -495,17 +554,18 @@ class TemplatesListState extends State<TemplatesList> {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5), width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -515,6 +575,9 @@ class TemplatesListState extends State<TemplatesList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureTemplates, future: futureTemplates,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureTemplates == null) {
return CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||
@ -543,14 +606,17 @@ class TemplatesListState extends State<TemplatesList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey), color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Please Create Templates", "Please Create Templates",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey), fontSize: 16,
color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -559,7 +625,8 @@ class TemplatesListState extends State<TemplatesList> {
); );
} }
List<dynamic> templates = filteredTemplates.isNotEmpty List<dynamic> templates =
filteredTemplates.isNotEmpty
? filteredTemplates ? filteredTemplates
: allTemplate; : allTemplate;
@ -573,25 +640,27 @@ class TemplatesListState extends State<TemplatesList> {
templates.sort((a, b) { templates.sort((a, b) {
try { try {
DateTime dateA = DateTime dateA = DateTime.parse(
DateTime.parse(a['created_at'] ?? '2000-01-01'); a['created_at'] ?? '2000-01-01',
DateTime dateB = );
DateTime.parse(b['created_at'] ?? '2000-01-01'); DateTime dateB = DateTime.parse(
b['created_at'] ?? '2000-01-01',
);
return dateB.compareTo(dateA); return dateB.compareTo(dateA);
} catch (e) { } catch (e) {
return 0; // If parsing fails, consider them equal return 0; // If parsing fails, consider them equal
} }
}); });
List paginatedTemplates = templates List paginatedTemplates =
templates
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = double minWidth = isDesktop ? constraints.maxWidth : 1300;
isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
@ -600,7 +669,9 @@ class TemplatesListState extends State<TemplatesList> {
columnSpacing: isDesktop ? 24.0 : 16.0, columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200), width: 0.5,
color: Colors.grey.shade200,
),
), ),
columns: [ columns: [
DataColumn( DataColumn(
@ -608,8 +679,10 @@ class TemplatesListState extends State<TemplatesList> {
'Template Name', 'Template Name',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
// DataColumn( // DataColumn(
// label: Text( // label: Text(
// 'Attributes', // 'Attributes',
@ -622,24 +695,33 @@ class TemplatesListState extends State<TemplatesList> {
'Actions', 'Actions',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
], ],
rows: paginatedTemplates.map((forex) { rows:
String forexId = forex['template_id'] paginatedTemplates.map((forex) {
String forexId =
forex['template_id']
.toString(); // Get user ID .toString(); // Get user ID
bool isSelected = selectedUserId == forexId; bool isSelected = selectedUserId == forexId;
return DataRow(cells: [ return DataRow(
DataCell(Text( cells: [
DataCell(
Text(
// "${forex['template_name'] ?? ''}", // "${forex['template_name'] ?? ''}",
formatTemplateName( formatTemplateName(
forex['template_name'] ?? ''), forex['template_name'] ?? '',
),
// Text("{forex['template_name'] ?? ''}", // Text("{forex['template_name'] ?? ''}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
),
),
// DataCell(Text( // DataCell(Text(
// getPlaceholderNames(forex['placeholder']), // getPlaceholderNames(forex['placeholder']),
// style: TextStyle( // style: TextStyle(
@ -656,7 +738,8 @@ class TemplatesListState extends State<TemplatesList> {
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15), height: 15,
),
onTap: () async { onTap: () async {
// final userId = getUserId(user['user_id']); // final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
@ -664,7 +747,8 @@ class TemplatesListState extends State<TemplatesList> {
// context.go('/template'); // context.go('/template');
final templateId = int.tryParse( final templateId = int.tryParse(
forex['template_id'].toString()); forex['template_id'].toString(),
);
if (templateId != null) { if (templateId != null) {
print("templateId -- $templateId"); print("templateId -- $templateId");
@ -672,16 +756,18 @@ class TemplatesListState extends State<TemplatesList> {
.getTemplateFind(templateId); .getTemplateFind(templateId);
print("ForexId -- $data"); print("ForexId -- $data");
context.go('/template', extra: { context.go(
'templateData': data, '/template',
}); extra: {'templateData': data},
);
} else { } else {
print("Invalid Forex ID"); print("Invalid Forex ID");
} }
}, },
), ),
), ),
]); ],
);
}).toList(), }).toList(),
), ),
); );
@ -696,7 +782,9 @@ class TemplatesListState extends State<TemplatesList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -714,16 +802,18 @@ class TemplatesListState extends State<TemplatesList> {
Text( Text(
// forex['template_name'] ?? 'N/A', // forex['template_name'] ?? 'N/A',
formatTemplateName( formatTemplateName(
forex['template_name'] ?? ''), forex['template_name'] ?? '',
),
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700,
),
), ),
UserActionsMenu( UserActionsMenu(
user: forex, user: forex,
getUserDetails: (id) => getUserDetails:
apiService.getSingleUser(id), (id) => apiService.getSingleUser(id),
), ),
], ],
), ),
@ -764,7 +854,8 @@ class TemplatesListState extends State<TemplatesList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: isDesktop child:
isDesktop
? (searchController.text.isNotEmpty && ? (searchController.text.isNotEmpty &&
filteredTemplates.isEmpty filteredTemplates.isEmpty
? Center( ? Center(
@ -772,7 +863,8 @@ class TemplatesListState extends State<TemplatesList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
@ -786,11 +878,13 @@ class TemplatesListState extends State<TemplatesList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: buildMobileCardView( : buildMobileCardView(
paginatedTemplates)), paginatedTemplates,
)),
), ),
// Expanded( // Expanded(
// child: isDesktop // child: isDesktop
@ -821,9 +915,11 @@ class TemplatesListState extends State<TemplatesList> {
), ),
); );
}, },
) ),
]), ],
)), ),
),
),
); );
} }
} }

View File

@ -53,13 +53,29 @@ class _OrgSetUpState extends State<OrgSetUp> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadAllServices();
// getOrganizationData();
// initializeData();
// loadInitialData();
// });
}
WidgetsBinding.instance.addPostFrameCallback((_) { void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
loadAllServices(); loadAllServices();
getOrganizationData(); getOrganizationData();
initializeData(); initializeData();
loadInitialData(); loadInitialData();
});
} }
void loadInitialData() async { void loadInitialData() async {

View File

@ -48,6 +48,20 @@ class _CreatePlansState extends State<CreatePlan> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// loadInitialData();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
loadInitialData(); loadInitialData();
} }

View File

@ -1,5 +1,8 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:core'; import 'dart:core';
import 'dart:html' as html;
import 'package:frontend/data/models/plan.dart'; import 'package:frontend/data/models/plan.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';
@ -12,6 +15,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../routes/custom_appBar.dart'; import '../../routes/custom_appBar.dart';
import '../../routes/custom_drawer.dart'; import '../../routes/custom_drawer.dart';
import '../../routes/custom_router.dart';
import '../../services/apiService.dart'; import '../../services/apiService.dart';
import '../../utils/auth_utils.dart'; import '../../utils/auth_utils.dart';
import '../../utils/pagination.dart'; import '../../utils/pagination.dart';
@ -35,6 +39,7 @@ class _ListPlansState extends State<ListPlans> {
String? userId; String? userId;
String? orgId; String? orgId;
String? roleUser;
String? token; String? token;
String? TripPlanAction; String? TripPlanAction;
@ -44,37 +49,115 @@ class _ListPlansState extends State<ListPlans> {
List<Plan> allPlans = []; List<Plan> allPlans = [];
List<Plan> filteredPlans = []; List<Plan> filteredPlans = [];
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
String? location;
late bool _dialogShown = false;
late StreamSubscription<html.PopStateEvent> _popStateListener;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// futurePlans = fetchPlans(); _checkAuthAndLoadData();
// checkbackbutton();
// futurePlans.then((plans) {
// setState(() {
// allPlans = plans;
// filteredPlans = plans;
// });
// });
// getToken();
// initializeData();
// loadInitialData();
}
void checkbackbutton() async {
roleUser = await getRoleUser();
print(roleUser);
if (roleUser == "User") {
print("user");
// Push a dummy state so back button triggers popstate instead of navigating
html.window.history.pushState(null, '', html.window.location.href);
_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();
}
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"),
),
],
),
);
}
Future<void> _logoutAndRedirect(BuildContext context) async {
print("logue 0");
// Example: clear session or shared preferences
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
context.go("/");
print("logue 1");
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
} else {
if (roleUser == "User") {
print("user");
// After login is successful and navigation completes:
WidgetsBinding.instance.addPostFrameCallback((_) {
checkbackbutton();
});
}
getToken(); getToken();
initializeData(); initializeData();
loadInitialData(); loadInitialData();
}
WidgetsBinding.instance.addPostFrameCallback((_) {
// initializeData();
// loadInitialData();
// futurePlans.then((plans) {
// setState(() {
// allPlans = plans;
// filteredPlans = plans;
// });
// });
});
// futurePlans = fetchPlans();
} }
void refresh() { void refresh() {
@ -135,6 +218,7 @@ class _ListPlansState extends State<ListPlans> {
token = await getToken(); token = await getToken();
userId = await getUserId(); userId = await getUserId();
orgId = await getOrgId(); orgId = await getOrgId();
roleUser = await getRoleUser();
TripPlanAction = await getTripPlanAction(); TripPlanAction = await getTripPlanAction();
if (token == null || userId == null) { if (token == null || userId == null) {
@ -325,13 +409,31 @@ class _ListPlansState extends State<ListPlans> {
} }
} }
void _handleBackButton() {
// final location = GoRouterState.of(context).uri.toString();
print("location - $location");
if (location!.contains('/listPlan')) {
// Do nothing or show "Press again to exit" toast
print("Blocked back on /listPlan");
} else {
print("/listPlan ..");
}
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder( return ResponsiveBuilder(
builder: (context, sizingInfo) { builder: (context, sizingInfo) {
bool isDesktop = bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop; sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return PopScope(
canPop: false, // Allow back navigation only if not login screen
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
_handleBackButton(); // Show exit confirmation dialog
},
child: Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
// 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),
@ -356,6 +458,7 @@ class _ListPlansState extends State<ListPlans> {
], ],
), ),
), ),
),
); );
}, },
); );

View File

@ -114,9 +114,40 @@ class _PolicyState extends State<Policy> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// WidgetsFlutterBinding.ensureInitialized(); // WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
// loadinitializeData();
//
// updateSelectedServices();
// updateData();
//
// loadInitialData();
//
// if (widget.policy != null) {
// final details = List<Map<String, dynamic>>.from(
// widget.policy!['policy_details'],
// );
// policyCriteriaKey.currentState?.loadPolicyDetails(details);
//
// policyCriteriaKey.currentState?.fetchTrainFlightClass();
// }
// });
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
loadinitializeData(); loadinitializeData();
updateSelectedServices(); updateSelectedServices();
@ -132,7 +163,9 @@ class _PolicyState extends State<Policy> {
policyCriteriaKey.currentState?.fetchTrainFlightClass(); policyCriteriaKey.currentState?.fetchTrainFlightClass();
} }
}); } catch (e) {
print("group : $e");
}
} }
void loadInitialData() async { void loadInitialData() async {

View File

@ -21,7 +21,8 @@ class PolicyList extends StatefulWidget {
class _PolicyListState extends State<PolicyList> { class _PolicyListState extends State<PolicyList> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futurePolicy; // late Future<List<dynamic>> futurePolicy;
Future<List<dynamic>>? futurePolicy;
late Map<String, dynamic> userSingleData; late Map<String, dynamic> userSingleData;
List<dynamic>? apiCountryData; List<dynamic>? apiCountryData;
@ -43,20 +44,48 @@ class _PolicyListState extends State<PolicyList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futurePolicy = fetchPolicy();
//
// futurePolicy.then((object) {
// setState(() {
// allPolicy = object;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// fetchPolicy();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futurePolicy = fetchPolicy(); futurePolicy = fetchPolicy();
futurePolicy.then((object) { futurePolicy?.then((object) {
setState(() { setState(() {
allPolicy = object; allPolicy = object;
}); });
}); });
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
fetchPolicy(); fetchPolicy();
}); } catch (e) {
print("group : $e");
// futurePlans = fetchPlans(); }
} }
void loadInitialData() async { void loadInitialData() async {
@ -91,7 +120,7 @@ class _PolicyListState extends State<PolicyList> {
setState(() { setState(() {
futurePolicy = fetchPolicy(); // Re-fetch users after status update futurePolicy = fetchPolicy(); // Re-fetch users after status update
futurePolicy.then((object) { futurePolicy?.then((object) {
setState(() { setState(() {
allPolicy = object; allPolicy = object;
}); });
@ -375,7 +404,7 @@ class _PolicyListState extends State<PolicyList> {
), ),
), ),
onPressed: () async { onPressed: () async {
List<dynamic> policyData = await futurePolicy; List? policyData = await futurePolicy;
// Print the resolved value // Print the resolved value
print("CREATELIAS - $policyData"); print("CREATELIAS - $policyData");
@ -454,6 +483,10 @@ class _PolicyListState extends State<PolicyList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futurePolicy, future: futurePolicy,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futurePolicy == null) {
return const CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -28,7 +28,8 @@ class TravellerListState extends State<TravellerList> {
GlobalKey<TravellerListState>(); GlobalKey<TravellerListState>();
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
late Future<List<dynamic>> futureTraveller; Future<List<dynamic>>? futureTraveller;
// late Future<List<dynamic>> futureTraveller;
late Map<String, dynamic> depSingleData; late Map<String, dynamic> depSingleData;
String? selectedTravellerId; String? selectedTravellerId;
@ -47,9 +48,37 @@ class TravellerListState extends State<TravellerList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_checkAuthAndLoadData();
// futureTraveller = fetchGetTraveller();
//
// futureTraveller.then((object) {
// setState(() {
// allTraveller = object;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// loadInitialData();
// });
// futurePlans = fetchPlans();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
}
if (!mounted) return;
try {
futureTraveller = fetchGetTraveller(); futureTraveller = fetchGetTraveller();
futureTraveller.then((object) { futureTraveller?.then((object) {
setState(() { setState(() {
allTraveller = object; allTraveller = object;
}); });
@ -58,8 +87,9 @@ class TravellerListState extends State<TravellerList> {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData(); loadInitialData();
}); });
} catch (e) {
// futurePlans = fetchPlans(); print("group : $e");
}
} }
void loadInitialData() async { void loadInitialData() async {
@ -89,7 +119,7 @@ class TravellerListState extends State<TravellerList> {
futureTraveller = fetchGetTraveller(); futureTraveller = fetchGetTraveller();
return futureTraveller.then((object) { return futureTraveller!.then((object) {
print("Calling Refresh Data $object"); print("Calling Refresh Data $object");
setState(() { setState(() {
allTraveller = object; allTraveller = object;
@ -147,14 +177,16 @@ class TravellerListState extends State<TravellerList> {
final lowerQuery = query.toLowerCase().trim(); final lowerQuery = query.toLowerCase().trim();
setState(() { setState(() {
filteredTraveller = allTraveller.where((object) { filteredTraveller =
allTraveller.where((object) {
final travellerId = object['traveller_id']?.toLowerCase() ?? ''; final travellerId = object['traveller_id']?.toLowerCase() ?? '';
final firstName = object['first_name']?.toLowerCase() ?? ''; final firstName = object['first_name']?.toLowerCase() ?? '';
final lastName = object['last_name']?.toLowerCase() ?? ''; final lastName = object['last_name']?.toLowerCase() ?? '';
final fullName = '$firstName $lastName'; final fullName = '$firstName $lastName';
final mobile = object['mobile']?.toLowerCase() ?? ''; final mobile = object['mobile']?.toLowerCase() ?? '';
final email = object['email']?.toLowerCase() ?? ''; final email = object['email']?.toLowerCase() ?? '';
final isActiveStatus = object['is_active'] == "1" ? "active" : "inactive"; final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive";
return travellerId.contains(lowerQuery) || return travellerId.contains(lowerQuery) ||
firstName.contains(lowerQuery) || firstName.contains(lowerQuery) ||
@ -411,6 +443,10 @@ class TravellerListState extends State<TravellerList> {
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureTraveller, future: futureTraveller,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureTraveller == null) {
return CircularProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || } else if (snapshot.hasError ||

View File

@ -56,6 +56,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String? orgId; String? orgId;
String? userIdApi; String? userIdApi;
bool isCheckingToken = false;
String? token; String? token;
late bool isapiselectedUser = false; late bool isapiselectedUser = false;
@ -152,10 +154,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"date_of_birth": controllers["dob"]?.text, "date_of_birth": controllers["dob"]?.text,
"address": controllers["address"]?.text, "address": controllers["address"]?.text,
"gender": selectedGender, "gender": selectedGender,
// "gender": personalDetailsKey.currentState?.selectedGender, // "gender": personalDetailsKey.currentState?.selectedGender,
// "agent_supported_service_ids": selectedServiceIds, // "agent_supported_service_ids": selectedServiceIds,
"agent_supported_service_ids": selectedServiceIds, "agent_supported_service_ids": selectedServiceIds,
"postal_code": controllers["postalCode"]?.text, "postal_code": controllers["postalCode"]?.text,
"country_code": selectedCountry, "country_code": selectedCountry,
"employee_code": controllers["employeeCode"]?.text, "employee_code": controllers["employeeCode"]?.text,
@ -338,8 +340,161 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
} }
@override @override
// void initState() {
// super.initState();
// prepareForNewEntry();
// selectedTab = "personal";
//
// // WidgetsFlutterBinding.ensureInitialized();
//
// // Step 1: Set 'reloaded' flag before page unload
// // html.window.onBeforeUnload.listen((event) {
// // html.window.localStorage['reloaded'] = 'true';
// // });
//
// apiCountryData = null;
// apiUserData = null;
// // apiselectedUser = null;
// apiCostData = null;
// apiRoleData = null;
//
// // Initialize controllers for each field
//
// WidgetsBinding.instance.addPostFrameCallback((_) async {
// // final wasReloaded = html.window.localStorage['reloaded'] == 'true';
// //
// // if (wasReloaded) {
// // html.window.localStorage.remove('reloaded'); // Clear it
// // context.go('/listUser'); // Navigate using go_router
// // }
//
// final extraData =
// GoRouterState.of(context).extra as Map<String, dynamic>?;
//
// if (extraData != null) {
// print("extraData: ${extraData['selectedUser']}");
//
// setState(() {
// // apiCountryData = extraData['apiCountryData'];
// // apiUserData = extraData['apiUserData'];
// //
// // userList = apiUserData ?? [];
// // userMap = {
// // for (var user in userList)
// // user['user_id'].toString(): "${user['first_name']} ${user['last_name']}"
// // };
// // userIdsApi = userMap.keys.toList();
//
// // Handle selectedUser as a Map (not a List)
// apiselectedUser =
// extraData['selectedUser']
// as Map<String, dynamic>?; // Cast it as a Map
// isViewMode = extraData['isViewMode'] ?? false;
// isEditProfile = extraData['isEditProfile'] ?? false;
// });
//
// print("selectedUser: $apiselectedUser");
//
// // Add another post-frame callback to check after setState
// // await Future.delayed(Duration(
// // milliseconds: 100)); // Optional delay to ensure UI has updated
// updateData();
// }
//
// initializeData();
// fetchCountries();
// fetchDepartment();
// fetchUsers();
// fetchRoles();
// loadInitialData();
// });
//
// for (var field in dataHeader) {
// controllers[field] = TextEditingController();
// }
// }
void initState() { void initState() {
super.initState(); super.initState();
setState(() {
isCheckingToken = true;
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkAuthAndLoadData(); // Safe place to use context
});
}
void _checkAuthAndLoadData() async {
setState(() {
isCheckingToken = true;
});
final String? token = await getToken();
if (!mounted) return;
if (token == null || token.isEmpty) {
context.go("/");
return;
}
setState(() {
isCheckingToken = false;
});
prepareForNewEntry();
selectedTab = "personal";
apiCountryData = null;
apiUserData = null;
apiCostData = null;
apiRoleData = null;
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
/// Now this is safe here
try {
final extraData = GoRouterState.of(context).extra;
if (extraData != null && extraData is Map<String, dynamic>) {
setState(() {
apiselectedUser = extraData['selectedUser'] as Map<String, dynamic>?;
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
});
updateData();
}
} catch (e) {
print("Router extra error: $e");
}
// Final async data fetches
initializeData();
fetchCountries();
fetchDepartment();
fetchUsers();
fetchRoles();
loadInitialData();
}
void _checkAuthAndLoadData22() async {
final String? token = await getToken(); // Your async function to get token
if (!mounted) return;
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
setState(() {
isCheckingToken = false;
});
return;
} else {
if (!mounted) return;
// Future.microtask(() {
prepareForNewEntry(); prepareForNewEntry();
selectedTab = "personal"; selectedTab = "personal";
@ -358,7 +513,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Initialize controllers for each field // Initialize controllers for each field
WidgetsBinding.instance.addPostFrameCallback((_) async { // WidgetsBinding.instance.addPostFrameCallback((_) async {
// if (!mounted) return;
// final wasReloaded = html.window.localStorage['reloaded'] == 'true'; // final wasReloaded = html.window.localStorage['reloaded'] == 'true';
// //
// if (wasReloaded) { // if (wasReloaded) {
@ -405,11 +561,17 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
fetchUsers(); fetchUsers();
fetchRoles(); fetchRoles();
loadInitialData(); loadInitialData();
});
for (var field in dataHeader) { for (var field in dataHeader) {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
setState(() {
isCheckingToken = false;
});
// });
}
} }
Future<void> fetchCountries() async { Future<void> fetchCountries() async {
@ -952,9 +1114,15 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Encode travel_details as a proper JSON string // Encode travel_details as a proper JSON string
request.fields[key] = jsonEncode(value); request.fields[key] = jsonEncode(value);
print("✅ Encoded travel_details: ${request.fields[key]}"); print("✅ Encoded travel_details1: ${request.fields[key]}");
} else if (key == 'agent_supported_service_ids' && value is List) {
request.fields[key] = jsonEncode(value);
print("✅ Encoded agent_supported_service_ids: ${request.fields[key]}");
} else { } else {
// request.fields[key] = jsonEncode(value);
print("✅ Encoded travel_details:${key} - ${value}");
request.fields[key] = value.toString(); request.fields[key] = value.toString();
print("✅ Encoded travel_details2: ${request.fields[key]}");
} }
// } // }
}); });
@ -1043,6 +1211,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
bool isDesktop = bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop; sizingInfo.deviceScreenType == DeviceScreenType.desktop;
if (isCheckingToken) {
return Center(child: CircularProgressIndicator());
}
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '), // appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),

View File

@ -452,8 +452,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
selectedServiceIds.add({"service_id": serviceId}); selectedServiceIds.add({"service_id": serviceId});
} }
print("selectedServiceIdsUser --- $selectedServiceIds"); print("selectedServiceIdsUser --- $selectedServiceIds");
print(
"selectedServiceIdsUser1 --- ${json.encode(selectedServiceIds)}",
);
// Call the parent's callback // Call the parent's callback
widget.onServiceIdsChanged!(selectedServiceIds); widget.onServiceIdsChanged!(selectedServiceIds);
// widget.onServiceIdsChanged!(selectedServiceIds);
}); });
}, },
child: Row( child: Row(

View File

@ -2377,6 +2377,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserTravellerWrapper( CustomTextFieldUserTravellerWrapper(
width: width:
widget.isDesktop widget.isDesktop
@ -2675,14 +2676,14 @@ class TravellerDetailsState extends State<TravellerDetails> {
); );
} }
return Text( return Text(
selectedItem['dropdown_value'] ?? 'Select Seat"', selectedItem['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
); );
}, },
items: seatOptionsInt, items: seatOptionsInt,
selectedItem: selectedItem:
selectedIntenationalSeat == null selectedIntenationalSeat == null
? {"dropdown_value": "Select Seat"} ? null
: {"dropdown_value": selectedIntenationalSeat}, : {"dropdown_value": selectedIntenationalSeat},
onChanged: onChanged:
widget.isViewMode widget.isViewMode
@ -3673,7 +3674,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
" * I confirm my 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

@ -46,6 +46,31 @@ class _UserListScreenState extends State<UserListScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// futureUsers = fetchUsers();
//
// futureUsers.then((users) {
// setState(() {
// allUsers = users;
// });
// });
//
// WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// loadInitialData();
// });
_checkAuthAndLoadData();
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
return;
} else {
futureUsers = fetchUsers(); futureUsers = fetchUsers();
futureUsers.then((users) { futureUsers.then((users) {
@ -53,13 +78,13 @@ class _UserListScreenState extends State<UserListScreen> {
allUsers = users; allUsers = users;
}); });
}); });
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCountryList(); fetchCountryList();
loadInitialData(); loadInitialData();
}); // WidgetsBinding.instance.addPostFrameCallback((_) {
// fetchCountryList();
// futurePlans = fetchPlans(); // loadInitialData();
// });
}
} }
void loadInitialData() async { void loadInitialData() async {
@ -194,8 +219,7 @@ class _UserListScreenState extends State<UserListScreen> {
print("handDel - $userId"); print("handDel - $userId");
} }
Future<void> handleUpload ()async { Future<void> handleUpload() async {
final String apiUrldata = '$apiUrl/api/user/userUpload'; // api final String apiUrldata = '$apiUrl/api/user/userUpload'; // api
final String? token = await getToken(); // 2kn final String? token = await getToken(); // 2kn
@ -227,7 +251,6 @@ class _UserListScreenState extends State<UserListScreen> {
return; return;
} }
if (reader.readyState == html.FileReader.DONE) { if (reader.readyState == html.FileReader.DONE) {
Uint8List? fileBytes = reader.result as Uint8List?; Uint8List? fileBytes = reader.result as Uint8List?;
if (fileBytes != null) { if (fileBytes != null) {
@ -253,15 +276,23 @@ class _UserListScreenState extends State<UserListScreen> {
// formData.appendBlob('file', html.Blob([fileBytes]), fileName); // formData.appendBlob('file', html.Blob([fileBytes]), fileName);
// Create a multipart request // Create a multipart request
final request = http.MultipartRequest('POST', Uri.parse(apiUrldata)); final request = http.MultipartRequest(
'POST',
Uri.parse(apiUrldata),
);
// Attach the file to the request // Attach the file to the request
// Set authorization token in headers // Set authorization token in headers
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
// request.files.add(http.MultipartFile.fromBytes('file', fileBytes, filename: fileName)); // request.files.add(http.MultipartFile.fromBytes('file', fileBytes, filename: fileName));
request.files.add(http.MultipartFile.fromBytes( 'user_file', fileBytes, filename: 'user_file.xlsx' )); request.files.add(
http.MultipartFile.fromBytes(
'user_file',
fileBytes,
filename: 'user_file.xlsx',
),
);
print('request : $request'); print('request : $request');
// Send the request // Send the request
@ -446,6 +477,10 @@ class _UserListScreenState extends State<UserListScreen> {
// Refresh user list after update // Refresh user list after update
void refreshUserList() { void refreshUserList() {
setState(() { setState(() {
print("Search cleared 1");
searchController.clear(); // or wrap in setState if needed
print("Search cleared - ${searchController.text}");
filteredUsers = [];
futureUsers = fetchUsers(); futureUsers = fetchUsers();
futureUsers.then((users) { futureUsers.then((users) {
@ -573,8 +608,9 @@ class _UserListScreenState extends State<UserListScreen> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.15), SizedBox(width: MediaQuery.of(context).size.width * 0.23),
// SizedBox(width: MediaQuery.of(context).size.width * 0.15),
if (isDesktop) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -616,27 +652,62 @@ class _UserListScreenState extends State<UserListScreen> {
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
Spacer(), Spacer(),
OutlinedButton(
onPressed: () { apiService.getDownloadUserTemplateForUpload(); }, // OutlinedButton(
style: OutlinedButton.styleFrom( // onPressed: () {
backgroundColor: Colors.white, // apiService.getDownloadUserTemplateForUpload();
foregroundColor: Color(0xFF114D8B), // },
side: BorderSide(color: Colors.white), // style: OutlinedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16), // backgroundColor: Colors.white,
// foregroundColor: Color(0xFF114D8B),
// side: BorderSide(color: Colors.white),
// padding: EdgeInsets.symmetric(
// horizontal: 20,
// vertical: 16,
// ),
// ),
// child: Text("Sample Template Download"),
// ),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/download.png',
width: 25,
height: 25,
), ),
child: Text("Sample Template Download"), tooltip: 'Sample Template Download',
), Spacer(), onPressed: () {
apiService.getDownloadUserTemplateForUpload();
},
),
SizedBox(width: 5),
// Upload Button // Upload Button
OutlinedButton( // OutlinedButton(
onPressed: handleUpload, // onPressed: handleUpload,
style: OutlinedButton.styleFrom( // style: OutlinedButton.styleFrom(
backgroundColor: Colors.white, // backgroundColor: Colors.white,
foregroundColor: Color(0xFF114D8B), // foregroundColor: Color(0xFF114D8B),
side: BorderSide(color: Colors.white), // side: BorderSide(color: Colors.white),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16), // padding: EdgeInsets.symmetric(
// horizontal: 20,
// vertical: 16,
// ),
// ),
// child: Text("User Bulk Upload"),
// ),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/upload.png',
width: 25,
height: 25,
), ),
child: Text("User Bulk Upload"), tooltip: 'User Bulk Upload',
), Spacer(), onPressed: () {
handleUpload();
},
),
// Spacer(),
SizedBox(width: 5),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), backgroundColor: Color(0xFF114D8B),

View File

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'dart:html' as html; import 'dart:html' as html;
import 'package:frontend/config/apiUrl.dart'; // 1 newly added import 'package:frontend/config/apiUrl.dart'; // 1 newly added
import 'package:frontend/services/apiService.dart'; import 'package:frontend/services/apiService.dart';
@ -31,10 +31,12 @@ class _MyAppState extends State<MyApp> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// SemanticsBinding.instance.ensureSemantics(); // Safe here SemanticsBinding.instance.ensureSemantics(); // Safe here
if (kIsWeb) { if (kIsWeb) {
final uri = Uri.parse(html.window.location.href); final uri = Uri.parse(html.window.location.href);
if (uri.path == '/authredirection' && print("URI - $uri");
if (uri.path == '/tstat/authredirection' &&
uri.queryParameters['code'] != null) { uri.queryParameters['code'] != null) {
_authCode = uri.queryParameters['code']; _authCode = uri.queryParameters['code'];
// _isAuthRedirect = true; // _isAuthRedirect = true;
@ -51,7 +53,7 @@ class _MyAppState extends State<MyApp> {
} }
} }
Future<void> handleTokenUsingMS(authCode) async { Future<void> handleTokenUsingMS(String? authCode) async {
if (authCode == null) return; if (authCode == null) return;
final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode'; final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
@ -62,10 +64,11 @@ class _MyAppState extends State<MyApp> {
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
final MS_Token = json.decode(response.body)['token']; final responseBody = json.decode(response.body);
final MS_Token = responseBody['token'];
print("MS_Token - $MS_Token"); print("MS_Token - $MS_Token");
if (MS_Token != '') { if (MS_Token != null && MS_Token != '') {
print('Microsoft - Token Available'); print('Microsoft - Token Available');
await storeUserDetails(MS_Token); await storeUserDetails(MS_Token);
@ -79,20 +82,78 @@ class _MyAppState extends State<MyApp> {
router.go('/listPlan'); router.go('/listPlan');
} }
} else { } else {
print('Microsoft - Token Not Available'); throw Exception('Token not found in response.');
throw Exception('Token not Founded');
} }
} else { } else {
final errorMessage = json.decode(response.body)['message']; // Handle 400/401/500 etc.
print(errorMessage); String errorMsg;
throw Exception(errorMessage); try {
final decoded = json.decode(response.body);
errorMsg = decoded['message'] ?? 'Unknown error';
} catch (_) {
errorMsg = response.body; // fallback to plain text
} }
} catch (e) {
print("Error response: $errorMsg");
throw Exception("Authentication failed: $errorMsg");
}
} catch (e, stack) {
print("Caught error: $e");
router.go('/'); router.go('/');
print("Error: $e");
} }
} }
// Future<void> handleTokenUsingMS(authCode) async {
// if (authCode == null) return;
//
// final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
// try {
// final response = await http.get(
// Uri.parse(url),
// headers: {'Content-Type': 'application/json'},
// );
//
// if (response.statusCode == 200) {
// final MS_Token = json.decode(response.body)['token'];
// print("MS_Token - $MS_Token");
//
// if (MS_Token != '') {
// print('Microsoft - Token Available');
// await storeUserDetails(MS_Token);
//
// print("userRole - $userRole");
//
// if (userRole == "Travel Agent") {
// router.go('/listTravelAgentPlan');
// } else if (userRole == "Org Admin" || userRole == "Travel Admin") {
// router.go('/listAllPlan');
// } else {
// router.go('/listPlan');
// }
// } else {
// print('Microsoft - Token Not Available');
// throw Exception('Token not Founded');
// }
// } else {
// // final errorMessage = json.decode(response.body)['message'];
// // print(errorMessage);
// // throw Exception(errorMessage);
//
// try {
// final errorMessage = json.decode(response.body)['message'];
// print(errorMessage);
// throw Exception(errorMessage);
// } catch (_) {
// print("Non-JSON error from server: ${response.body}");
// throw Exception("Authentication failed: ${response.body}");
// }
// }
// } catch (e) {
// router.go('/');
// print("Error: $e");
// }
// }
Future<void> storeUserDetails(String token) async { Future<void> storeUserDetails(String token) async {
try { try {
final parts = token.split('.'); final parts = token.split('.');

View File

@ -295,9 +295,26 @@ class _CustomAppBarState extends State<CustomAppBar> {
context.go('/'); context.go('/');
} }
void _handleBackButton() {
if (selectedTab == TabSelection.dashboard) {
// Do nothing or show "Press again to exit" toast
print("Blocked back on dashboard");
} else {
setState(() {
selectedTab = TabSelection.dashboard;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppBar( return PopScope(
canPop: false, // Allow back navigation only if not login screen
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
_handleBackButton(); // Show exit confirmation dialog
},
child: AppBar(
backgroundColor: Colors.white, backgroundColor: Colors.white,
surfaceTintColor: Colors.white, surfaceTintColor: Colors.white,
// elevation: 3, // elevation: 3,
@ -331,7 +348,11 @@ class _CustomAppBarState extends State<CustomAppBar> {
width: 130, //130 width: 130, //130
height: 80, //80 height: 80, //80
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) { errorBuilder: (
context,
error,
stackTrace,
) {
return const CircleAvatar( return const CircleAvatar(
radius: 20, radius: 20,
child: Icon( child: Icon(
@ -372,7 +393,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
'/StatusDashboard', '/StatusDashboard',
), ),
layoutColor!, layoutColor!,
isSelected: selectedTab == TabSelection.dashboard, isSelected:
selectedTab == TabSelection.dashboard,
icon: Icons.dashboard, icon: Icons.dashboard,
// icon: Icons.insights_outlined, // icon: Icons.insights_outlined,
), ),
@ -388,7 +410,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
'/listAllPlan', '/listAllPlan',
), ),
layoutColor!, layoutColor!,
isSelected: selectedTab == TabSelection.allTrips, isSelected:
selectedTab == TabSelection.allTrips,
icon: Icons.format_list_bulleted_rounded, icon: Icons.format_list_bulleted_rounded,
// icon: Icons.insights_outlined, // icon: Icons.insights_outlined,
), ),
@ -407,7 +430,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
icon: Icons.shopping_bag_outlined, icon: Icons.shopping_bag_outlined,
// icon: Icons.request_page_outlined, // icon: Icons.request_page_outlined,
), ),
if (userData?["role"] != "Travel Agent") // for others if (userData?["role"] !=
"Travel Agent") // for others
buildNavItem( buildNavItem(
"My Trips", "My Trips",
() => handleTabChange( () => handleTabChange(
@ -454,7 +478,10 @@ class _CustomAppBarState extends State<CustomAppBar> {
(context) => PopupMenuButton<String>( (context) => PopupMenuButton<String>(
color: Colors.white, color: Colors.white,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
offset: const Offset(0, 50), // 👈 shift it 50 pixels down offset: const Offset(
0,
50,
), // 👈 shift it 50 pixels down
onSelected: (String value) { onSelected: (String value) {
switch (value) { switch (value) {
case '/OrganizationSettings': case '/OrganizationSettings':
@ -509,7 +536,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
menuItems menuItems
.where( .where(
(item) => (item) =>
item['value'] == '/CreateUserDetails' || item['value'] ==
'/CreateUserDetails' ||
item['value'] == '/logout', item['value'] == '/logout',
) )
.toList(); .toList();
@ -617,6 +645,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
color: layoutColor, // Set the color of the bottom border color: layoutColor, // Set the color of the bottom border
), ),
), ),
),
); );
} }

View File

@ -105,6 +105,8 @@ flutter:
- assets/images/IconsImg/Frame.png - assets/images/IconsImg/Frame.png
- assets/images/IconsImg/delete.png - assets/images/IconsImg/delete.png
- assets/images/IconsImg/edit.png - assets/images/IconsImg/edit.png
- assets/images/IconsImg/upload.png
- assets/images/IconsImg/download.png
- assets/images/IconsImg/planPdf_icon.png - assets/images/IconsImg/planPdf_icon.png