user mangement bugs

This commit is contained in:
venbaittech 2025-06-05 12:40:16 +05:30
parent 7c9968c159
commit b246c79789
15 changed files with 4932 additions and 3769 deletions

View File

@ -63,11 +63,13 @@ class _ApprovalListState extends State<ApprovalList> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -239,8 +241,10 @@ class _ApprovalListState extends State<ApprovalList> {
// print("Error fetching plan: $e");
// }
bool confirmed =
await apiService.showCancelConfirmationDialog(context, layoutColor);
bool confirmed = await apiService.showCancelConfirmationDialog(
context,
layoutColor,
);
if (confirmed) {
try {
@ -282,17 +286,23 @@ class _ApprovalListState extends State<ApprovalList> {
}
}
void viewPlanforApprover(String planId,
{bool isViewMode = false, bool isApprover = true}) async {
void viewPlanforApprover(
String planId, {
bool isViewMode = false,
bool isApprover = true,
}) async {
try {
Map<String, dynamic> planData = await getViewPlan(planId);
print("ViewAAA - $planData");
context.go('/createPlan', extra: {
context.go(
'/createPlan',
extra: {
'planData': planData,
'isViewMode': isViewMode,
'isApprover': isApprover
});
'isApprover': isApprover,
},
);
} catch (e) {
print("Error fetching plan: $e");
}
@ -314,12 +324,15 @@ class _ApprovalListState extends State<ApprovalList> {
print("allPlans before filtering: $allPlans");
final lowerQuery = query.toLowerCase();
setState(() {
filteredPlans = allPlans.where((plan) {
filteredPlans =
allPlans.where((plan) {
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ??
false) ||
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ??
false) ||
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
@ -330,8 +343,10 @@ class _ApprovalListState extends State<ApprovalList> {
}
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -340,23 +355,27 @@ class _ApprovalListState extends State<ApprovalList> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
child: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(child: buildGroupListLayout(isDesktop))
Expanded(child: buildGroupListLayout(isDesktop)),
],
),
),
);
});
},
);
}
Widget buildGroupListLayout(bool isDesktop) {
@ -383,11 +402,14 @@ class _ApprovalListState extends State<ApprovalList> {
// }
// }
final adjHgt = MediaQuery.of(context).size.height;
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd, MMM yyyy HH:mm')
.format(dateTime); // 24-hour format
return DateFormat(
'dd, MMM yyyy HH:mm',
).format(dateTime); // 24-hour format
} catch (e) {
return rawDate; // fallback if parsing fails
}
@ -396,11 +418,13 @@ class _ApprovalListState extends State<ApprovalList> {
return Container(
margin: isDesktop ? EdgeInsets.all(10.0) : null,
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
border: isDesktop
border:
isDesktop
? Border.all(
width: 2,
color: Colors.white,
@ -444,9 +468,7 @@ class _ApprovalListState extends State<ApprovalList> {
],
),
if (isDesktop)
SizedBox(
width: MediaQuery.of(context).size.width * 0.23,
),
SizedBox(width: MediaQuery.of(context).size.width * 0.23),
if (isDesktop)
Container(
@ -457,8 +479,10 @@ class _ApprovalListState extends State<ApprovalList> {
onChanged: filterPlans,
decoration: InputDecoration(
hintText: "Search...",
hintStyle:
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
hintStyle: TextStyle(
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -470,27 +494,26 @@ class _ApprovalListState extends State<ApprovalList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
],
),
if (!isDesktop)
SizedBox(
height: 5,
),
if (!isDesktop) SizedBox(height: 5),
isDesktop
? SizedBox.shrink()
: Row(
@ -505,7 +528,9 @@ class _ApprovalListState extends State<ApprovalList> {
decoration: InputDecoration(
hintText: "Search...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -517,17 +542,19 @@ class _ApprovalListState extends State<ApprovalList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -548,7 +575,9 @@ class _ApprovalListState extends State<ApprovalList> {
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon(Icons.error_outline,
// color: Colors.redAccent, size: 60),
// SizedBox(height: 1),
@ -557,14 +586,18 @@ class _ApprovalListState extends State<ApprovalList> {
// fontSize: 22,
// fontWeight: FontWeight.bold,
// color: Colors.redAccent)),
SizedBox(height: 15),
Text("No Trips Pending For Your Approvals",
SizedBox(height: adjHgt / 4),
Text(
" No Trips Pending For Your Approvals",
textAlign: TextAlign.center,
style: TextStyle(
style: GoogleFonts.poppins(
fontSize: 20,
fontFamily: "Inter",
// fontFamily: "Inter",
fontWeight: FontWeight.w600,
color: Colors.black54)),
color: Colors.black54,
),
),
],
),
),
@ -580,10 +613,13 @@ class _ApprovalListState extends State<ApprovalList> {
List<Plan> plans =
searchController.text.isEmpty ? allPlans : filteredPlans;
plans.sort((a, b) =>
int.parse(b.planId).compareTo(int.parse(a.planId)));
plans.sort(
(a, b) =>
int.parse(b.planId).compareTo(int.parse(a.planId)),
);
List<Plan> paginatedPlans = plans
List<Plan> paginatedPlans =
plans
.skip(currentPage * itemsPerPage)
.take(itemsPerPage)
.toList();
@ -593,125 +629,178 @@ class _ApprovalListState extends State<ApprovalList> {
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth,
),
constraints: BoxConstraints(minWidth: minWidth),
child: DataTable(
dividerThickness: 0.5,
columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder(
horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200),
width: 0.5,
color: Colors.grey.shade200,
),
),
columns: [
DataColumn(
label: Text(
'Trip ID',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Trip Name',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Emp Code',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Traveller',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Trip Type',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Created On',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Status',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Actions',
style: GoogleFonts.poppins(
fontSize: 13, fontWeight: FontWeight.w600),
)),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
],
rows: paginatedPlans.map((plan) {
return DataRow(cells: [
DataCell(Text(plan.planId,
rows:
paginatedPlans.map((plan) {
return DataRow(
cells: [
DataCell(
Text(
plan.planId,
style: TextStyle(
fontSize: 13,
fontFamily: "Archivo",
))),
),
),
),
DataCell(Text(plan.tripTitle,
DataCell(
Text(
plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text(plan.employeeCode ?? " - ",
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
plan.employeeCode ?? " - ",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(
),
),
),
DataCell(
Text(
plan.userName.isNotEmpty
? plan.userName
: plan.travellerName,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(plan.tripType,
),
),
),
DataCell(
Text(
plan.tripType,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(
),
),
),
DataCell(
Text(
// plan.createdOn,
_formatDate(plan.createdOn),
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
),
),
),
DataCell(
Container(
width: double
width:
double
.infinity, // Set your desired fixed size (equal width and height)
height: 25,
alignment: Alignment.center,
decoration: BoxDecoration(
color: getStatusColor(plan.statusValue),
borderRadius: BorderRadius.circular(8),
color: getStatusColor(
plan.statusValue,
),
borderRadius: BorderRadius.circular(
8,
),
),
child: Text(
plan.statusValue,
textAlign: TextAlign.center,
style: TextStyle(
color:
getStatusTextColor(plan.statusValue),
color: getStatusTextColor(
plan.statusValue,
),
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.w400,
@ -732,96 +821,143 @@ class _ApprovalListState extends State<ApprovalList> {
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
itemBuilder:
(context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
padding:
EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize:
MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
MainAxisAlignment
.center,
children: [
IconButton(
icon: Icon(
Icons.remove_red_eye,
color:
Color(0xFF475569),
size: 18),
tooltip: 'View The Trip Details',
Icons
.remove_red_eye,
color: Color(
0xFF475569,
),
size: 18,
),
tooltip:
'View The Trip Details',
onPressed: () {
Navigator.pop(
context); // Close popup manually
context,
); // Close popup manually
viewPlanforApprover(
plan.planId,
isViewMode: true,
isApprover: true);
}),
isViewMode:
true,
isApprover:
true,
);
},
),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15),
tooltip: 'Edit The Trip Details',
height: 15,
),
tooltip:
'Edit The Trip Details',
onPressed: () {
print(
"Approver Edit : ${plan.approverId}");
"Approver Edit : ${plan.approverId}",
);
print(
"Approver Edit2 : ${plan.delegaterId}");
Navigator.pop(context);
ApiService
.viewPlanForApprover(
"Approver Edit2 : ${plan.delegaterId}",
);
Navigator.pop(
context,
);
ApiService.viewPlanForApprover(
context,
plan.planId,
plan.approverId,
plan.delegaterId,
isViewMode: false,
isApprover: true);
isViewMode:
false,
isApprover:
true,
);
},
),
IconButton(
icon: Icon(
Icons.cancel_rounded,
size: 18),
tooltip: 'Cancellation The Trip Details',
Icons
.cancel_rounded,
size: 18,
),
tooltip:
'Cancellation The Trip Details',
onPressed: () {
Navigator.pop(context);
deletePlan(plan.planId);
Navigator.pop(
context,
);
deletePlan(
plan.planId,
);
},
),
IconButton(
icon: Icon(Icons.download,
color: Color(0xFF114D8B),
size: 18),
tooltip: 'Download The Trip Details',
icon: Icon(
Icons.download,
color: Color(
0xFF114D8B,
),
size: 18,
),
tooltip:
'Download The Trip Details',
onPressed: () {
Navigator.pop(context);
apiService.getPdfDownload(
plan.planId);
Navigator.pop(
context,
);
apiService
.getPdfDownload(
plan.planId,
);
},
),
IconButton(
icon: const Icon(
Icons.comment,
color: Color(0xFF475569),
color: Color(
0xFF475569,
),
size: 11,
),
tooltip: 'Approver Comment',
tooltip:
'Approver Comment',
onPressed: () {
showDialog(
context: context,
builder: (context) =>
CommentModalList(
context:
context,
builder:
(
context,
) => CommentModalList(
// planId: plan.planId,
planId: plan
.planId
planId:
plan.planId
.toString(),
layoutColorForUser:
layoutColor!,
role:
"Approver"),
"Approver",
),
);
}),
},
),
],
),
),
@ -880,7 +1016,8 @@ class _ApprovalListState extends State<ApprovalList> {
// apiService.getPdfDownload(plan.planId);
// }),
// ])),
]);
],
);
}).toList(),
),
);
@ -894,8 +1031,10 @@ class _ApprovalListState extends State<ApprovalList> {
final plan = paginatedPlans[index];
return Card(
color: Colors.white,
margin:
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
margin: EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -912,7 +1051,9 @@ class _ApprovalListState extends State<ApprovalList> {
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: getStatusColor(plan.statusValue),
borderRadius: BorderRadius.circular(8),
@ -921,7 +1062,8 @@ class _ApprovalListState extends State<ApprovalList> {
plan.statusValue,
style: TextStyle(
color: getStatusTextColor(
plan.statusValue),
plan.statusValue,
),
fontSize: 10,
fontWeight: FontWeight.w600,
),
@ -936,92 +1078,119 @@ class _ApprovalListState extends State<ApprovalList> {
color: Color(0xFF475569),
size: 14,
),
itemBuilder: (context) => [
itemBuilder:
(context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
horizontal: 8,
vertical: 8,
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize:
MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(
Icons.remove_red_eye,
color:
Color(0xFF475569),
size: 18),
tooltip: 'View The Trip Details',
color: Color(
0xFF475569,
),
size: 18,
),
tooltip:
'View The Trip Details',
onPressed: () {
Navigator.pop(
context); // Close popup manually
context,
); // Close popup manually
viewPlanforApprover(
plan.planId,
isViewMode: true,
isApprover: true);
}),
isApprover: true,
);
},
),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15),
tooltip: 'Edit The Trip Details',
height: 15,
),
tooltip:
'Edit The Trip Details',
onPressed: () {
Navigator.pop(context);
ApiService
.viewPlanForApprover(
ApiService.viewPlanForApprover(
context,
plan.planId,
plan.approverId,
plan.delegaterId,
isViewMode: false,
isApprover: true);
isApprover: true,
);
},
),
IconButton(
icon: Icon(
Icons.cancel_rounded,
size: 18),
tooltip: 'Cancellation The Trip Details',
size: 18,
),
tooltip:
'Cancellation The Trip Details',
onPressed: () {
Navigator.pop(context);
deletePlan(plan.planId);
},
),
IconButton(
icon: Icon(Icons.download,
color: Color(0xFF114D8B),
size: 18),
tooltip: 'Download The Trip Details',
icon: Icon(
Icons.download,
color: Color(
0xFF114D8B,
),
size: 18,
),
tooltip:
'Download The Trip Details',
onPressed: () {
Navigator.pop(context);
apiService.getPdfDownload(
plan.planId);
apiService
.getPdfDownload(
plan.planId,
);
},
),
IconButton(
icon: const Icon(
Icons.comment,
color: Color(0xFF475569),
color: Color(
0xFF475569,
),
size: 11,
),
tooltip: 'Trip Comments',
onPressed: () {
showDialog(
context: context,
builder: (context) =>
CommentModalList(
builder:
(
context,
) => CommentModalList(
// planId: plan.planId,
planId: plan
.planId
planId:
plan.planId
.toString(),
layoutColorForUser:
layoutColor!,
role:
"Approver"),
"Approver",
),
);
}),
},
),
],
),
),
@ -1039,11 +1208,14 @@ class _ApprovalListState extends State<ApprovalList> {
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripTitle}',
Text(
' ${plan.tripTitle}',
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
fontWeight: FontWeight.bold,
),
),
],
),
],
@ -1058,24 +1230,28 @@ class _ApprovalListState extends State<ApprovalList> {
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripType}',
Text(
' ${plan.tripType}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
),
),
],
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('${_formatDate(plan.createdOn)}',
Text(
'${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
),
),
],
),
],
@ -1095,7 +1271,8 @@ class _ApprovalListState extends State<ApprovalList> {
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -1109,7 +1286,8 @@ class _ApprovalListState extends State<ApprovalList> {
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -1130,14 +1308,17 @@ class _ApprovalListState extends State<ApprovalList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: isDesktop
child:
isDesktop
? (searchController.text.isNotEmpty &&
filteredPlans.isEmpty
? Center(
child: Text(
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14, color: Colors.grey),
fontSize: 14,
color: Colors.grey,
),
),
)
: SingleChildScrollView(
@ -1150,7 +1331,9 @@ class _ApprovalListState extends State<ApprovalList> {
child: Text(
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14, color: Colors.grey),
fontSize: 14,
color: Colors.grey,
),
),
)
: buildMobileCardView(paginatedPlans)),
@ -1183,7 +1366,7 @@ class _ApprovalListState extends State<ApprovalList> {
),
);
},
)
),
],
),
),

View File

@ -156,6 +156,8 @@ class _LoginWidgetState extends State<LoginWidget> {
backgroundColor: Colors.red,
),
);
_emailController.clear();
_passwordController.clear();
// Fluttertoast.showToast(
// msg: "Login Failed: $errorMessage",
// toastLength: Toast.LENGTH_LONG,

View File

@ -67,11 +67,13 @@ class CostCenterListState extends State<CostCenterList> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -97,7 +99,6 @@ class CostCenterListState extends State<CostCenterList> {
}
Future<List<dynamic>> fetchGetCostCenter() async {
final String apiUrlData = '$apiUrl/api/getCostCenterMaster';
final String? token = await getToken();
@ -143,26 +144,30 @@ class CostCenterListState extends State<CostCenterList> {
print("all before filtering: $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredCostCenter = allCostCenter.where((object) {
filteredCostCenter =
allCostCenter.where((object) {
final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive";
return (object['cost_center_id']?.toLowerCase().contains(lowerQuery) ??
return (object['cost_center_id']?.toLowerCase().contains(
lowerQuery,
) ??
false) ||
(object['name']?.toLowerCase().contains(lowerQuery) ??
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ?? false) ||
(isActiveStatus.contains(lowerQuery));
}).toList();
currentPage = 0;
});
print("filteredCostCenter: $filteredCostCenter");
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -171,11 +176,14 @@ class CostCenterListState extends State<CostCenterList> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
@ -188,7 +196,8 @@ class CostCenterListState extends State<CostCenterList> {
),
),
);
});
},
);
}
Widget buildGroupList(bool isDesktop) {
@ -216,7 +225,8 @@ class CostCenterListState extends State<CostCenterList> {
// ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10),
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
@ -238,7 +248,7 @@ class CostCenterListState extends State<CostCenterList> {
Row(
children: [
Text(
'CostCenter Details',
'Cost Center Details',
style: GoogleFonts.poppins(
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
@ -248,9 +258,7 @@ class CostCenterListState extends State<CostCenterList> {
],
),
if (isDesktop)
SizedBox(
width: MediaQuery.of(context).size.width * 0.16,
),
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
if (isDesktop)
Container(
@ -262,7 +270,9 @@ class CostCenterListState extends State<CostCenterList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -274,17 +284,19 @@ class CostCenterListState extends State<CostCenterList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -298,16 +310,18 @@ class CostCenterListState extends State<CostCenterList> {
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side:
BorderSide(color: Color(0xFF114D8B), width: 2),
side: BorderSide(color: Color(0xFF114D8B), width: 2),
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12),
horizontal: 20,
vertical: 12,
),
),
onPressed: () async {
showDialog(
context: context,
builder: (context) => CostCenterData(
builder:
(context) => CostCenterData(
isDesktop: isDesktop,
layoutColor: layoutColor!,
fetchGetCostCenter: refreshData,
@ -339,10 +353,7 @@ class CostCenterListState extends State<CostCenterList> {
],
),
if (!isDesktop)
SizedBox(
height: 5,
),
if (!isDesktop) SizedBox(height: 5),
isDesktop
? SizedBox.shrink()
: Row(
@ -357,7 +368,9 @@ class CostCenterListState extends State<CostCenterList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -370,17 +383,18 @@ class CostCenterListState extends State<CostCenterList> {
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200,
width: 0.5),
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -418,14 +432,17 @@ class CostCenterListState extends State<CostCenterList> {
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.grey),
color: Colors.grey,
),
),
const SizedBox(height: 20),
Text(
"Please Create CostCenter Details",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey),
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 20),
],
@ -435,19 +452,21 @@ class CostCenterListState extends State<CostCenterList> {
}
/* Here collect the list to displayed the data in table or card Used */
List<dynamic> object =
filteredCostCenter.isNotEmpty ? filteredCostCenter : allCostCenter;
filteredCostCenter.isNotEmpty
? filteredCostCenter
: allCostCenter;
/* List is Sorting here */
object.sort((a, b) {
DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']);
return dateB
.compareTo(dateA); // Descending: newest first
return dateB.compareTo(dateA); // Descending: newest first
});
/* For pagination for list ... */
List paginatedCostCenter = object
List paginatedCostCenter =
object
.skip(currentPage * itemsPerPage)
.take(itemsPerPage)
.toList();
@ -455,8 +474,7 @@ class CostCenterListState extends State<CostCenterList> {
/* Table ... */
Widget table = LayoutBuilder(
builder: (context, constraints) {
double minWidth =
isDesktop ? constraints.maxWidth : 1300;
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
@ -465,7 +483,9 @@ class CostCenterListState extends State<CostCenterList> {
columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder(
horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200),
width: 0.5,
color: Colors.grey.shade200,
),
),
columns: [
DataColumn(
@ -473,48 +493,68 @@ class CostCenterListState extends State<CostCenterList> {
'Name',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Description',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Status',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Actions',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
],
rows: paginatedCostCenter.map((tableObject) {
String costcenterId = tableObject['cost_center_id']
rows:
paginatedCostCenter.map((tableObject) {
String costcenterId =
tableObject['cost_center_id']
.toString(); // Get user ID
bool isSelected = selectedCostCenterId == costcenterId;
bool isSelected =
selectedCostCenterId == costcenterId;
return DataRow(cells: [
DataCell(Text(tableObject['name'] ?? '',
return DataRow(
cells: [
DataCell(
Text(
tableObject['name'] ?? '',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(tableObject['description'] ?? 'N/A',
),
),
),
DataCell(
Text(
tableObject['description'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
tableObject['is_active'] == "1"
@ -523,7 +563,10 @@ class CostCenterListState extends State<CostCenterList> {
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
color: tableObject['is_active'] == "1" ? Colors.green : Colors.red,
color:
tableObject['is_active'] == "1"
? Colors.green
: Colors.red,
),
softWrap: true,
overflow: TextOverflow.ellipsis,
@ -550,22 +593,31 @@ class CostCenterListState extends State<CostCenterList> {
//
final costcenterId = int.tryParse(
tableObject['cost_center_id']
.toString());
.toString(),
);
if (costcenterId != null) {
print("Table cell - costcenter Id -- $costcenterId");
final data = await apiService.getCostCenterDetailsFind(costcenterId);
print(
"Table cell - costcenter Id -- $costcenterId",
);
final data = await apiService
.getCostCenterDetailsFind(
costcenterId,
);
print("CostCenterId -- $data");
showDialog(
context: context,
builder: (context) => CostCenterData(
builder:
(context) => CostCenterData(
isDesktop: isDesktop,
costcenterId: costcenterId, // Pass the ID
costcenterId:
costcenterId, // Pass the ID
costcenterData: data,
layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex,
fetchGetCostCenter: refreshData,
fetchGetCostCenter:
refreshData,
// role:
// "Travel Agent"
),
@ -576,7 +628,8 @@ class CostCenterListState extends State<CostCenterList> {
},
),
),
]);
],
);
}).toList(),
),
);
@ -592,7 +645,9 @@ class CostCenterListState extends State<CostCenterList> {
return Card(
color: Colors.white,
margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -612,7 +667,8 @@ class CostCenterListState extends State<CostCenterList> {
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.w700),
fontWeight: FontWeight.w700,
),
),
GestureDetector(
@ -630,23 +686,31 @@ class CostCenterListState extends State<CostCenterList> {
//
final costcenterId = int.tryParse(
cardObject['cost_center_id']
.toString());
.toString(),
);
if (costcenterId != null) {
print("costcenterId -- $costcenterId");
print(
"costcenterId -- $costcenterId",
);
final data = await apiService
.getCostCenterDetailsFind(costcenterId);
.getCostCenterDetailsFind(
costcenterId,
);
print("CostCenterId -- $data");
showDialog(
context: context,
builder: (context) => CostCenterData(
builder:
(context) => CostCenterData(
isDesktop: isDesktop,
costcenterId:costcenterId, // Pass the ID
costcenterData:data,
layoutColor:layoutColor!,
costcenterId:
costcenterId, // Pass the ID
costcenterData: data,
layoutColor: layoutColor!,
// fetchGetCostCenter: fetchGetCostCenter,
fetchGetCostCenter: refreshData,
fetchGetCostCenter:
refreshData,
// role:
// "Travel Agent"
),
@ -745,13 +809,12 @@ class CostCenterListState extends State<CostCenterList> {
cardObject['description'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
SizedBox(
width: 10,
),
SizedBox(width: 10),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
@ -760,7 +823,8 @@ class CostCenterListState extends State<CostCenterList> {
cardObject['description'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -776,13 +840,13 @@ class CostCenterListState extends State<CostCenterList> {
);
}
return Expanded(
child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: isDesktop
child:
isDesktop
? (searchController.text.isNotEmpty &&
filteredCostCenter.isEmpty
? Center(
@ -790,7 +854,8 @@ class CostCenterListState extends State<CostCenterList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: SingleChildScrollView(
@ -804,10 +869,13 @@ class CostCenterListState extends State<CostCenterList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: buildMobileCardView(paginatedCostCenter)),
: buildMobileCardView(
paginatedCostCenter,
)),
),
// Expanded(
// child: isDesktop
@ -838,9 +906,11 @@ class CostCenterListState extends State<CostCenterList> {
),
);
},
)
]),
)),
),
],
),
),
),
);
}
}

View File

@ -67,11 +67,13 @@ class DepartmentListState extends State<DepartmentList> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -141,10 +143,13 @@ class DepartmentListState extends State<DepartmentList> {
print("all before filtering: $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredDepartment = allDepartment.where((object) {
filteredDepartment =
allDepartment.where((object) {
final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive";
return (object['department_id']?.toLowerCase().contains(lowerQuery) ??
return (object['department_id']?.toLowerCase().contains(
lowerQuery,
) ??
false) ||
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ??
@ -158,8 +163,10 @@ class DepartmentListState extends State<DepartmentList> {
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -168,11 +175,14 @@ class DepartmentListState extends State<DepartmentList> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
@ -185,7 +195,8 @@ class DepartmentListState extends State<DepartmentList> {
),
),
);
});
},
);
}
Widget buildGroupList(bool isDesktop) {
@ -213,7 +224,8 @@ class DepartmentListState extends State<DepartmentList> {
// ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10),
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
@ -245,9 +257,7 @@ class DepartmentListState extends State<DepartmentList> {
],
),
if (isDesktop)
SizedBox(
width: MediaQuery.of(context).size.width * 0.16,
),
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
if (isDesktop)
Container(
@ -259,7 +269,9 @@ class DepartmentListState extends State<DepartmentList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -271,17 +283,19 @@ class DepartmentListState extends State<DepartmentList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -295,16 +309,18 @@ class DepartmentListState extends State<DepartmentList> {
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side:
BorderSide(color: Color(0xFF114D8B), width: 2),
side: BorderSide(color: Color(0xFF114D8B), width: 2),
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12),
horizontal: 20,
vertical: 12,
),
),
onPressed: () async {
showDialog(
context: context,
builder: (context) => DepartmentData(
builder:
(context) => DepartmentData(
isDesktop: isDesktop,
layoutColor: layoutColor!,
fetchGetDepartment: refreshData,
@ -336,10 +352,7 @@ class DepartmentListState extends State<DepartmentList> {
],
),
if (!isDesktop)
SizedBox(
height: 5,
),
if (!isDesktop) SizedBox(height: 5),
isDesktop
? SizedBox.shrink()
: Row(
@ -354,7 +367,9 @@ class DepartmentListState extends State<DepartmentList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -367,17 +382,18 @@ class DepartmentListState extends State<DepartmentList> {
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200,
width: 0.5),
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -415,14 +431,17 @@ class DepartmentListState extends State<DepartmentList> {
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.grey),
color: Colors.grey,
),
),
const SizedBox(height: 20),
Text(
"Please Create Department Details",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey),
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 20),
],
@ -431,7 +450,8 @@ class DepartmentListState extends State<DepartmentList> {
);
}
/* Here collect the list to displayed the data in table or card Used */
List<dynamic> object = filteredDepartment.isNotEmpty
List<dynamic> object =
filteredDepartment.isNotEmpty
? filteredDepartment
: allDepartment;
@ -440,12 +460,12 @@ class DepartmentListState extends State<DepartmentList> {
DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']);
return dateB
.compareTo(dateA); // Descending: newest first
return dateB.compareTo(dateA); // Descending: newest first
});
/* For pagination for list ... */
List paginatedDepartment = object
List paginatedDepartment =
object
.skip(currentPage * itemsPerPage)
.take(itemsPerPage)
.toList();
@ -453,8 +473,7 @@ class DepartmentListState extends State<DepartmentList> {
/* Table ... */
Widget table = LayoutBuilder(
builder: (context, constraints) {
double minWidth =
isDesktop ? constraints.maxWidth : 1300;
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
@ -463,7 +482,9 @@ class DepartmentListState extends State<DepartmentList> {
columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder(
horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200),
width: 0.5,
color: Colors.grey.shade200,
),
),
columns: [
DataColumn(
@ -471,51 +492,68 @@ class DepartmentListState extends State<DepartmentList> {
'Name',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Description',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Status',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Actions',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
],
rows: paginatedDepartment.map((tableObject) {
rows:
paginatedDepartment.map((tableObject) {
String departmentId =
tableObject['department_id']
.toString(); // Get user ID
bool isSelected =
selectedDepartmentId == departmentId;
return DataRow(cells: [
DataCell(Text(tableObject['name'] ?? '',
return DataRow(
cells: [
DataCell(
Text(
tableObject['name'] ?? '',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
),
),
),
DataCell(
Text(tableObject['description'] ?? 'N/A',
Text(
tableObject['description'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
tableObject['is_active'] == "1"
@ -524,7 +562,8 @@ class DepartmentListState extends State<DepartmentList> {
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
color: tableObject['is_active'] == "1"
color:
tableObject['is_active'] == "1"
? Colors.green
: Colors.red,
),
@ -539,37 +578,45 @@ class DepartmentListState extends State<DepartmentList> {
// apiService.getSingleUser(id),
// ),
GestureDetector(
child: Tooltip(
message: 'Edit Department Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15),
height: 15,
),
),
onTap: () async {
// final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId);
//
final departmentId = int.tryParse(
tableObject['department_id']
.toString());
.toString(),
);
if (departmentId != null) {
print(
"Table cell - department Id -- $departmentId");
"Table cell - department Id -- $departmentId",
);
final data = await apiService
.getDepartmentDetailsFind(
departmentId);
departmentId,
);
print("DepartmentId -- $data");
showDialog(
context: context,
builder: (context) =>
DepartmentData(
builder:
(context) => DepartmentData(
isDesktop: isDesktop,
departmentId:
departmentId, // Pass the ID
departmentData: data,
layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex,
fetchGetDepartment: refreshData,
fetchGetDepartment:
refreshData,
// role:
// "Travel Agent"
),
@ -580,7 +627,8 @@ class DepartmentListState extends State<DepartmentList> {
},
),
),
]);
],
);
}).toList(),
),
);
@ -596,7 +644,9 @@ class DepartmentListState extends State<DepartmentList> {
return Card(
color: Colors.white,
margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -616,7 +666,8 @@ class DepartmentListState extends State<DepartmentList> {
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.w700),
fontWeight: FontWeight.w700,
),
),
GestureDetector(
@ -634,20 +685,23 @@ class DepartmentListState extends State<DepartmentList> {
//
final departmentId = int.tryParse(
cardObject['department_id']
.toString());
.toString(),
);
if (departmentId != null) {
print(
"departmentId -- $departmentId");
"departmentId -- $departmentId",
);
final data = await apiService
.getDepartmentDetailsFind(
departmentId);
departmentId,
);
print("DepartmentId -- $data");
showDialog(
context: context,
builder: (context) =>
DepartmentData(
builder:
(context) => DepartmentData(
isDesktop: isDesktop,
departmentId:
departmentId, // Pass the ID
@ -754,13 +808,12 @@ class DepartmentListState extends State<DepartmentList> {
cardObject['description'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
SizedBox(
width: 10,
),
SizedBox(width: 10),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
@ -769,7 +822,8 @@ class DepartmentListState extends State<DepartmentList> {
cardObject['description'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -790,7 +844,8 @@ class DepartmentListState extends State<DepartmentList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: isDesktop
child:
isDesktop
? (searchController.text.isNotEmpty &&
filteredDepartment.isEmpty
? Center(
@ -798,7 +853,8 @@ class DepartmentListState extends State<DepartmentList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: SingleChildScrollView(
@ -812,11 +868,13 @@ class DepartmentListState extends State<DepartmentList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: buildMobileCardView(
paginatedDepartment)),
paginatedDepartment,
)),
),
// Expanded(
// child: isDesktop
@ -847,9 +905,11 @@ class DepartmentListState extends State<DepartmentList> {
),
);
},
)
]),
)),
),
],
),
),
),
);
}
}

View File

@ -83,11 +83,13 @@ class ForexDataListState extends State<ForexDataList> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -151,7 +153,8 @@ class ForexDataListState extends State<ForexDataList> {
if (!data.containsKey('data') || data['data'] is! List) {
throw Exception(
"Invalid response format: 'data' field is missing or not a List");
"Invalid response format: 'data' field is missing or not a List",
);
}
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
@ -180,7 +183,10 @@ class ForexDataListState extends State<ForexDataList> {
}
Future<void> createUserData(
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 String? token = await getToken();
@ -230,8 +236,11 @@ class ForexDataListState extends State<ForexDataList> {
}
}
void handleToggleUserStatus(String userId, String currentStatus,
Map<String, dynamic> userData) async {
void handleToggleUserStatus(
String userId,
String currentStatus,
Map<String, dynamic> userData,
) async {
print("Toggling user status - $userId (Current: $currentStatus)");
final String apiUrlData =
@ -274,7 +283,7 @@ class ForexDataListState extends State<ForexDataList> {
// }
}
// Refresh user list after update
// Refresh user list after update
void refreshUserList() {
setState(() {
futureForex = fetchGetForex(); // Re-fetch users after status update
@ -282,48 +291,35 @@ class ForexDataListState extends State<ForexDataList> {
});
}
void filterForex1(String query) {
print("allUsers before filtering: $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredForex = allForex.where((forex) {
return (forex['country_code']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['country_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) ||
(forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ??
false);
}).toList();
currentPage = 0;
});
print("filteredPlans: $filteredForex");
}
void filterForex(String query) {
print("allForex before filtering: $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredForex = allForex.where((forex) {
filteredForex =
allForex.where((forex) {
final isActiveStatus =
forex['is_active'] == "1" ? "active" : "inactive";
return (forex['country_code']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['country_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) ||
(forex['currency']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ??
false) ||
(isActiveStatus.contains(lowerQuery));
}).toList();
currentPage = 0;
});
print("filteredForex: $filteredForex");
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -332,11 +328,14 @@ class ForexDataListState extends State<ForexDataList> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
@ -349,7 +348,8 @@ class ForexDataListState extends State<ForexDataList> {
),
),
);
});
},
);
}
Widget buildGroupList(bool isDesktop) {
@ -377,7 +377,8 @@ class ForexDataListState extends State<ForexDataList> {
// ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10),
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
@ -409,9 +410,7 @@ class ForexDataListState extends State<ForexDataList> {
],
),
if (isDesktop)
SizedBox(
width: MediaQuery.of(context).size.width * 0.16,
),
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
if (isDesktop)
Container(
@ -423,7 +422,9 @@ class ForexDataListState extends State<ForexDataList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -435,17 +436,19 @@ class ForexDataListState extends State<ForexDataList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -459,16 +462,18 @@ class ForexDataListState extends State<ForexDataList> {
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side:
BorderSide(color: Color(0xFF114D8B), width: 2),
side: BorderSide(color: Color(0xFF114D8B), width: 2),
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12),
horizontal: 20,
vertical: 12,
),
),
onPressed: () async {
showDialog(
context: context,
builder: (context) => ForexData(
builder:
(context) => ForexData(
isDesktop: isDesktop,
layoutColor: layoutColor!,
fetchGetForex: refreshData,
@ -499,10 +504,7 @@ class ForexDataListState extends State<ForexDataList> {
],
),
if (!isDesktop)
SizedBox(
height: 5,
),
if (!isDesktop) SizedBox(height: 5),
isDesktop
? SizedBox.shrink()
: Row(
@ -517,7 +519,9 @@ class ForexDataListState extends State<ForexDataList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -530,17 +534,18 @@ class ForexDataListState extends State<ForexDataList> {
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200,
width: 0.5),
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -578,14 +583,17 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.grey),
color: Colors.grey,
),
),
const SizedBox(height: 20),
Text(
"Please Create Perdiem Amount",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey),
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 20),
],
@ -601,19 +609,18 @@ class ForexDataListState extends State<ForexDataList> {
DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']);
return dateB
.compareTo(dateA); // Descending: newest first
return dateB.compareTo(dateA); // Descending: newest first
});
List paginatedForex = forex
List paginatedForex =
forex
.skip(currentPage * itemsPerPage)
.take(itemsPerPage)
.toList();
Widget table = LayoutBuilder(
builder: (context, constraints) {
double minWidth =
isDesktop ? constraints.maxWidth : 1300;
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
@ -622,7 +629,9 @@ class ForexDataListState extends State<ForexDataList> {
columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder(
horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200),
width: 0.5,
color: Colors.grey.shade200,
),
),
columns: [
DataColumn(
@ -630,76 +639,105 @@ class ForexDataListState extends State<ForexDataList> {
'Country Code',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Country',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Currency',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Perdiem Amount',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Status',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Actions',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
],
rows: paginatedForex.map((forex) {
String forexId = forex['forex_perdiem_id']
rows:
paginatedForex.map((forex) {
String forexId =
forex['forex_perdiem_id']
.toString(); // Get user ID
bool isSelected = selectedUserId == forexId;
return DataRow(cells: [
return DataRow(
cells: [
DataCell(
Text("${forex['country_code'] ?? ''}",
Text(
"${forex['country_code'] ?? ''}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(forex['country_name'] ?? '',
),
),
),
DataCell(
Text(
forex['country_name'] ?? '',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(forex['currency'] ?? 'N/A',
),
),
),
DataCell(
Text(
forex['currency'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(forex['perdiem_amount'] ?? 'N/A',
Text(
forex['perdiem_amount'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
forex['is_active'] == "1"
@ -737,7 +775,8 @@ class ForexDataListState extends State<ForexDataList> {
//
final forexId = int.tryParse(
forex['forex_perdiem_id']
.toString());
.toString(),
);
if (forexId != null) {
print("ForexId -- $forexId");
@ -747,9 +786,11 @@ class ForexDataListState extends State<ForexDataList> {
showDialog(
context: context,
builder: (context) => ForexData(
builder:
(context) => ForexData(
isDesktop: isDesktop,
forexId: forexId, // Pass the ID
forexId:
forexId, // Pass the ID
forexData: data,
layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex,
@ -764,7 +805,8 @@ class ForexDataListState extends State<ForexDataList> {
},
),
),
]);
],
);
}).toList(),
),
);
@ -779,7 +821,9 @@ class ForexDataListState extends State<ForexDataList> {
return Card(
color: Colors.white,
margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -799,7 +843,8 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.w700),
fontWeight: FontWeight.w700,
),
),
GestureDetector(
@ -816,8 +861,8 @@ class ForexDataListState extends State<ForexDataList> {
// final usersData = await getUserDetails(userId);
//
final forexId = int.tryParse(
forex['forex_perdiem_id']
.toString());
forex['forex_perdiem_id'].toString(),
);
if (forexId != null) {
print("ForexId -- $forexId");
@ -827,7 +872,8 @@ class ForexDataListState extends State<ForexDataList> {
showDialog(
context: context,
builder: (context) => ForexData(
builder:
(context) => ForexData(
isDesktop: isDesktop,
forexId:
forexId, // Pass the ID
@ -933,7 +979,8 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
fontWeight: FontWeight.w500),
fontWeight: FontWeight.w500,
),
),
],
),
@ -952,13 +999,12 @@ class ForexDataListState extends State<ForexDataList> {
forex['currency'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
SizedBox(
width: 10,
),
SizedBox(width: 10),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
@ -967,7 +1013,8 @@ class ForexDataListState extends State<ForexDataList> {
forex['perdiem_amount'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -988,7 +1035,8 @@ class ForexDataListState extends State<ForexDataList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: isDesktop
child:
isDesktop
? (searchController.text.isNotEmpty &&
filteredForex.isEmpty
? Center(
@ -996,7 +1044,8 @@ class ForexDataListState extends State<ForexDataList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: SingleChildScrollView(
@ -1010,7 +1059,8 @@ class ForexDataListState extends State<ForexDataList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: buildMobileCardView(paginatedForex)),
@ -1044,11 +1094,11 @@ class ForexDataListState extends State<ForexDataList> {
),
);
},
)
]),
)),
),
],
),
),
),
);
}
}

View File

@ -15,8 +15,6 @@ import '../../utils/auth_utils.dart';
import '../../utils/pagination.dart';
import 'groupDetails.dart';
class GroupList extends StatefulWidget {
@override
_GroupListState createState() => _GroupListState();
@ -39,7 +37,6 @@ class _GroupListState extends State<GroupList> {
List filteredGroups = [];
TextEditingController searchController = TextEditingController();
int currentPage = 0;
int itemsPerPage = 10;
@ -87,15 +84,11 @@ class _GroupListState extends State<GroupList> {
return prefs.getString('auth_token');
}
Future<List<dynamic>> fetchGroups() async {
final result = await apiService.fetchAllGroup();
return result; // Returning raw JSON list
}
Future<void> loadAllGroups() async {
try {
final result = await apiService.fetchAllGroup();
@ -117,13 +110,20 @@ class _GroupListState extends State<GroupList> {
allGroups.where((group) {
return (group['name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(group['domestic_policy_name']?.toLowerCase().contains(lowerQuery) ??
false)
(group['international_policy_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(group['domestic_policy_name']?.toLowerCase().contains(
lowerQuery,
) ??
false)(
group['international_policy_name']?.toLowerCase().contains(
lowerQuery,
) ??
false,
) ||
(group['description']?.toLowerCase().contains(lowerQuery) ??
false) ||
(group['is_active']?.toLowerCase().contains(lowerQuery) ?? false);}).toList();
(group['is_active']?.toLowerCase().contains(lowerQuery) ??
false);
}).toList();
currentPage = 0;
});
@ -159,7 +159,7 @@ class _GroupListState extends State<GroupList> {
'Content-Type': 'application/json',
},
body: jsonEncode({
"is_active": newStatus // Set new status dynamically
"is_active": newStatus, // Set new status dynamically
}),
);
@ -189,7 +189,6 @@ class _GroupListState extends State<GroupList> {
loadAllGroups();
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
@ -213,11 +212,7 @@ class _GroupListState extends State<GroupList> {
0, // 5% of screen height as vertical padding
)
: EdgeInsets.all(0),
child: Row(
children: [
Expanded(child: buildGroupList(isDesktop)),
],
),
child: Row(children: [Expanded(child: buildGroupList(isDesktop))]),
),
);
},
@ -346,15 +341,14 @@ class _GroupListState extends State<GroupList> {
// context.go('/CreateGroup');
showDialog(
context: context,
builder: (context) => GroupData(
builder:
(context) => GroupData(
isDesktop: isDesktop,
groupId: null,
layoutColor: layoutColor!,
fetchGetGroup: refreshData
fetchGetGroup: refreshData,
),
);
},
child: Row(
mainAxisSize:
@ -556,7 +550,8 @@ class _GroupListState extends State<GroupList> {
rows:
paginatedGroup.map((group) {
String groupId =
group['group_id'].toString(); // Get group ID
group['group_id']
.toString(); // Get group ID
bool isSelected = selectedGroupId == groupId;
return DataRow(
@ -571,7 +566,8 @@ class _GroupListState extends State<GroupList> {
),
),
DataCell(
Text("${group['domestic_policy_name'] ?? 'N/A'}",
Text(
"${group['domestic_policy_name'] ?? 'N/A'}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
@ -613,31 +609,39 @@ class _GroupListState extends State<GroupList> {
),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () async {
if (group['group_id'] != null) {
final newGroupID = int.tryParse(
group['group_id'].toString());
group['group_id'].toString(),
);
if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind(
newGroupID); // Always an int
final data = await apiService
.getGroupDetailsFind(
newGroupID,
); // Always an int
showDialog(
context: context,
builder: (context) =>
GroupData(
builder:
(context) => GroupData(
isDesktop: isDesktop,
groupId: newGroupID,
// Pass the ID
groupData: data,
layoutColor: layoutColor!,
fetchGetGroup: refreshData
layoutColor:
layoutColor!,
fetchGetGroup:
refreshData,
),
);
}
} else {
print("something went wrong check properly");
print(
"something went wrong check properly",
);
}
},
@ -646,16 +650,20 @@ class _GroupListState extends State<GroupList> {
// },
child: Tooltip(
message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/edit.png',
width: 20, height: 15), ),
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
SizedBox(
width: 5,
),
),
SizedBox(width: 5),
GestureDetector(
onTap: () {
final idStr = group['group_id'];
final id = int.tryParse(idStr.toString());
final id = int.tryParse(
idStr.toString(),
);
if (id == null) {
print("group_id is null");
@ -667,8 +675,12 @@ class _GroupListState extends State<GroupList> {
},
child: Tooltip(
message: 'Delete Group Details',
child: Image.asset('assets/images/IconsImg/delete.png',
width: 20, height: 15),),
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
],
),
@ -688,7 +700,10 @@ class _GroupListState extends State<GroupList> {
return Card(
color: Colors.white,
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
margin: EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -700,7 +715,8 @@ class _GroupListState extends State<GroupList> {
children: [
// Row 1: Policy Name and Actions
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: RichText(
@ -718,11 +734,12 @@ class _GroupListState extends State<GroupList> {
),
),
TextSpan(
text: "${object['name'] ?? 'N/A'}",
text:
"${object['name'] ?? 'N/A'}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.normal
fontWeight: FontWeight.normal,
),
),
],
@ -736,42 +753,54 @@ class _GroupListState extends State<GroupList> {
onTap: () async {
if (object['group_id'] != null) {
final newGroupID = int.tryParse(
object['group_id'].toString());
object['group_id'].toString(),
);
if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind(
newGroupID); // Always an int
final data = await apiService
.getGroupDetailsFind(
newGroupID,
); // Always an int
showDialog(
context: context,
builder: (context) =>
GroupData(
builder:
(context) => GroupData(
isDesktop: isDesktop,
groupId: newGroupID,
// Pass the ID
groupData: data,
layoutColor: layoutColor!,
fetchGetGroup: refreshData
layoutColor:
layoutColor!,
fetchGetGroup:
refreshData,
),
);
}
} else {
print("something went wrong check properly");
print(
"something went wrong check properly",
);
}
},
// onTap: () {
// context.go("/CreateGroup", extra: group);
// },
child: Tooltip( message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/edit.png',
width: 20, height: 15),),
child: Tooltip(
message: 'Edit Group Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
SizedBox(
width: 5,
),
),
SizedBox(width: 5),
GestureDetector(
onTap: () {
final idStr = object['group_id'];
final id = int.tryParse(idStr.toString());
final id = int.tryParse(
idStr.toString(),
);
if (id == null) {
print("group_id is null");
@ -783,8 +812,12 @@ class _GroupListState extends State<GroupList> {
},
child: Tooltip(
message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/delete.png',
width: 20, height: 15),),
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
],
),
@ -792,7 +825,6 @@ class _GroupListState extends State<GroupList> {
),
SizedBox(height: 8), // Spacing
// Row 2:
RichText(
text: TextSpan(
@ -809,18 +841,19 @@ class _GroupListState extends State<GroupList> {
),
),
TextSpan(
text: "${object['domestic_policy_name'] ?? 'N/A'}",
text:
"${object['domestic_policy_name'] ?? 'N/A'}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.normal
fontWeight: FontWeight.normal,
),
),
],
),
),
SizedBox(height: 8), // Spacing
// Row 3:
RichText(
text: TextSpan(
@ -837,18 +870,18 @@ class _GroupListState extends State<GroupList> {
),
),
TextSpan(
text: "${object['international_policy_name']}",
text:
"${object['international_policy_name'] ?? 'N/A'}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.normal
fontWeight: FontWeight.normal,
),
),
],
),
),
SizedBox(height: 8), // Spacing
// Row 4:
RichText(
text: TextSpan(
@ -865,11 +898,12 @@ class _GroupListState extends State<GroupList> {
),
),
TextSpan(
text: "${object['description'] ?? 'N/A'}",
text:
"${object['description'] ?? 'N/A'}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.normal
fontWeight: FontWeight.normal,
),
),
],

View File

@ -83,11 +83,13 @@ class HotelsDataListState extends State<HotelsDataList> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -150,7 +152,8 @@ class HotelsDataListState extends State<HotelsDataList> {
if (!data.containsKey('data') || data['data'] is! List) {
throw Exception(
"Invalid response format: 'data' field is missing or not a List");
"Invalid response format: 'data' field is missing or not a List",
);
}
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
@ -174,8 +177,7 @@ class HotelsDataListState extends State<HotelsDataList> {
}
}
// Refresh user list after update
// Refresh user list after update
void refreshUserList() {
setState(() {
futureHotels = fetchGetHotels(); // Re-fetch users after status update
@ -187,15 +189,19 @@ class HotelsDataListState extends State<HotelsDataList> {
print("allHotels before filtering: $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredHotels = allHotels.where((hotels) {
filteredHotels =
allHotels.where((hotels) {
final isActiveStatus =
hotels['is_active'] == "1" ? "active" : "inactive";
return (hotels['country_code']?.toLowerCase().contains(lowerQuery) ??
return (hotels['country_code']?.toLowerCase().contains(
lowerQuery,
) ??
false) ||
(hotels['country_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(hotels['city']?.toLowerCase().contains(lowerQuery) ?? false) ||
(hotels['hotel_chain']?.toLowerCase().contains(lowerQuery) ?? false) ||
(hotels['hotel_chain']?.toLowerCase().contains(lowerQuery) ??
false) ||
(hotels['hotel_name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(isActiveStatus.contains(lowerQuery));
@ -207,8 +213,10 @@ class HotelsDataListState extends State<HotelsDataList> {
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -217,11 +225,14 @@ class HotelsDataListState extends State<HotelsDataList> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
@ -234,7 +245,8 @@ class HotelsDataListState extends State<HotelsDataList> {
),
),
);
});
},
);
}
Widget buildGroupList(bool isDesktop) {
@ -262,7 +274,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10),
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
@ -294,9 +307,7 @@ class HotelsDataListState extends State<HotelsDataList> {
],
),
if (isDesktop)
SizedBox(
width: MediaQuery.of(context).size.width * 0.16,
),
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
if (isDesktop)
Container(
@ -308,7 +319,9 @@ class HotelsDataListState extends State<HotelsDataList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -320,17 +333,19 @@ class HotelsDataListState extends State<HotelsDataList> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5),
color: Colors.grey.shade200,
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -344,16 +359,18 @@ class HotelsDataListState extends State<HotelsDataList> {
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side:
BorderSide(color: Color(0xFF114D8B), width: 2),
side: BorderSide(color: Color(0xFF114D8B), width: 2),
),
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12),
horizontal: 20,
vertical: 12,
),
),
onPressed: () async {
showDialog(
context: context,
builder: (context) => HotelsData(
builder:
(context) => HotelsData(
isDesktop: isDesktop,
layoutColor: layoutColor!,
fetchGetHotels: refreshData,
@ -384,10 +401,7 @@ class HotelsDataListState extends State<HotelsDataList> {
],
),
if (!isDesktop)
SizedBox(
height: 5,
),
if (!isDesktop) SizedBox(height: 5),
isDesktop
? SizedBox.shrink()
: Row(
@ -402,7 +416,9 @@ class HotelsDataListState extends State<HotelsDataList> {
decoration: InputDecoration(
hintText: "Search ...",
hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)),
fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon(
Icons.search,
color: Color(0xFF9E9DBD),
@ -415,17 +431,18 @@ class HotelsDataListState extends State<HotelsDataList> {
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: Colors.grey.shade200,
width: 0.5),
width: 0.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
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),
@ -463,14 +480,17 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.grey),
color: Colors.grey,
),
),
const SizedBox(height: 20),
Text(
"Please Create Hotels",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey),
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 20),
],
@ -486,19 +506,18 @@ class HotelsDataListState extends State<HotelsDataList> {
DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']);
return dateB
.compareTo(dateA); // Descending: newest first
return dateB.compareTo(dateA); // Descending: newest first
});
List paginatedHotels = hotels
List paginatedHotels =
hotels
.skip(currentPage * itemsPerPage)
.take(itemsPerPage)
.toList();
Widget table = LayoutBuilder(
builder: (context, constraints) {
double minWidth =
isDesktop ? constraints.maxWidth : 1300;
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
@ -507,7 +526,9 @@ class HotelsDataListState extends State<HotelsDataList> {
columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder(
horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200),
width: 0.5,
color: Colors.grey.shade200,
),
),
columns: [
DataColumn(
@ -515,74 +536,105 @@ class HotelsDataListState extends State<HotelsDataList> {
'Hotel Name',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Hotel Chain',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'City',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Country',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Status',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Actions',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600),
)),
fontWeight: FontWeight.w600,
),
),
),
],
rows: paginatedHotels.map((hotels) {
String hotelsId = hotels['hotel_id']
rows:
paginatedHotels.map((hotels) {
String hotelsId =
hotels['hotel_id']
.toString(); // Get user ID
bool isSelected = selectedUserId == hotelsId;
return DataRow(cells: [
DataCell(Text(hotels['hotel_name'] ?? 'N/A',
return DataRow(
cells: [
DataCell(
Text(
hotels['hotel_name'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text(hotels['hotel_chain'] ?? '',
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
hotels['hotel_chain'] ?? '',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(hotels['city'] ?? 'N/A',
),
),
),
DataCell(
Text(
hotels['city'] ?? 'N/A',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text(hotels['country_name'] ?? '',
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
hotels['country_name'] ?? '',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
))),
),
),
),
DataCell(
Text(
hotels['is_active'] == "1"
@ -591,7 +643,10 @@ class HotelsDataListState extends State<HotelsDataList> {
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
color: hotels['is_active'] == "1" ? Colors.green : Colors.red,
color:
hotels['is_active'] == "1"
? Colors.green
: Colors.red,
),
softWrap: true,
overflow: TextOverflow.ellipsis,
@ -605,9 +660,9 @@ class HotelsDataListState extends State<HotelsDataList> {
// ),
GestureDetector(
child: Tooltip(
message: 'Delete Hotel Details',
message: 'Edit Hotel Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
@ -617,8 +672,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// final usersData = await getUserDetails(userId);
//
final hotelsId = int.tryParse(
hotels['hotel_id']
.toString());
hotels['hotel_id'].toString(),
);
if (hotelsId != null) {
print("HotelsId -- $hotelsId");
@ -628,9 +683,11 @@ class HotelsDataListState extends State<HotelsDataList> {
showDialog(
context: context,
builder: (context) => HotelsData(
builder:
(context) => HotelsData(
isDesktop: isDesktop,
hotelsId: hotelsId, // Pass the ID
hotelsId:
hotelsId, // Pass the ID
hotelsData: data,
layoutColor: layoutColor!,
// fetchGetHotels: fetchGetHotels,
@ -645,7 +702,8 @@ class HotelsDataListState extends State<HotelsDataList> {
},
),
),
]);
],
);
}).toList(),
),
);
@ -660,7 +718,9 @@ class HotelsDataListState extends State<HotelsDataList> {
return Card(
color: Colors.white,
margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -680,21 +740,26 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.w700),
fontWeight: FontWeight.w700,
),
),
GestureDetector(
child: Tooltip(
message: 'Edit Hotel Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15),
height: 15,
),
),
onTap: () async {
// final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId);
//
final hotelsId = int.tryParse(
hotels['hotel_id']
.toString());
hotels['hotel_id'].toString(),
);
if (hotelsId != null) {
print("HotelsId -- $hotelsId");
@ -704,7 +769,8 @@ class HotelsDataListState extends State<HotelsDataList> {
showDialog(
context: context,
builder: (context) => HotelsData(
builder:
(context) => HotelsData(
isDesktop: isDesktop,
hotelsId:
hotelsId, // Pass the ID
@ -737,7 +803,8 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
fontWeight: FontWeight.w500),
fontWeight: FontWeight.w500,
),
),
],
),
@ -755,7 +822,8 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
fontWeight: FontWeight.w500),
fontWeight: FontWeight.w500,
),
),
],
),
@ -772,7 +840,8 @@ class HotelsDataListState extends State<HotelsDataList> {
hotels['country_name'] ?? '',
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87),
color: Colors.black87,
),
),
],
),
@ -792,7 +861,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: isDesktop
child:
isDesktop
? (searchController.text.isNotEmpty &&
filteredHotels.isEmpty
? Center(
@ -800,7 +870,8 @@ class HotelsDataListState extends State<HotelsDataList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: SingleChildScrollView(
@ -814,7 +885,8 @@ class HotelsDataListState extends State<HotelsDataList> {
"No matches found",
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey),
color: Colors.grey,
),
),
)
: buildMobileCardView(paginatedHotels)),
@ -848,9 +920,11 @@ class HotelsDataListState extends State<HotelsDataList> {
),
);
},
)
]),
)),
),
],
),
),
),
);
}
}

View File

@ -14,12 +14,13 @@ class TaxiScreen extends StatefulWidget {
final Map<String, dynamic>? selectedItem;
final String? loginUser;
TaxiScreen(
{required this.onClose,
TaxiScreen({
required this.onClose,
this.apiData,
required this.onSavetaxi,
required this.selectedItem,
required this.loginUser});
required this.loginUser,
});
@override
_TaxiScreenState createState() => _TaxiScreenState();
@ -97,13 +98,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
super.initState();
_addFocusListener(
_destinationFocusNode, (focus) => _destinationFocus = focus);
_destinationFocusNode,
(focus) => _destinationFocus = focus,
);
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
_addFocusListener(
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus);
_numPassengerFocusNode,
(focus) => _numPassengerFocus = focus,
);
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
_destinationController = initController("destination_city");
@ -168,7 +173,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
"location_of_pickup",
"no_of_passengers",
"date",
"time"
"time",
];
// Check validation for each field
@ -199,9 +204,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container(
// color: Color(0xFFF4F4FB),
@ -216,13 +223,14 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
),
)
),
],
),
),
),
);
});
},
);
}
List<Widget> _buildAccomadtionForm(bool isDesktop) {
@ -235,7 +243,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop),
_buildSecondRow(isDesktop)
_buildSecondRow(isDesktop),
];
return [
@ -253,19 +261,24 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<Widget> _buildFirstRow(isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item) => DropdownMenuItem<String>(
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
))
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available",
style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
@ -283,20 +296,16 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
isDesktop
? Row(children: _buildTripType(isDesktop))
: Column(children: _buildTripType(isDesktop))
: Column(children: _buildTripType(isDesktop)),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -305,7 +314,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -319,8 +329,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: const TextStyle(fontSize: 12),
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
FilteringTextInputFormatter.allow(
RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
],
decoration: const InputDecoration(
labelText: "Number of Passenger",
@ -334,19 +345,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
if (errorMessages["no_of_passengers"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -355,7 +358,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -369,16 +373,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(horizontal: 10), // Proper padding
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedCarType = newValue;
});
print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
}
: null,
@ -388,31 +395,31 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
],
),
if (isDesktop)
SizedBox.shrink()
else
SizedBox(
height: 8,
),
if (isDesktop) SizedBox.shrink() else SizedBox(height: 8),
];
}
List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item) => DropdownMenuItem<String>(
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
))
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available",
style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
@ -425,7 +432,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
CustomTextFieldWrapper(
isFocused: _taxiReqFocused,
isDesktop: isDesktop,
width: isDesktop
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
@ -436,16 +444,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(horizontal: 10), // Proper padding
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedReqTaxi = newValue;
});
print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
}
: null,
@ -466,7 +477,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedCheckOutDate != null &&
initialDate:
_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate!
: today,
@ -494,8 +506,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
// Formatting time to HH:mm (24-hour format)
final now = DateTime.now();
final formattedTime = DateFormat('HH:mm').format(
DateTime(now.year, now.month, now.day, pickedTime.hour,
pickedTime.minute),
DateTime(
now.year,
now.month,
now.day,
pickedTime.hour,
pickedTime.minute,
),
);
_timeController.text = formattedTime;
});
@ -511,7 +528,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -535,28 +553,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
if (errorMessages["destination_city"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Location of Pickup",
"Pickup Location",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -569,7 +580,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
controller: _locationController,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Location of Pickup",
labelText: "Pickup Location",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
@ -580,19 +591,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
if (errorMessages["location_of_pickup"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -601,7 +604,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -622,8 +626,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today,
size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
@ -632,19 +639,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
if (errorMessages["date"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -653,7 +652,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -674,8 +674,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon:
Icon(Icons.access_time, size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.access_time,
size: 16,
color: Colors.grey,
),
),
),
),
@ -684,10 +687,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
if (errorMessages["time"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
@ -704,13 +704,15 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF575A74)),
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width: isDesktop
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
@ -733,9 +735,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
],
),
if (isDesktop) Spacer(),
SizedBox(
height: 5,
),
SizedBox(height: 5),
Column(
children: [
Row(
@ -756,9 +756,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
@ -767,7 +765,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
),
SizedBox(width: 10), // Space between buttons
// Save Changes Button
ElevatedButton(
onPressed: () {
@ -775,9 +772,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), // Primary color for save
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(

View File

@ -85,7 +85,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
return AlertDialog(
title: const Text('Select Trip Type'),
content: const Text(
'Please select a trip type before adding a flight.'),
'Please select a trip type before adding a flight.',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
@ -118,11 +119,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ),
MouseRegion(
cursor: widget.isViewMode
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: widget.isViewMode
onTap:
widget.isViewMode
? null
: () {
checkClass();
@ -141,7 +144,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
),
],
),
),
@ -149,9 +152,9 @@ class _FlightListWidgetState extends State<FlightListWidget> {
],
),
const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop)
// Scroll behavior based on device
_buildData(context, isDesktop),
],
),
),
@ -224,8 +227,11 @@ class _FlightListWidgetState extends State<FlightListWidget> {
if (hour == 24 && minute == 0) {
// 24:00 is treated as 00:00 on the next day
dateTime = DateTime(now.year, now.month, now.day)
.add(const Duration(days: 1));
dateTime = DateTime(
now.year,
now.month,
now.day,
).add(const Duration(days: 1));
} else {
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw FormatException("Invalid hour or minute");
@ -245,7 +251,21 @@ class _FlightListWidgetState extends State<FlightListWidget> {
itemCount: filteredList.length,
itemBuilder: (context, index) {
final item = filteredList[index];
String? tripTypeName = '';
switch (item["trip_type"]?.toString()) {
case "Roundtrip":
tripTypeName = "Round Trip";
break;
case "Multitrip":
tripTypeName = "Multi-Trip";
break;
case "Oneway":
tripTypeName = "One-Way";
break;
default:
tripTypeName = item["trip_type"]?.toString();
break;
}
return Container(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration(
@ -281,7 +301,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Row(
children: [
Text(
item["trip_type"]?.toString() ?? "N/A",
tripTypeName ?? "N/A",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
@ -313,9 +333,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
],
),
Divider(
color: Colors.blueGrey.shade50,
),
Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
if (isDesktop)
Row(
@ -324,39 +342,35 @@ class _FlightListWidgetState extends State<FlightListWidget> {
flex: 2,
child: Text(
"Class",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 4,
child: Text(
"Sector",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
"Date",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
"Time",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
],
),
SizedBox(height: 4),
// Trip Rows
// Trip Rows
if (isDesktop)
if (item["trips"] != null && item["trips"].isNotEmpty)
...item["trips"].map<Widget>((trip) {
@ -385,7 +399,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Expanded(
flex: 4,
child: Text(
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
"$fromPlaceCountry (From) - (To) $toPlaceCountry",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins(
fontSize: 12,
@ -437,13 +451,20 @@ class _FlightListWidgetState extends State<FlightListWidget> {
_buildKeyValueRow(
"Class",
getRequestForClass(trip["class"].toString()) ??
"N/A"),
_buildKeyValueRow("Sector",
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}"),
"N/A",
),
_buildKeyValueRow(
"Date", formatDate(trip["date"] ?? "")),
"Sector",
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}",
),
_buildKeyValueRow(
"Time", formatTime(trip["time"] ?? "")),
"Date",
formatDate(trip["date"] ?? ""),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
),
],
),
),
@ -474,12 +495,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
),
Expanded(
child: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
),
),
child: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
),
],
),

View File

@ -131,7 +131,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"delegationEndDate",
// "dateOfIssue",
// "dateOfExpiry",
"changePassword"
"changePassword",
];
Color? layoutColor;
@ -286,7 +286,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
if (apiselectedUser?["delegated_to_user_id"] != null) {
print(
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}");
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}",
);
selectedSubstituteApprover =
apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
@ -303,11 +304,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
List<dynamic> decodedList = jsonDecode(fixedJson);
selectedServiceIds = decodedList.map<Map<String, dynamic>>((item) {
selectedServiceIds =
decodedList.map<Map<String, dynamic>>((item) {
final map = Map<String, dynamic>.from(item);
return {
"service_id": map['service_id'].toString(),
};
return {"service_id": map['service_id'].toString()};
}).toList();
} catch (e) {
print("❌ Error decoding fixed agent_supported_service_ids: $e");
@ -380,7 +380,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// userIdsApi = userMap.keys.toList();
// Handle selectedUser as a Map (not a List)
apiselectedUser = extraData['selectedUser']
apiselectedUser =
extraData['selectedUser']
as Map<String, dynamic>?; // Cast it as a Map
isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false;
@ -443,7 +444,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
userMap = {
for (var user in userList)
user['user_id'].toString():
"${user['first_name']} ${user['last_name']}"
"${user['first_name']} ${user['last_name']}",
};
userIdsApi = userMap.keys.toList();
});
@ -481,11 +482,13 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
@ -538,6 +541,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
}
}
void handleGoBack() async {
print("hello, please Go Back");
printFormData();
}
void handleNext() async {
print("USR Detail Next");
printFormData();
@ -552,14 +560,6 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("USERDETAILS : $data");
if (!isValidData(data)) {
print("USERDETAILS : $userDetials");
print("Validation Failed: Required fields are missing.");
setState(() {});
return; // Stop execution if validation fails
} else {
print("USERDETAILS : $userDetials");
final tabs = {
"personal": "Personal Details",
"office": "Office Details",
@ -570,17 +570,57 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
print("currentIndex - $currentIndex");
bool isValid = false;
final currentTab = tabKeys[currentIndex];
if (currentTab == "personal") {
isValid = isValidData(userDetials);
} else if (currentTab == "office") {
isValid = isValidDataTwo(userDetials);
} else {
isValid = true; // Travel tab might not need validation at this point
}
if (!isValid) {
print("Validation Failed on $currentTab: $userDetials");
setState(() {}); // To trigger UI update showing errors
return;
}
if (currentIndex < tabKeys.length - 1) {
// Move to next tab
setState(() {
selectedTab = tabKeys[currentIndex + 1];
});
} else {
// Already at last tab (travel), maybe submit form or show done message
// Final step submit or show done
print("All tabs completed!");
// You can trigger full form submit here
}
// Submit the full form here
}
// if (!isValidData(data))
// {
// print("USERDETAILS : $userDetials");
// print("Validation Failed: Required fields are missing.");
// setState(() {});
// return; // Stop execution if validation fails
// } else
// {
// print("USERDETAILS : $userDetials");
//
// if (currentIndex < tabKeys.length - 1) {
// // Move to next tab
// setState(() {
// selectedTab = tabKeys[currentIndex + 1];
// });
// } else {
// // Already at last tab (travel), maybe submit form or show done message
// print("All tabs completed!");
// // You can trigger full form submit here
// }
// }
}
void handleSubmit() async {
@ -601,7 +641,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Map<String, dynamic> data = userDetials;
if (!isValidData(data)) {
if (!isValidData(data) && isValidDataTwo(data)) {
print("USERDETAILS : $userDetials");
print("Validation Failed: Required fields are missing.");
setState(() {});
@ -623,7 +663,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"last_name",
"email",
"mobile_no",
// "employeeCode"
// "employeeCode",
];
if (apiselectedUser == null) {
@ -647,8 +687,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
if (data["alternate_mobile_no"] != null &&
data["alternate_mobile_no"].toString().isNotEmpty) {
if (!RegExp(r"^\d{10}$")
.hasMatch(data["alternate_mobile_no"].toString())) {
if (!RegExp(
r"^\d{10}$",
).hasMatch(data["alternate_mobile_no"].toString())) {
errorMessages["alternate_mobile_no"] =
"Enter 10 digits"; // Invalid mobile number format
}
@ -656,14 +697,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Email validation
if (data["email"] != null && data["email"].toString().isNotEmpty) {
if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
.hasMatch(data["email"].toString())) {
if (!RegExp(
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
).hasMatch(data["email"].toString())) {
errorMessages["email"] = "Invalid email format"; // Invalid email format
}
}
return errorMessages.isEmpty; // Valid if there are no errors
}
bool isValidDataTwo(Map<String, dynamic> data) {
errorMessages.clear(); // Reset errors
// Required fields that must not be empty
List<String> requiredFields = ["employee_code"];
// Check validation for each field
for (String field in requiredFields) {
if (data[field] == null || data[field].toString().trim().isEmpty) {
errorMessages[field] = "Required";
}
}
return errorMessages.isEmpty; // Valid if there are no errors
}
void _clearError(String field) {
if (mounted && errorMessages.containsKey(field)) {
setState(() {
@ -814,8 +872,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("enteredPassword - $enteredPassword ");
if (hashedPassword != null && hashedPassword.isNotEmpty) {
bool isMatch =
BCrypt.checkpw(enteredPassword, hashedPassword); // Compare passwords
bool isMatch = BCrypt.checkpw(
enteredPassword,
hashedPassword,
); // Compare passwords
setState(() {
// Ensure UI updates
@ -825,8 +885,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print(" Password match!");
} else {
print(" Password NOT match!");
errorMessages
.remove("password"); // Clear error if password is different
errorMessages.remove(
"password",
); // Clear error if password is different
}
});
} else {
@ -836,8 +897,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: Color(0xFFf5f5f5),
@ -846,22 +909,24 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
horizontal:
MediaQuery.of(context).size.width *
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
)
: EdgeInsets.all(0),
child: Row(
children: [
Expanded(child: buildData(isDesktop, context)),
],
children: [Expanded(child: buildData(isDesktop, context))],
),
),
);
});
},
);
}
Widget buildData(bool isDesktop, context) {
@ -875,7 +940,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
children: [
Expanded(
child: Container(
height: isDesktop
height:
isDesktop
? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
child: Padding(
@ -888,24 +954,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: isDesktop
child:
isDesktop
? Row(
mainAxisAlignment: MainAxisAlignment.end,
children: (selectedTab == "travel" ||
children:
(selectedTab == "travel" ||
selectedRole == "5" ||
setSelectesUserType == true)
? _buildSubmit(isDesktop, layoutColor!)
: _buildNext(isDesktop, layoutColor!),
: _buildNext(
isDesktop,
layoutColor!,
), // _buildGoBack(isDesktop, layoutColor!),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: (selectedTab == "travel" ||
mainAxisAlignment: MainAxisAlignment.end,
children:
(selectedTab == "travel" ||
selectedRole == "5" ||
setSelectesUserType == true)
? _buildSubmit(isDesktop, layoutColor!)
: _buildNext(isDesktop, layoutColor!),
)),
)
),
),
),
],
),
);
@ -944,9 +1017,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// })
],
),
SizedBox(
height: 18,
),
SizedBox(height: 18),
isDesktop
? buildTabsForUser()
: SingleChildScrollView(
@ -955,14 +1026,13 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
),
Container(
// color: Colors.yellow.shade50,
height: MediaQuery.of(context).size.height * 0.64,
child: Row(
children: [
Expanded(child: buildTabContents(isDesktop, isViewMode)),
],
),
)
),
],
),
),
@ -977,7 +1047,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
userIdApi:userIdApi,
userIdApi: userIdApi,
controllers: controllers,
errorMessages: errorMessages,
selectedGender: selectedGender,
@ -1012,7 +1082,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return OfficeDetails(
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
userIdApi:userIdApi,
userIdApi: userIdApi,
controllers: controllers,
errorMessages: errorMessages,
selectedLevel: selectedLevel,
@ -1063,14 +1133,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
errorMessages: errorMessages,
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
passportFileUrlFromApi: passportFileUrlFromApi,
userIdApi:userIdApi,
userIdApi: userIdApi,
);
default:
return PersonalDetails(
personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
userIdApi:userIdApi,
userIdApi: userIdApi,
controllers: controllers,
errorMessages: errorMessages,
selectedGender: selectedGender,
@ -1101,9 +1171,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Map<String, String> getTabs(bool setSelectesUserType) {
if (setSelectesUserType || selectedRole == "5") {
return {
"personal": "Personal Details",
};
return {"personal": "Personal Details"};
} else {
return allTabs;
}
@ -1113,16 +1181,37 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return Row(
crossAxisAlignment: CrossAxisAlignment.end, // important
children: tabs.entries.map((entry) {
children:
tabs.entries.map((entry) {
final isSelected = selectedTab == entry.key;
return GestureDetector(
onTap: () {
setState(() {
bool isValid = false;
final currentTab = selectedTab;
if (currentTab == "personal") {
isValid = isValidData(userDetials);
if (isValid) {
selectedTab = entry.key;
}
} else if (currentTab == "office") {
isValid = isValidDataTwo(userDetials);
if (isValid) {
selectedTab = entry.key;
}
} else {
isValid =
true; // Travel tab might not need validation at this point
selectedTab = entry.key;
}
});
},
child: Padding(
padding: const EdgeInsets.only(right: 24.0), // space between tabs
padding: const EdgeInsets.only(
right: 24.0,
), // space between tabs
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -1131,7 +1220,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
color:
isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
),
),
const SizedBox(height: 8),
@ -1149,12 +1239,42 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
);
}
// ---- Submit ---------------------------------------
// ---- Submit ---------------------------------------
List<Widget> _buildGoBack(isDesktop, Color layoutColor) {
return [
MouseRegion(
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor:
isViewMode ? Colors.white : Colors.white, // Keep original color
disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: handleGoBack,
child: Text("Back"),
),
),
];
}
List<Widget> _buildNext(isDesktop, Color layoutColor) {
return [
MouseRegion(
cursor: isViewMode
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
@ -1177,7 +1297,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// isViewMode ? null : handleNext, // Disable when in view mode
child: Text("Next"),
),
)
),
];
}
@ -1196,20 +1316,21 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
onPressed: () {
isEditProfile ? context.go('/listPlan') : context.go('/listUser');
},
child: Text("Cancel")),
SizedBox(
width: 20,
child: Text("Cancel"),
),
SizedBox(width: 20),
if (!isViewMode)
MouseRegion(
cursor: isViewMode
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor: isViewMode
foregroundColor:
isViewMode
? Colors.white
: Colors.white, // Keep original color
disabledBackgroundColor:
@ -1225,7 +1346,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
isViewMode ? null : handleSubmit, // Disable when in view mode
child: Text("Submit"),
),
)
),
];
}
}

View File

@ -17,7 +17,6 @@ class OfficeDetails extends StatefulWidget {
final bool isViewMode;
final String? userIdApi;
final ValueChanged<String?>? onLevelChanged;
final ValueChanged<String?>? onDepartmentChanged;
final ValueChanged<String?>? onFirstApproverChanged;
@ -157,17 +156,25 @@ class _OfficeDetailsState extends State<OfficeDetails> {
fetchFindGroup();
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
try {
// Basic validation: Check mobile number length
if (field == "employeeCode") {
field = "employee_code";
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
final response = await apiService.CheckDuplicate(
label,
field,
value,
userId,
);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}");
return;
} else {
@ -290,7 +297,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
SizedBox(height: 20),
_buildFirstRow(widget.isDesktop),
if (widget.isDesktop) SizedBox(height: 10),
_buildSecondRow(widget.isDesktop),
@ -407,7 +414,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Employee Code",
"Employee Code *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -425,8 +432,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("employeeCode");
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi);
_clearError("employee_code");
apiCheckDuplicate(
"Employee Code",
"employee_code",
value,
widget.userIdApi,
);
},
decoration: InputDecoration(
labelText: "Employee Code",
@ -441,10 +453,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
),
),
),
if (widget.errorMessages["employeeCode"] != null) ...[
if (widget.errorMessages["employee_code"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["employeeCode"]!,
widget.errorMessages["employee_code"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
@ -452,7 +464,71 @@ class _OfficeDetailsState extends State<OfficeDetails> {
);
}
// Widget buildDepartmentFieldOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Department",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// isFocused: false, // Dropdown doesn't use focus
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 45, // Set appropriate height
// child: DropdownButtonFormField<String>(
// value: selectedDepartment,
// // value: widget.isViewMode ? null : selectedDepartment,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// widget.isViewMode
// ? null
// : (newValue) {
// setState(() {
// selectedDepartment = newValue;
// });
// widget.onDepartmentChanged?.call(newValue);
// },
//
// items:
// apiCostData?.map<DropdownMenuItem<String>>((item) {
// return DropdownMenuItem(
//
// value: item['department_id'], // ID as value
// child: Text(item['name'] ?? "Unknown"),
// );
// }).toList(),
// hint: Text("Select"),
// disabledHint: Text(
// selectedDepartment ?? "Select Department",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
// ),
// ),
// ],
// );
// }
Widget buildDepartmentField() {
// Map department_id to department_name
Map<String, String> departmentMap = {
for (var item in apiCostData ?? [])
item['department_id'] as String: item['name'] as String,
};
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -466,41 +542,74 @@ class _OfficeDetailsState extends State<OfficeDetails> {
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus
isFocused: false,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 45, // Set appropriate height
child: DropdownButtonFormField<String>(
value: selectedDepartment,
// value: widget.isViewMode ? null : selectedDepartment,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
height: 40,
child: DropdownSearch<String>(
selectedItem: departmentMap[selectedDepartment],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
), // Proper padding
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 200),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Department...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: departmentMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Department",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (newValue) {
: (String? newValue) {
if (newValue == null) return;
final departmentId =
departmentMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() {
selectedDepartment = newValue;
selectedDepartment = departmentId;
});
widget.onDepartmentChanged?.call(newValue);
widget.onDepartmentChanged?.call(
departmentId,
); // Send department_id
},
items:
apiCostData?.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem(
value: item['department_id'], // ID as value
child: Text(item['name'] ?? "Unknown"),
);
}).toList(),
hint: Text("Select"),
disabledHint: Text(
selectedDepartment ?? "Select Department",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
),
),
),
@ -585,6 +694,17 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
@ -686,6 +806,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(
fontSize: 11.5,
),
),
),
constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
@ -806,6 +942,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(
fontSize: 11.5,
),
),
),
constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
@ -925,6 +1077,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(
fontSize: 11.5,
),
),
),
constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
@ -1047,6 +1215,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(
fontSize: 11.5,
),
),
),
constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(

View File

@ -157,7 +157,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
});
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
try {
// Basic validation: Check mobile number length
if (field == "mobile_no" && value.length != 10) {
@ -167,10 +172,16 @@ class PersonalDetailsState extends State<PersonalDetails> {
return; // Skip the API call if input is invalid
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
final response = await apiService.CheckDuplicate(
label,
field,
value,
userId,
);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}");
return;
} else {
@ -182,9 +193,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
}
}
void _clearError(String field) {
setState(() {
widget.errorMessages.remove(field);
@ -305,11 +313,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
SizedBox(height: 20),
_buildFirstRow(widget.isDesktop),
SizedBox(height: 10),
_buildSecondRow(widget.isDesktop),
// SizedBox(height: 10),
SizedBox(height: 10),
_buildThirdRow(widget.isDesktop),
SizedBox(height: 10),
_buildForthRow(widget.isDesktop),
@ -731,7 +739,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"First Name",
"First Name *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -781,7 +789,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Last Name",
"Last Name*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -822,7 +830,107 @@ class PersonalDetailsState extends State<PersonalDetails> {
);
}
// Widget buildGenderFieldOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Gender",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// width:
// widget.isDesktop
// ? MediaQuery.of(context).size.width * 0.12
// : null,
// isFocused: false,
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 40,
// child: DropdownButtonFormField<String>(
// // value: selectedGender,
// value: widget.isViewMode ? null : selectedGender,
// onChanged:
// widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// selectedGender = newValue;
// print("selectedGender - $selectedGender");
// });
//
// widget.onGenderChanged?.call(newValue);
// },
// decoration: InputDecoration(
// border: InputBorder.none,
// enabled: !widget.isViewMode, // Disables input when in view mode
// ),
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// items: [
// DropdownMenuItem(value: "Male", child: Text("Male")),
// DropdownMenuItem(value: "Female", child: Text("Female")),
// ],
// hint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// disabledHint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
//
// // child: DropdownSearch<String>(
// // selectedItem: selectedGender,
// // // key: ValueKey(selectedGender),
// // popupProps: PopupProps.menu(
// // fit: FlexFit.loose, // Allows flexible height
// // constraints: BoxConstraints(maxHeight: 250),
// //
// // ),
// // items: ["Male", "Female", "Others"],
// // dropdownDecoratorProps: DropDownDecoratorProps(
// // dropdownSearchDecoration: InputDecoration(
// // border: InputBorder.none,
// // contentPadding: EdgeInsets.symmetric(horizontal: 1,),
// // ),
// // ),
// // dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
// // alignment: Alignment.centerLeft,
// // child: Text(
// // selectedItem ?? "Select",
// // style: TextStyle(fontSize: 12),
// // ),
// // ),
// // onChanged: isViewMode
// // ? null
// // : (String? newValue) {
// // setState(() {
// // // Find the country_code based on selected country_name
// // selectedGender = newValue;
// // print("selectedGender - $selectedGender");
// // // if (selectedCountry!.isNotEmpty) {
// // // errorMessages.remove("country_code");
// // // }
// // });
// // },
// //
// //
// // ),
// ),
// ),
// ],
// );
// }
Widget buildGenderField() {
List<String> genderOptions = ["Male", "Female"];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -844,9 +952,45 @@ class PersonalDetailsState extends State<PersonalDetails> {
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: DropdownButtonFormField<String>(
// value: selectedGender,
value: widget.isViewMode ? null : selectedGender,
child: DropdownSearch<String>(
selectedItem: selectedGender,
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: false, // Set true if you want search
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
),
items: genderOptions,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Gender",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
@ -855,65 +999,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
selectedGender = newValue;
print("selectedGender - $selectedGender");
});
widget.onGenderChanged?.call(newValue);
},
decoration: InputDecoration(
border: InputBorder.none,
enabled: !widget.isViewMode, // Disables input when in view mode
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
items: [
DropdownMenuItem(value: "Male", child: Text("Male")),
DropdownMenuItem(value: "Female", child: Text("Female")),
],
hint: Text(
selectedGender ?? "Select Gender",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
disabledHint: Text(
selectedGender ?? "Select Gender",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
),
// child: DropdownSearch<String>(
// selectedItem: selectedGender,
// // key: ValueKey(selectedGender),
// popupProps: PopupProps.menu(
// fit: FlexFit.loose, // Allows flexible height
// constraints: BoxConstraints(maxHeight: 250),
//
// ),
// items: ["Male", "Female", "Others"],
// dropdownDecoratorProps: DropDownDecoratorProps(
// dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(horizontal: 1,),
// ),
// ),
// dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
// alignment: Alignment.centerLeft,
// child: Text(
// selectedItem ?? "Select",
// style: TextStyle(fontSize: 12),
// ),
// ),
// onChanged: isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// // Find the country_code based on selected country_name
// selectedGender = newValue;
// print("selectedGender - $selectedGender");
// // if (selectedCountry!.isNotEmpty) {
// // errorMessages.remove("country_code");
// // }
// });
// },
//
//
// ),
),
),
],
@ -1014,7 +1102,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Email",
"Email *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -1032,7 +1120,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
controller: widget.controllers["email"],
onChanged: (value) {
_clearError("email");
apiCheckDuplicate("Email", "email",value,widget.userIdApi);
apiCheckDuplicate("Email", "email", value, widget.userIdApi);
},
enabled: !widget.isViewMode,
decoration: InputDecoration(
@ -1064,7 +1152,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Mobile Number",
"Mobile Number *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -1083,7 +1171,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("mobile_no");
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi);
apiCheckDuplicate(
"Mobile Number",
"mobile_no",
value,
widget.userIdApi,
);
},
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
@ -1208,6 +1301,18 @@ class PersonalDetailsState extends State<PersonalDetails> {
popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 200),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
@ -1323,12 +1428,79 @@ class PersonalDetailsState extends State<PersonalDetails> {
);
}
// Widget buildRoleOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Role ",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// isFocused: false, // Dropdown doesn't use focus
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 45, // Set appropriate height
// child: DropdownButtonFormField<String>(
// // value: widget.isViewMode ? null : selectedRole,
// value: selectedRole,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// widget.isViewMode
// ? null
// : (newValue) {
// setState(() {
// selectedRole = newValue;
// isTravelAgent = selectedRole == "5";
// // Pass the result back to parent
// widget.onUserTypeChanged?.call(isTravelAgent);
// });
// widget.onRoleChanged?.call(newValue);
// },
// items:
// apiRoleData?.map<DropdownMenuItem<String>>((item) {
// return DropdownMenuItem(
// value: item['dropdown_key'], // ID as value
// child: Text(item['dropdown_value'] ?? "Select Role"),
// );
// }).toList(),
// hint: Text("Select Role"),
// disabledHint: Text(
// selectedRole ?? "Select Role",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
// ),
// ),
// ],
// );
// }
Widget buildRole() {
// Map dropdown_key (ID) -> dropdown_value (Name)
Map<String, String> roleMap = {
for (var item in apiRoleData ?? [])
item['dropdown_key'] as String: item['dropdown_value'] as String,
};
List<String> roleNames = roleMap.values.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Role ",
"Role",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -1337,44 +1509,73 @@ class PersonalDetailsState extends State<PersonalDetails> {
),
SizedBox(height: 5),
CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus
isFocused: false,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 45, // Set appropriate height
child: DropdownButtonFormField<String>(
// value: widget.isViewMode ? null : selectedRole,
value: selectedRole,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
height: 40,
child: DropdownSearch<String>(
selectedItem: selectedRole != null ? roleMap[selectedRole] : null,
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 250),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
), // Proper padding
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Role...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: roleNames,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Role",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged:
widget.isViewMode
? null
: (newValue) {
: (String? newValue) {
if (newValue == null) return;
final selectedKey =
roleMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() {
selectedRole = newValue;
isTravelAgent = selectedRole == "5";
// Pass the result back to parent
widget.onUserTypeChanged?.call(isTravelAgent);
selectedRole = selectedKey;
isTravelAgent = selectedKey == "5";
});
widget.onRoleChanged?.call(newValue);
widget.onUserTypeChanged?.call(isTravelAgent);
widget.onRoleChanged?.call(selectedKey);
},
items:
apiRoleData?.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem(
value: item['dropdown_key'], // ID as value
child: Text(item['dropdown_value'] ?? "Select Role"),
);
}).toList(),
hint: Text("Select Role"),
disabledHint: Text(
selectedRole ?? "Select Role",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
),
),
),
@ -1429,7 +1630,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Password",
"Password *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,

View File

@ -33,7 +33,6 @@ class TravellerDetails extends StatefulWidget {
final String? passportFileUrlFromApi;
final String? userIdApi;
const TravellerDetails({
Key? key,
required this.controllers,
@ -149,15 +148,24 @@ class TravellerDetailsState extends State<TravellerDetails> {
});
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
var newField = "";
try {
if(field == "forex_card_num"){
field = "forex_pre_paid_card_number";
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
final response = await apiService.CheckDuplicate(
label,
newField,
value,
userId,
);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
widget.errorMessages[field] =
response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}");
return;
} else {
@ -705,6 +713,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.only(top: 8),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
@ -1107,7 +1116,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["passportNumber"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("last_name");
_clearError("passport_number");
apiCheckDuplicate(
"Passport Number",
"passport_number",
value,
widget.userIdApi,
);
},
decoration: InputDecoration(
labelText: "Passport Number",
@ -1122,6 +1137,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
),
),
),
if (widget.errorMessages["passport_number"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["passport_number"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
],
);
}
@ -1181,7 +1203,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
_selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today)
? _selectedDateOfIssue!
: today,
firstDate: today,
// firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
@ -1271,7 +1294,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
_selectedDateOfExpiry!.isAfter(today)
? _selectedDateOfExpiry!
: today,
firstDate: today,
// firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
@ -2330,8 +2354,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["forex_card_num"],
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("forex_card_num");
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi);
_clearError("forex_pre_paid_card_number");
apiCheckDuplicate(
"Forex Pre-Paid Card Number",
"forex_pre_paid_card_number",
value,
widget.userIdApi,
);
},
decoration: InputDecoration(
labelText: "Card Number",
@ -2467,9 +2496,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
padding: EdgeInsets.only(
top: 20,
left: 8,
), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -2480,7 +2516,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
),
),
),
],
)
: Column(
@ -2491,7 +2526,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildFrequentFlierInformation(entry),
SizedBox(width: 15),
IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -2782,9 +2821,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
padding: EdgeInsets.only(
top: 20,
left: 8,
), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -2804,7 +2850,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8),
buildHotelMembershipNum(entry),
IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -3035,9 +3085,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
padding: EdgeInsets.only(
top: 20,
left: 8,
), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -3061,7 +3118,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8),
buildVisaValidUpTo(entry),
IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
@ -3187,6 +3248,116 @@ class TravellerDetailsState extends State<TravellerDetails> {
);
}
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
// Map for id => name
Map<String, String> visaTypeMap = {
for (var item in purposeList)
item['dropdown_key'].toString(): item['dropdown_value'].toString(),
};
// Selected value from entry
String? selectedPurpose = entry['visa_type_id']?.toString();
if (!visaTypeMap.containsKey(selectedPurpose)) {
selectedPurpose = null;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Visa Type",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserTravellerWrapper(
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.17
: null,
isFocused: false,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: DropdownSearch<String>(
selectedItem: visaTypeMap[selectedPurpose],
enabled: purposeList.isNotEmpty,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Visa Type...",
hintStyle: GoogleFonts.poppins(fontSize: 11.5),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: visaTypeMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Visa Type",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: (newValue) {
if (newValue == null) return;
final selectedId =
visaTypeMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() {
entry['visa_type_id'] = selectedId;
});
print("Updating form data: visa_type_id -> $selectedId");
},
),
),
),
],
);
}
Widget buildVisaType3(entry) {
if (apiData == null || apiData?['visa_type_of_visa'] == null) {
return Center(
child: Transform.scale(scale: 0.5, child: CircularProgressIndicator()),
);
}
// List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? [];
// List<dynamic> purposeList = [];
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
@ -3402,8 +3573,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: initialDate,
// initialDate: initialDate,
// firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
@ -3490,8 +3662,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: initialDate,
// initialDate: initialDate,
// firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);

View File

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// import 'package:flutter/rendering.dart';
import 'package:flutter/rendering.dart';
import 'dart:html' as html;
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
import 'package:frontend/services/apiService.dart';
@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// SemanticsBinding.instance.ensureSemantics(); // Safe here
SemanticsBinding.instance.ensureSemantics(); // Safe here
if (kIsWeb) {
final uri = Uri.parse(html.window.location.href);
if (uri.path == '/authredirection' &&

View File

@ -1,3 +1,3 @@
//api url
const String apiUrl = 'http://apitest.tripapprovaltool.com';
const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be';
// const String apiUrl = 'https://uat.tripapprovaltool.com';