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

View File

@ -67,11 +67,13 @@ class CostCenterListState extends State<CostCenterList> {
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
@ -97,7 +99,6 @@ class CostCenterListState extends State<CostCenterList> {
} }
Future<List<dynamic>> fetchGetCostCenter() async { Future<List<dynamic>> fetchGetCostCenter() async {
final String apiUrlData = '$apiUrl/api/getCostCenterMaster'; final String apiUrlData = '$apiUrl/api/getCostCenterMaster';
final String? token = await getToken(); final String? token = await getToken();
@ -143,26 +144,30 @@ class CostCenterListState extends State<CostCenterList> {
print("all before filtering: $query"); print("all before filtering: $query");
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
setState(() { setState(() {
filteredCostCenter = allCostCenter.where((object) { filteredCostCenter =
allCostCenter.where((object) {
final isActiveStatus = final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive"; object['is_active'] == "1" ? "active" : "inactive";
return (object['cost_center_id']?.toLowerCase().contains(lowerQuery) ?? return (object['cost_center_id']?.toLowerCase().contains(
lowerQuery,
) ??
false) || false) ||
(object['name']?.toLowerCase().contains(lowerQuery) ?? (object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ?? false) ||
(isActiveStatus.contains(lowerQuery)); (isActiveStatus.contains(lowerQuery));
}).toList(); }).toList();
currentPage = 0; currentPage = 0;
}); });
print("filteredCostCenter: $filteredCostCenter"); print("filteredCostCenter: $filteredCostCenter");
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
@ -171,11 +176,14 @@ class CostCenterListState extends State<CostCenterList> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height * vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
@ -188,7 +196,8 @@ class CostCenterListState extends State<CostCenterList> {
), ),
), ),
); );
}); },
);
} }
Widget buildGroupList(bool isDesktop) { Widget buildGroupList(bool isDesktop) {
@ -216,7 +225,8 @@ class CostCenterListState extends State<CostCenterList> {
// ? EdgeInsets.all(10.0) // ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: isDesktop height:
isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
@ -248,9 +258,7 @@ class CostCenterListState extends State<CostCenterList> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox( SizedBox(width: MediaQuery.of(context).size.width * 0.16),
width: MediaQuery.of(context).size.width * 0.16,
),
if (isDesktop) if (isDesktop)
Container( Container(
@ -262,7 +270,9 @@ class CostCenterListState extends State<CostCenterList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -274,17 +284,19 @@ class CostCenterListState extends State<CostCenterList> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5), color: Colors.grey.shade200,
width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -298,16 +310,18 @@ class CostCenterListState extends State<CostCenterList> {
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: side: BorderSide(color: Color(0xFF114D8B), width: 2),
BorderSide(color: Color(0xFF114D8B), width: 2),
), ),
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12), horizontal: 20,
vertical: 12,
),
), ),
onPressed: () async { onPressed: () async {
showDialog( showDialog(
context: context, context: context,
builder: (context) => CostCenterData( builder:
(context) => CostCenterData(
isDesktop: isDesktop, isDesktop: isDesktop,
layoutColor: layoutColor!, layoutColor: layoutColor!,
fetchGetCostCenter: refreshData, fetchGetCostCenter: refreshData,
@ -339,10 +353,7 @@ class CostCenterListState extends State<CostCenterList> {
], ],
), ),
if (!isDesktop) if (!isDesktop) SizedBox(height: 5),
SizedBox(
height: 5,
),
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
@ -357,7 +368,9 @@ class CostCenterListState extends State<CostCenterList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -370,17 +383,18 @@ class CostCenterListState extends State<CostCenterList> {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5), width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -418,14 +432,17 @@ class CostCenterListState extends State<CostCenterList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey), color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Please Create CostCenter Details", "Please Create CostCenter Details",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey), fontSize: 16,
color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -435,19 +452,21 @@ class CostCenterListState extends State<CostCenterList> {
} }
/* Here collect the list to displayed the data in table or card Used */ /* Here collect the list to displayed the data in table or card Used */
List<dynamic> object = List<dynamic> object =
filteredCostCenter.isNotEmpty ? filteredCostCenter : allCostCenter; filteredCostCenter.isNotEmpty
? filteredCostCenter
: allCostCenter;
/* List is Sorting here */ /* List is Sorting here */
object.sort((a, b) { object.sort((a, b) {
DateTime dateA = DateTime.parse(a['created_on']); DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']); DateTime dateB = DateTime.parse(b['created_on']);
return dateB return dateB.compareTo(dateA); // Descending: newest first
.compareTo(dateA); // Descending: newest first
}); });
/* For pagination for list ... */ /* For pagination for list ... */
List paginatedCostCenter = object List paginatedCostCenter =
object
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
@ -455,8 +474,7 @@ class CostCenterListState extends State<CostCenterList> {
/* Table ... */ /* Table ... */
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = double minWidth = isDesktop ? constraints.maxWidth : 1300;
isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
@ -465,7 +483,9 @@ class CostCenterListState extends State<CostCenterList> {
columnSpacing: isDesktop ? 24.0 : 16.0, columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200), width: 0.5,
color: Colors.grey.shade200,
),
), ),
columns: [ columns: [
DataColumn( DataColumn(
@ -473,48 +493,68 @@ class CostCenterListState extends State<CostCenterList> {
'Name', 'Name',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Description', 'Description',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Status', 'Status',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Actions', 'Actions',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
], ],
rows: paginatedCostCenter.map((tableObject) { rows:
String costcenterId = tableObject['cost_center_id'] paginatedCostCenter.map((tableObject) {
String costcenterId =
tableObject['cost_center_id']
.toString(); // Get user ID .toString(); // Get user ID
bool isSelected = selectedCostCenterId == costcenterId; bool isSelected =
selectedCostCenterId == costcenterId;
return DataRow(cells: [ return DataRow(
DataCell(Text(tableObject['name'] ?? '', cells: [
DataCell(
Text(
tableObject['name'] ?? '',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
DataCell(Text(tableObject['description'] ?? 'N/A', ),
),
DataCell(
Text(
tableObject['description'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
),
),
DataCell( DataCell(
Text( Text(
tableObject['is_active'] == "1" tableObject['is_active'] == "1"
@ -523,7 +563,10 @@ class CostCenterListState extends State<CostCenterList> {
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
color: tableObject['is_active'] == "1" ? Colors.green : Colors.red, color:
tableObject['is_active'] == "1"
? Colors.green
: Colors.red,
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -550,22 +593,31 @@ class CostCenterListState extends State<CostCenterList> {
// //
final costcenterId = int.tryParse( final costcenterId = int.tryParse(
tableObject['cost_center_id'] tableObject['cost_center_id']
.toString()); .toString(),
);
if (costcenterId != null) { if (costcenterId != null) {
print("Table cell - costcenter Id -- $costcenterId"); print(
final data = await apiService.getCostCenterDetailsFind(costcenterId); "Table cell - costcenter Id -- $costcenterId",
);
final data = await apiService
.getCostCenterDetailsFind(
costcenterId,
);
print("CostCenterId -- $data"); print("CostCenterId -- $data");
showDialog( showDialog(
context: context, context: context,
builder: (context) => CostCenterData( builder:
(context) => CostCenterData(
isDesktop: isDesktop, isDesktop: isDesktop,
costcenterId: costcenterId, // Pass the ID costcenterId:
costcenterId, // Pass the ID
costcenterData: data, costcenterData: data,
layoutColor: layoutColor!, layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex, // fetchGetForex: fetchGetForex,
fetchGetCostCenter: refreshData, fetchGetCostCenter:
refreshData,
// role: // role:
// "Travel Agent" // "Travel Agent"
), ),
@ -576,7 +628,8 @@ class CostCenterListState extends State<CostCenterList> {
}, },
), ),
), ),
]); ],
);
}).toList(), }).toList(),
), ),
); );
@ -592,7 +645,9 @@ class CostCenterListState extends State<CostCenterList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -612,7 +667,8 @@ class CostCenterListState extends State<CostCenterList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700,
),
), ),
GestureDetector( GestureDetector(
@ -630,23 +686,31 @@ class CostCenterListState extends State<CostCenterList> {
// //
final costcenterId = int.tryParse( final costcenterId = int.tryParse(
cardObject['cost_center_id'] cardObject['cost_center_id']
.toString()); .toString(),
);
if (costcenterId != null) { if (costcenterId != null) {
print("costcenterId -- $costcenterId"); print(
"costcenterId -- $costcenterId",
);
final data = await apiService final data = await apiService
.getCostCenterDetailsFind(costcenterId); .getCostCenterDetailsFind(
costcenterId,
);
print("CostCenterId -- $data"); print("CostCenterId -- $data");
showDialog( showDialog(
context: context, context: context,
builder: (context) => CostCenterData( builder:
(context) => CostCenterData(
isDesktop: isDesktop, isDesktop: isDesktop,
costcenterId:costcenterId, // Pass the ID costcenterId:
costcenterId, // Pass the ID
costcenterData: data, costcenterData: data,
layoutColor: layoutColor!, layoutColor: layoutColor!,
// fetchGetCostCenter: fetchGetCostCenter, // fetchGetCostCenter: fetchGetCostCenter,
fetchGetCostCenter: refreshData, fetchGetCostCenter:
refreshData,
// role: // role:
// "Travel Agent" // "Travel Agent"
), ),
@ -745,13 +809,12 @@ class CostCenterListState extends State<CostCenterList> {
cardObject['description'] ?? '', cardObject['description'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
SizedBox( SizedBox(width: 10),
width: 10,
),
Column( Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
@ -760,7 +823,8 @@ class CostCenterListState extends State<CostCenterList> {
cardObject['description'] ?? '', cardObject['description'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
@ -776,13 +840,13 @@ class CostCenterListState extends State<CostCenterList> {
); );
} }
return Expanded( return Expanded(
child: Column( child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: isDesktop child:
isDesktop
? (searchController.text.isNotEmpty && ? (searchController.text.isNotEmpty &&
filteredCostCenter.isEmpty filteredCostCenter.isEmpty
? Center( ? Center(
@ -790,7 +854,8 @@ class CostCenterListState extends State<CostCenterList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
@ -804,10 +869,13 @@ class CostCenterListState extends State<CostCenterList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: buildMobileCardView(paginatedCostCenter)), : buildMobileCardView(
paginatedCostCenter,
)),
), ),
// Expanded( // Expanded(
// child: isDesktop // 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(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
@ -141,10 +143,13 @@ class DepartmentListState extends State<DepartmentList> {
print("all before filtering: $query"); print("all before filtering: $query");
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
setState(() { setState(() {
filteredDepartment = allDepartment.where((object) { filteredDepartment =
allDepartment.where((object) {
final isActiveStatus = final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive"; object['is_active'] == "1" ? "active" : "inactive";
return (object['department_id']?.toLowerCase().contains(lowerQuery) ?? return (object['department_id']?.toLowerCase().contains(
lowerQuery,
) ??
false) || false) ||
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) || (object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
(object['description']?.toLowerCase().contains(lowerQuery) ?? (object['description']?.toLowerCase().contains(lowerQuery) ??
@ -158,8 +163,10 @@ class DepartmentListState extends State<DepartmentList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
@ -168,11 +175,14 @@ class DepartmentListState extends State<DepartmentList> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height * vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
@ -185,7 +195,8 @@ class DepartmentListState extends State<DepartmentList> {
), ),
), ),
); );
}); },
);
} }
Widget buildGroupList(bool isDesktop) { Widget buildGroupList(bool isDesktop) {
@ -213,7 +224,8 @@ class DepartmentListState extends State<DepartmentList> {
// ? EdgeInsets.all(10.0) // ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: isDesktop height:
isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
@ -245,9 +257,7 @@ class DepartmentListState extends State<DepartmentList> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox( SizedBox(width: MediaQuery.of(context).size.width * 0.16),
width: MediaQuery.of(context).size.width * 0.16,
),
if (isDesktop) if (isDesktop)
Container( Container(
@ -259,7 +269,9 @@ class DepartmentListState extends State<DepartmentList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -271,17 +283,19 @@ class DepartmentListState extends State<DepartmentList> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5), color: Colors.grey.shade200,
width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -295,16 +309,18 @@ class DepartmentListState extends State<DepartmentList> {
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: side: BorderSide(color: Color(0xFF114D8B), width: 2),
BorderSide(color: Color(0xFF114D8B), width: 2),
), ),
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12), horizontal: 20,
vertical: 12,
),
), ),
onPressed: () async { onPressed: () async {
showDialog( showDialog(
context: context, context: context,
builder: (context) => DepartmentData( builder:
(context) => DepartmentData(
isDesktop: isDesktop, isDesktop: isDesktop,
layoutColor: layoutColor!, layoutColor: layoutColor!,
fetchGetDepartment: refreshData, fetchGetDepartment: refreshData,
@ -336,10 +352,7 @@ class DepartmentListState extends State<DepartmentList> {
], ],
), ),
if (!isDesktop) if (!isDesktop) SizedBox(height: 5),
SizedBox(
height: 5,
),
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
@ -354,7 +367,9 @@ class DepartmentListState extends State<DepartmentList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -367,17 +382,18 @@ class DepartmentListState extends State<DepartmentList> {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5), width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -415,14 +431,17 @@ class DepartmentListState extends State<DepartmentList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey), color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Please Create Department Details", "Please Create Department Details",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey), fontSize: 16,
color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -431,7 +450,8 @@ class DepartmentListState extends State<DepartmentList> {
); );
} }
/* Here collect the list to displayed the data in table or card Used */ /* Here collect the list to displayed the data in table or card Used */
List<dynamic> object = filteredDepartment.isNotEmpty List<dynamic> object =
filteredDepartment.isNotEmpty
? filteredDepartment ? filteredDepartment
: allDepartment; : allDepartment;
@ -440,12 +460,12 @@ class DepartmentListState extends State<DepartmentList> {
DateTime dateA = DateTime.parse(a['created_on']); DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']); DateTime dateB = DateTime.parse(b['created_on']);
return dateB return dateB.compareTo(dateA); // Descending: newest first
.compareTo(dateA); // Descending: newest first
}); });
/* For pagination for list ... */ /* For pagination for list ... */
List paginatedDepartment = object List paginatedDepartment =
object
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
@ -453,8 +473,7 @@ class DepartmentListState extends State<DepartmentList> {
/* Table ... */ /* Table ... */
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = double minWidth = isDesktop ? constraints.maxWidth : 1300;
isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
@ -463,7 +482,9 @@ class DepartmentListState extends State<DepartmentList> {
columnSpacing: isDesktop ? 24.0 : 16.0, columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200), width: 0.5,
color: Colors.grey.shade200,
),
), ),
columns: [ columns: [
DataColumn( DataColumn(
@ -471,51 +492,68 @@ class DepartmentListState extends State<DepartmentList> {
'Name', 'Name',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Description', 'Description',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Status', 'Status',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Actions', 'Actions',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
], ],
rows: paginatedDepartment.map((tableObject) { rows:
paginatedDepartment.map((tableObject) {
String departmentId = String departmentId =
tableObject['department_id'] tableObject['department_id']
.toString(); // Get user ID .toString(); // Get user ID
bool isSelected = bool isSelected =
selectedDepartmentId == departmentId; selectedDepartmentId == departmentId;
return DataRow(cells: [ return DataRow(
DataCell(Text(tableObject['name'] ?? '', cells: [
DataCell(
Text(
tableObject['name'] ?? '',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
),
),
DataCell( DataCell(
Text(tableObject['description'] ?? 'N/A', Text(
tableObject['description'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
),
),
DataCell( DataCell(
Text( Text(
tableObject['is_active'] == "1" tableObject['is_active'] == "1"
@ -524,7 +562,8 @@ class DepartmentListState extends State<DepartmentList> {
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
color: tableObject['is_active'] == "1" color:
tableObject['is_active'] == "1"
? Colors.green ? Colors.green
: Colors.red, : Colors.red,
), ),
@ -539,37 +578,45 @@ class DepartmentListState extends State<DepartmentList> {
// apiService.getSingleUser(id), // apiService.getSingleUser(id),
// ), // ),
GestureDetector( GestureDetector(
child: Tooltip(
message: 'Edit Department Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15), height: 15,
),
),
onTap: () async { onTap: () async {
// final userId = getUserId(user['user_id']); // final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final departmentId = int.tryParse( final departmentId = int.tryParse(
tableObject['department_id'] tableObject['department_id']
.toString()); .toString(),
);
if (departmentId != null) { if (departmentId != null) {
print( print(
"Table cell - department Id -- $departmentId"); "Table cell - department Id -- $departmentId",
);
final data = await apiService final data = await apiService
.getDepartmentDetailsFind( .getDepartmentDetailsFind(
departmentId); departmentId,
);
print("DepartmentId -- $data"); print("DepartmentId -- $data");
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder:
DepartmentData( (context) => DepartmentData(
isDesktop: isDesktop, isDesktop: isDesktop,
departmentId: departmentId:
departmentId, // Pass the ID departmentId, // Pass the ID
departmentData: data, departmentData: data,
layoutColor: layoutColor!, layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex, // fetchGetForex: fetchGetForex,
fetchGetDepartment: refreshData, fetchGetDepartment:
refreshData,
// role: // role:
// "Travel Agent" // "Travel Agent"
), ),
@ -580,7 +627,8 @@ class DepartmentListState extends State<DepartmentList> {
}, },
), ),
), ),
]); ],
);
}).toList(), }).toList(),
), ),
); );
@ -596,7 +644,9 @@ class DepartmentListState extends State<DepartmentList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -616,7 +666,8 @@ class DepartmentListState extends State<DepartmentList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700,
),
), ),
GestureDetector( GestureDetector(
@ -634,20 +685,23 @@ class DepartmentListState extends State<DepartmentList> {
// //
final departmentId = int.tryParse( final departmentId = int.tryParse(
cardObject['department_id'] cardObject['department_id']
.toString()); .toString(),
);
if (departmentId != null) { if (departmentId != null) {
print( print(
"departmentId -- $departmentId"); "departmentId -- $departmentId",
);
final data = await apiService final data = await apiService
.getDepartmentDetailsFind( .getDepartmentDetailsFind(
departmentId); departmentId,
);
print("DepartmentId -- $data"); print("DepartmentId -- $data");
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder:
DepartmentData( (context) => DepartmentData(
isDesktop: isDesktop, isDesktop: isDesktop,
departmentId: departmentId:
departmentId, // Pass the ID departmentId, // Pass the ID
@ -754,13 +808,12 @@ class DepartmentListState extends State<DepartmentList> {
cardObject['description'] ?? '', cardObject['description'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
SizedBox( SizedBox(width: 10),
width: 10,
),
Column( Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
@ -769,7 +822,8 @@ class DepartmentListState extends State<DepartmentList> {
cardObject['description'] ?? '', cardObject['description'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
@ -790,7 +844,8 @@ class DepartmentListState extends State<DepartmentList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: isDesktop child:
isDesktop
? (searchController.text.isNotEmpty && ? (searchController.text.isNotEmpty &&
filteredDepartment.isEmpty filteredDepartment.isEmpty
? Center( ? Center(
@ -798,7 +853,8 @@ class DepartmentListState extends State<DepartmentList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
@ -812,11 +868,13 @@ class DepartmentListState extends State<DepartmentList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: buildMobileCardView( : buildMobileCardView(
paginatedDepartment)), paginatedDepartment,
)),
), ),
// Expanded( // Expanded(
// child: isDesktop // 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(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
@ -151,7 +153,8 @@ class ForexDataListState extends State<ForexDataList> {
if (!data.containsKey('data') || data['data'] is! List) { if (!data.containsKey('data') || data['data'] is! List) {
throw Exception( 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 List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
@ -180,7 +183,10 @@ class ForexDataListState extends State<ForexDataList> {
} }
Future<void> createUserData( 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 uri = Uri.parse('$apiUrl/api/users/update/$userId');
final String? token = await getToken(); final String? token = await getToken();
@ -230,8 +236,11 @@ class ForexDataListState extends State<ForexDataList> {
} }
} }
void handleToggleUserStatus(String userId, String currentStatus, void handleToggleUserStatus(
Map<String, dynamic> userData) async { String userId,
String currentStatus,
Map<String, dynamic> userData,
) async {
print("Toggling user status - $userId (Current: $currentStatus)"); print("Toggling user status - $userId (Current: $currentStatus)");
final String apiUrlData = final String apiUrlData =
@ -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) { void filterForex(String query) {
print("allForex before filtering: $query"); print("allForex before filtering: $query");
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
setState(() { setState(() {
filteredForex = allForex.where((forex) { filteredForex =
allForex.where((forex) {
final isActiveStatus = final isActiveStatus =
forex['is_active'] == "1" ? "active" : "inactive"; forex['is_active'] == "1" ? "active" : "inactive";
return (forex['country_code']?.toLowerCase().contains(lowerQuery) ?? return (forex['country_code']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(forex['country_name']?.toLowerCase().contains(lowerQuery) ?? (forex['country_name']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) || (forex['currency']?.toLowerCase().contains(lowerQuery) ??
false) ||
(forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ?? (forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(isActiveStatus.contains(lowerQuery)); (isActiveStatus.contains(lowerQuery));
}).toList(); }).toList();
currentPage = 0;
}); });
print("filteredForex: $filteredForex"); print("filteredForex: $filteredForex");
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
@ -332,11 +328,14 @@ class ForexDataListState extends State<ForexDataList> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height * vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
@ -349,7 +348,8 @@ class ForexDataListState extends State<ForexDataList> {
), ),
), ),
); );
}); },
);
} }
Widget buildGroupList(bool isDesktop) { Widget buildGroupList(bool isDesktop) {
@ -377,7 +377,8 @@ class ForexDataListState extends State<ForexDataList> {
// ? EdgeInsets.all(10.0) // ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: isDesktop height:
isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
@ -409,9 +410,7 @@ class ForexDataListState extends State<ForexDataList> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox( SizedBox(width: MediaQuery.of(context).size.width * 0.16),
width: MediaQuery.of(context).size.width * 0.16,
),
if (isDesktop) if (isDesktop)
Container( Container(
@ -423,7 +422,9 @@ class ForexDataListState extends State<ForexDataList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -435,17 +436,19 @@ class ForexDataListState extends State<ForexDataList> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5), color: Colors.grey.shade200,
width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -459,16 +462,18 @@ class ForexDataListState extends State<ForexDataList> {
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: side: BorderSide(color: Color(0xFF114D8B), width: 2),
BorderSide(color: Color(0xFF114D8B), width: 2),
), ),
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12), horizontal: 20,
vertical: 12,
),
), ),
onPressed: () async { onPressed: () async {
showDialog( showDialog(
context: context, context: context,
builder: (context) => ForexData( builder:
(context) => ForexData(
isDesktop: isDesktop, isDesktop: isDesktop,
layoutColor: layoutColor!, layoutColor: layoutColor!,
fetchGetForex: refreshData, fetchGetForex: refreshData,
@ -499,10 +504,7 @@ class ForexDataListState extends State<ForexDataList> {
], ],
), ),
if (!isDesktop) if (!isDesktop) SizedBox(height: 5),
SizedBox(
height: 5,
),
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
@ -517,7 +519,9 @@ class ForexDataListState extends State<ForexDataList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -530,17 +534,18 @@ class ForexDataListState extends State<ForexDataList> {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5), width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -578,14 +583,17 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey), color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Please Create Perdiem Amount", "Please Create Perdiem Amount",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey), fontSize: 16,
color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -601,19 +609,18 @@ class ForexDataListState extends State<ForexDataList> {
DateTime dateA = DateTime.parse(a['created_on']); DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']); DateTime dateB = DateTime.parse(b['created_on']);
return dateB return dateB.compareTo(dateA); // Descending: newest first
.compareTo(dateA); // Descending: newest first
}); });
List paginatedForex = forex List paginatedForex =
forex
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = double minWidth = isDesktop ? constraints.maxWidth : 1300;
isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
@ -622,7 +629,9 @@ class ForexDataListState extends State<ForexDataList> {
columnSpacing: isDesktop ? 24.0 : 16.0, columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200), width: 0.5,
color: Colors.grey.shade200,
),
), ),
columns: [ columns: [
DataColumn( DataColumn(
@ -630,76 +639,105 @@ class ForexDataListState extends State<ForexDataList> {
'Country Code', 'Country Code',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Country', 'Country',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Currency', 'Currency',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Perdiem Amount', 'Perdiem Amount',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Status', 'Status',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Actions', 'Actions',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
], ],
rows: paginatedForex.map((forex) { rows:
String forexId = forex['forex_perdiem_id'] paginatedForex.map((forex) {
String forexId =
forex['forex_perdiem_id']
.toString(); // Get user ID .toString(); // Get user ID
bool isSelected = selectedUserId == forexId; bool isSelected = selectedUserId == forexId;
return DataRow(cells: [ return DataRow(
cells: [
DataCell( DataCell(
Text("${forex['country_code'] ?? ''}", Text(
"${forex['country_code'] ?? ''}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
DataCell(Text(forex['country_name'] ?? '', ),
),
DataCell(
Text(
forex['country_name'] ?? '',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
DataCell(Text(forex['currency'] ?? 'N/A', ),
),
DataCell(
Text(
forex['currency'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
),
),
DataCell( DataCell(
Text(forex['perdiem_amount'] ?? 'N/A', Text(
forex['perdiem_amount'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
),
),
DataCell( DataCell(
Text( Text(
forex['is_active'] == "1" forex['is_active'] == "1"
@ -737,7 +775,8 @@ class ForexDataListState extends State<ForexDataList> {
// //
final forexId = int.tryParse( final forexId = int.tryParse(
forex['forex_perdiem_id'] forex['forex_perdiem_id']
.toString()); .toString(),
);
if (forexId != null) { if (forexId != null) {
print("ForexId -- $forexId"); print("ForexId -- $forexId");
@ -747,9 +786,11 @@ class ForexDataListState extends State<ForexDataList> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => ForexData( builder:
(context) => ForexData(
isDesktop: isDesktop, isDesktop: isDesktop,
forexId: forexId, // Pass the ID forexId:
forexId, // Pass the ID
forexData: data, forexData: data,
layoutColor: layoutColor!, layoutColor: layoutColor!,
// fetchGetForex: fetchGetForex, // fetchGetForex: fetchGetForex,
@ -764,7 +805,8 @@ class ForexDataListState extends State<ForexDataList> {
}, },
), ),
), ),
]); ],
);
}).toList(), }).toList(),
), ),
); );
@ -779,7 +821,9 @@ class ForexDataListState extends State<ForexDataList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -799,7 +843,8 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700,
),
), ),
GestureDetector( GestureDetector(
@ -816,8 +861,8 @@ class ForexDataListState extends State<ForexDataList> {
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final forexId = int.tryParse( final forexId = int.tryParse(
forex['forex_perdiem_id'] forex['forex_perdiem_id'].toString(),
.toString()); );
if (forexId != null) { if (forexId != null) {
print("ForexId -- $forexId"); print("ForexId -- $forexId");
@ -827,7 +872,8 @@ class ForexDataListState extends State<ForexDataList> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => ForexData( builder:
(context) => ForexData(
isDesktop: isDesktop, isDesktop: isDesktop,
forexId: forexId:
forexId, // Pass the ID forexId, // Pass the ID
@ -933,7 +979,8 @@ class ForexDataListState extends State<ForexDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w500), fontWeight: FontWeight.w500,
),
), ),
], ],
), ),
@ -952,13 +999,12 @@ class ForexDataListState extends State<ForexDataList> {
forex['currency'] ?? '', forex['currency'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
SizedBox( SizedBox(width: 10),
width: 10,
),
Column( Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
@ -967,7 +1013,8 @@ class ForexDataListState extends State<ForexDataList> {
forex['perdiem_amount'] ?? '', forex['perdiem_amount'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
@ -988,7 +1035,8 @@ class ForexDataListState extends State<ForexDataList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: isDesktop child:
isDesktop
? (searchController.text.isNotEmpty && ? (searchController.text.isNotEmpty &&
filteredForex.isEmpty filteredForex.isEmpty
? Center( ? Center(
@ -996,7 +1044,8 @@ class ForexDataListState extends State<ForexDataList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
@ -1010,7 +1059,8 @@ class ForexDataListState extends State<ForexDataList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: buildMobileCardView(paginatedForex)), : 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 '../../utils/pagination.dart';
import 'groupDetails.dart'; import 'groupDetails.dart';
class GroupList extends StatefulWidget { class GroupList extends StatefulWidget {
@override @override
_GroupListState createState() => _GroupListState(); _GroupListState createState() => _GroupListState();
@ -39,7 +37,6 @@ class _GroupListState extends State<GroupList> {
List filteredGroups = []; List filteredGroups = [];
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
int currentPage = 0; int currentPage = 0;
int itemsPerPage = 10; int itemsPerPage = 10;
@ -87,15 +84,11 @@ class _GroupListState extends State<GroupList> {
return prefs.getString('auth_token'); return prefs.getString('auth_token');
} }
Future<List<dynamic>> fetchGroups() async { Future<List<dynamic>> fetchGroups() async {
final result = await apiService.fetchAllGroup(); final result = await apiService.fetchAllGroup();
return result; // Returning raw JSON list return result; // Returning raw JSON list
} }
Future<void> loadAllGroups() async { Future<void> loadAllGroups() async {
try { try {
final result = await apiService.fetchAllGroup(); final result = await apiService.fetchAllGroup();
@ -117,13 +110,20 @@ class _GroupListState extends State<GroupList> {
allGroups.where((group) { allGroups.where((group) {
return (group['name']?.toLowerCase().contains(lowerQuery) ?? return (group['name']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(group['domestic_policy_name']?.toLowerCase().contains(lowerQuery) ?? (group['domestic_policy_name']?.toLowerCase().contains(
false) lowerQuery,
(group['international_policy_name']?.toLowerCase().contains(lowerQuery) ?? ) ??
false) || false)(
group['international_policy_name']?.toLowerCase().contains(
lowerQuery,
) ??
false,
) ||
(group['description']?.toLowerCase().contains(lowerQuery) ?? (group['description']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(group['is_active']?.toLowerCase().contains(lowerQuery) ?? false);}).toList(); (group['is_active']?.toLowerCase().contains(lowerQuery) ??
false);
}).toList();
currentPage = 0; currentPage = 0;
}); });
@ -159,7 +159,7 @@ class _GroupListState extends State<GroupList> {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: jsonEncode({ 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(); loadAllGroups();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder( return ResponsiveBuilder(
@ -213,11 +212,7 @@ class _GroupListState extends State<GroupList> {
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
child: Row( child: Row(children: [Expanded(child: buildGroupList(isDesktop))]),
children: [
Expanded(child: buildGroupList(isDesktop)),
],
),
), ),
); );
}, },
@ -346,15 +341,14 @@ class _GroupListState extends State<GroupList> {
// context.go('/CreateGroup'); // context.go('/CreateGroup');
showDialog( showDialog(
context: context, context: context,
builder: (context) => GroupData( builder:
(context) => GroupData(
isDesktop: isDesktop, isDesktop: isDesktop,
groupId: null, groupId: null,
layoutColor: layoutColor!, layoutColor: layoutColor!,
fetchGetGroup: refreshData fetchGetGroup: refreshData,
), ),
); );
}, },
child: Row( child: Row(
mainAxisSize: mainAxisSize:
@ -556,7 +550,8 @@ class _GroupListState extends State<GroupList> {
rows: rows:
paginatedGroup.map((group) { paginatedGroup.map((group) {
String groupId = String groupId =
group['group_id'].toString(); // Get group ID group['group_id']
.toString(); // Get group ID
bool isSelected = selectedGroupId == groupId; bool isSelected = selectedGroupId == groupId;
return DataRow( return DataRow(
@ -571,7 +566,8 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
DataCell( DataCell(
Text("${group['domestic_policy_name'] ?? 'N/A'}", Text(
"${group['domestic_policy_name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
@ -613,31 +609,39 @@ class _GroupListState extends State<GroupList> {
), ),
DataCell( DataCell(
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
if (group['group_id'] != null) { if (group['group_id'] != null) {
final newGroupID = int.tryParse( final newGroupID = int.tryParse(
group['group_id'].toString()); group['group_id'].toString(),
);
if (newGroupID != null) { if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind( final data = await apiService
newGroupID); // Always an int .getGroupDetailsFind(
newGroupID,
); // Always an int
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder:
GroupData( (context) => GroupData(
isDesktop: isDesktop, isDesktop: isDesktop,
groupId: newGroupID, groupId: newGroupID,
// Pass the ID // Pass the ID
groupData: data, groupData: data,
layoutColor: layoutColor!, layoutColor:
fetchGetGroup: refreshData layoutColor!,
fetchGetGroup:
refreshData,
), ),
); );
} }
} else { } else {
print("something went wrong check properly"); print(
"something went wrong check properly",
);
} }
}, },
@ -646,16 +650,20 @@ class _GroupListState extends State<GroupList> {
// }, // },
child: Tooltip( child: Tooltip(
message: 'Edit Group Details', message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/edit.png', child: Image.asset(
width: 20, height: 15), ), 'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
), ),
SizedBox(
width: 5,
), ),
),
SizedBox(width: 5),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
final idStr = group['group_id']; final idStr = group['group_id'];
final id = int.tryParse(idStr.toString()); final id = int.tryParse(
idStr.toString(),
);
if (id == null) { if (id == null) {
print("group_id is null"); print("group_id is null");
@ -667,8 +675,12 @@ class _GroupListState extends State<GroupList> {
}, },
child: Tooltip( child: Tooltip(
message: 'Delete Group Details', message: 'Delete Group Details',
child: Image.asset('assets/images/IconsImg/delete.png', child: Image.asset(
width: 20, height: 15),), 'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
), ),
], ],
), ),
@ -688,7 +700,10 @@ class _GroupListState extends State<GroupList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 6), margin: EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -700,7 +715,8 @@ class _GroupListState extends State<GroupList> {
children: [ children: [
// Row 1: Policy Name and Actions // Row 1: Policy Name and Actions
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: RichText( child: RichText(
@ -718,11 +734,12 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['name'] ?? 'N/A'}", text:
"${object['name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
@ -736,42 +753,54 @@ class _GroupListState extends State<GroupList> {
onTap: () async { onTap: () async {
if (object['group_id'] != null) { if (object['group_id'] != null) {
final newGroupID = int.tryParse( final newGroupID = int.tryParse(
object['group_id'].toString()); object['group_id'].toString(),
);
if (newGroupID != null) { if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind( final data = await apiService
newGroupID); // Always an int .getGroupDetailsFind(
newGroupID,
); // Always an int
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder:
GroupData( (context) => GroupData(
isDesktop: isDesktop, isDesktop: isDesktop,
groupId: newGroupID, groupId: newGroupID,
// Pass the ID // Pass the ID
groupData: data, groupData: data,
layoutColor: layoutColor!, layoutColor:
fetchGetGroup: refreshData layoutColor!,
fetchGetGroup:
refreshData,
), ),
); );
} }
} else { } else {
print("something went wrong check properly"); print(
"something went wrong check properly",
);
} }
}, },
// onTap: () { // onTap: () {
// context.go("/CreateGroup", extra: group); // context.go("/CreateGroup", extra: group);
// }, // },
child: Tooltip( message: 'Edit Group Details', child: Tooltip(
child: Image.asset('assets/images/IconsImg/edit.png', message: 'Edit Group Details',
width: 20, height: 15),), child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
), ),
SizedBox(
width: 5,
), ),
),
SizedBox(width: 5),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
final idStr = object['group_id']; final idStr = object['group_id'];
final id = int.tryParse(idStr.toString()); final id = int.tryParse(
idStr.toString(),
);
if (id == null) { if (id == null) {
print("group_id is null"); print("group_id is null");
@ -783,8 +812,12 @@ class _GroupListState extends State<GroupList> {
}, },
child: Tooltip( child: Tooltip(
message: 'Edit Group Details', message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/delete.png', child: Image.asset(
width: 20, height: 15),), 'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
), ),
], ],
), ),
@ -792,7 +825,6 @@ class _GroupListState extends State<GroupList> {
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 2: // Row 2:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -809,18 +841,19 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['domestic_policy_name'] ?? 'N/A'}", text:
"${object['domestic_policy_name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
), ),
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 3: // Row 3:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -837,18 +870,18 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['international_policy_name']}", text:
"${object['international_policy_name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
), ),
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 4: // Row 4:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -865,11 +898,12 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['description'] ?? 'N/A'}", text:
"${object['description'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],

View File

@ -83,11 +83,13 @@ class HotelsDataListState extends State<HotelsDataList> {
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
@ -150,7 +152,8 @@ class HotelsDataListState extends State<HotelsDataList> {
if (!data.containsKey('data') || data['data'] is! List) { if (!data.containsKey('data') || data['data'] is! List) {
throw Exception( 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 List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
@ -174,7 +177,6 @@ class HotelsDataListState extends State<HotelsDataList> {
} }
} }
// Refresh user list after update // Refresh user list after update
void refreshUserList() { void refreshUserList() {
setState(() { setState(() {
@ -187,15 +189,19 @@ class HotelsDataListState extends State<HotelsDataList> {
print("allHotels before filtering: $query"); print("allHotels before filtering: $query");
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
setState(() { setState(() {
filteredHotels = allHotels.where((hotels) { filteredHotels =
allHotels.where((hotels) {
final isActiveStatus = final isActiveStatus =
hotels['is_active'] == "1" ? "active" : "inactive"; hotels['is_active'] == "1" ? "active" : "inactive";
return (hotels['country_code']?.toLowerCase().contains(lowerQuery) ?? return (hotels['country_code']?.toLowerCase().contains(
lowerQuery,
) ??
false) || false) ||
(hotels['country_name']?.toLowerCase().contains(lowerQuery) ?? (hotels['country_name']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(hotels['city']?.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) ?? (hotels['hotel_name']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(isActiveStatus.contains(lowerQuery)); (isActiveStatus.contains(lowerQuery));
@ -207,8 +213,10 @@ class HotelsDataListState extends State<HotelsDataList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
@ -217,11 +225,14 @@ class HotelsDataListState extends State<HotelsDataList> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * horizontal:
MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height * vertical:
MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
@ -234,7 +245,8 @@ class HotelsDataListState extends State<HotelsDataList> {
), ),
), ),
); );
}); },
);
} }
Widget buildGroupList(bool isDesktop) { Widget buildGroupList(bool isDesktop) {
@ -262,7 +274,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// ? EdgeInsets.all(10.0) // ? EdgeInsets.all(10.0)
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: isDesktop height:
isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
@ -294,9 +307,7 @@ class HotelsDataListState extends State<HotelsDataList> {
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox( SizedBox(width: MediaQuery.of(context).size.width * 0.16),
width: MediaQuery.of(context).size.width * 0.16,
),
if (isDesktop) if (isDesktop)
Container( Container(
@ -308,7 +319,9 @@ class HotelsDataListState extends State<HotelsDataList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -320,17 +333,19 @@ class HotelsDataListState extends State<HotelsDataList> {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, width: 0.5), color: Colors.grey.shade200,
width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -344,16 +359,18 @@ class HotelsDataListState extends State<HotelsDataList> {
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: side: BorderSide(color: Color(0xFF114D8B), width: 2),
BorderSide(color: Color(0xFF114D8B), width: 2),
), ),
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12), horizontal: 20,
vertical: 12,
),
), ),
onPressed: () async { onPressed: () async {
showDialog( showDialog(
context: context, context: context,
builder: (context) => HotelsData( builder:
(context) => HotelsData(
isDesktop: isDesktop, isDesktop: isDesktop,
layoutColor: layoutColor!, layoutColor: layoutColor!,
fetchGetHotels: refreshData, fetchGetHotels: refreshData,
@ -384,10 +401,7 @@ class HotelsDataListState extends State<HotelsDataList> {
], ],
), ),
if (!isDesktop) if (!isDesktop) SizedBox(height: 5),
SizedBox(
height: 5,
),
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
@ -402,7 +416,9 @@ class HotelsDataListState extends State<HotelsDataList> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, color: Color(0xFF9E9DBD)), fontSize: 12,
color: Color(0xFF9E9DBD),
),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
@ -415,17 +431,18 @@ class HotelsDataListState extends State<HotelsDataList> {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5), width: 0.5,
),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, width: 1), color: Colors.grey.shade300,
width: 1,
), ),
), ),
style: GoogleFonts.poppins(
fontSize: 12,
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
@ -463,14 +480,17 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey), color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Please Create Hotels", "Please Create Hotels",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, color: Colors.grey), fontSize: 16,
color: Colors.grey,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -486,19 +506,18 @@ class HotelsDataListState extends State<HotelsDataList> {
DateTime dateA = DateTime.parse(a['created_on']); DateTime dateA = DateTime.parse(a['created_on']);
DateTime dateB = DateTime.parse(b['created_on']); DateTime dateB = DateTime.parse(b['created_on']);
return dateB return dateB.compareTo(dateA); // Descending: newest first
.compareTo(dateA); // Descending: newest first
}); });
List paginatedHotels = hotels List paginatedHotels =
hotels
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = double minWidth = isDesktop ? constraints.maxWidth : 1300;
isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
@ -507,7 +526,9 @@ class HotelsDataListState extends State<HotelsDataList> {
columnSpacing: isDesktop ? 24.0 : 16.0, columnSpacing: isDesktop ? 24.0 : 16.0,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(
width: 0.5, color: Colors.grey.shade200), width: 0.5,
color: Colors.grey.shade200,
),
), ),
columns: [ columns: [
DataColumn( DataColumn(
@ -515,74 +536,105 @@ class HotelsDataListState extends State<HotelsDataList> {
'Hotel Name', 'Hotel Name',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Hotel Chain', 'Hotel Chain',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'City', 'City',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Country', 'Country',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Status', 'Status',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Actions', 'Actions',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600,
)), ),
),
),
], ],
rows: paginatedHotels.map((hotels) { rows:
String hotelsId = hotels['hotel_id'] paginatedHotels.map((hotels) {
String hotelsId =
hotels['hotel_id']
.toString(); // Get user ID .toString(); // Get user ID
bool isSelected = selectedUserId == hotelsId; bool isSelected = selectedUserId == hotelsId;
return DataRow(cells: [ return DataRow(
DataCell(Text(hotels['hotel_name'] ?? 'N/A', cells: [
DataCell(
Text(
hotels['hotel_name'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
DataCell(Text(hotels['hotel_chain'] ?? '', ),
),
DataCell(
Text(
hotels['hotel_chain'] ?? '',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
DataCell(Text(hotels['city'] ?? 'N/A', ),
),
DataCell(
Text(
hotels['city'] ?? 'N/A',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis)), overflow: TextOverflow.ellipsis,
DataCell(Text(hotels['country_name'] ?? '', ),
),
DataCell(
Text(
hotels['country_name'] ?? '',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ),
),
),
DataCell( DataCell(
Text( Text(
hotels['is_active'] == "1" hotels['is_active'] == "1"
@ -591,7 +643,10 @@ class HotelsDataListState extends State<HotelsDataList> {
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
color: hotels['is_active'] == "1" ? Colors.green : Colors.red, color:
hotels['is_active'] == "1"
? Colors.green
: Colors.red,
), ),
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -605,9 +660,9 @@ class HotelsDataListState extends State<HotelsDataList> {
// ), // ),
GestureDetector( GestureDetector(
child: Tooltip( child: Tooltip(
message: 'Delete Hotel Details', message: 'Edit Hotel Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
), ),
@ -617,8 +672,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final hotelsId = int.tryParse( final hotelsId = int.tryParse(
hotels['hotel_id'] hotels['hotel_id'].toString(),
.toString()); );
if (hotelsId != null) { if (hotelsId != null) {
print("HotelsId -- $hotelsId"); print("HotelsId -- $hotelsId");
@ -628,9 +683,11 @@ class HotelsDataListState extends State<HotelsDataList> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => HotelsData( builder:
(context) => HotelsData(
isDesktop: isDesktop, isDesktop: isDesktop,
hotelsId: hotelsId, // Pass the ID hotelsId:
hotelsId, // Pass the ID
hotelsData: data, hotelsData: data,
layoutColor: layoutColor!, layoutColor: layoutColor!,
// fetchGetHotels: fetchGetHotels, // fetchGetHotels: fetchGetHotels,
@ -645,7 +702,8 @@ class HotelsDataListState extends State<HotelsDataList> {
}, },
), ),
), ),
]); ],
);
}).toList(), }).toList(),
), ),
); );
@ -660,7 +718,9 @@ class HotelsDataListState extends State<HotelsDataList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -680,21 +740,26 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700,
),
), ),
GestureDetector( GestureDetector(
child: Tooltip(
message: 'Edit Hotel Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15), height: 15,
),
),
onTap: () async { onTap: () async {
// final userId = getUserId(user['user_id']); // final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final hotelsId = int.tryParse( final hotelsId = int.tryParse(
hotels['hotel_id'] hotels['hotel_id'].toString(),
.toString()); );
if (hotelsId != null) { if (hotelsId != null) {
print("HotelsId -- $hotelsId"); print("HotelsId -- $hotelsId");
@ -704,7 +769,8 @@ class HotelsDataListState extends State<HotelsDataList> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => HotelsData( builder:
(context) => HotelsData(
isDesktop: isDesktop, isDesktop: isDesktop,
hotelsId: hotelsId:
hotelsId, // Pass the ID hotelsId, // Pass the ID
@ -737,7 +803,8 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w500), fontWeight: FontWeight.w500,
),
), ),
], ],
), ),
@ -755,7 +822,8 @@ class HotelsDataListState extends State<HotelsDataList> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.w500), fontWeight: FontWeight.w500,
),
), ),
], ],
), ),
@ -772,7 +840,8 @@ class HotelsDataListState extends State<HotelsDataList> {
hotels['country_name'] ?? '', hotels['country_name'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87), color: Colors.black87,
),
), ),
], ],
), ),
@ -792,7 +861,8 @@ class HotelsDataListState extends State<HotelsDataList> {
// mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: isDesktop child:
isDesktop
? (searchController.text.isNotEmpty && ? (searchController.text.isNotEmpty &&
filteredHotels.isEmpty filteredHotels.isEmpty
? Center( ? Center(
@ -800,7 +870,8 @@ class HotelsDataListState extends State<HotelsDataList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
@ -814,7 +885,8 @@ class HotelsDataListState extends State<HotelsDataList> {
"No matches found", "No matches found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey), color: Colors.grey,
),
), ),
) )
: buildMobileCardView(paginatedHotels)), : 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 Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
TaxiScreen( TaxiScreen({
{required this.onClose, required this.onClose,
this.apiData, this.apiData,
required this.onSavetaxi, required this.onSavetaxi,
required this.selectedItem, required this.selectedItem,
required this.loginUser}); required this.loginUser,
});
@override @override
_TaxiScreenState createState() => _TaxiScreenState(); _TaxiScreenState createState() => _TaxiScreenState();
@ -97,13 +98,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
super.initState(); super.initState();
_addFocusListener( _addFocusListener(
_destinationFocusNode, (focus) => _destinationFocus = focus); _destinationFocusNode,
(focus) => _destinationFocus = focus,
);
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus); _addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus); _addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus); _addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus); _addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
_addFocusListener( _addFocusListener(
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus); _numPassengerFocusNode,
(focus) => _numPassengerFocus = focus,
);
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus); _addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
_destinationController = initController("destination_city"); _destinationController = initController("destination_city");
@ -168,7 +173,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
"location_of_pickup", "location_of_pickup",
"no_of_passengers", "no_of_passengers",
"date", "date",
"time" "time",
]; ];
// Check validation for each field // Check validation for each field
@ -199,9 +204,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile; bool isMobile = sizingInfo.isMobile;
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container( return Container(
// color: Color(0xFFF4F4FB), // color: Color(0xFFF4F4FB),
@ -216,13 +223,14 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: Center( child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)), child: Column(children: _buildAccomadtionForm(isDesktop)),
), ),
) ),
], ],
), ),
), ),
), ),
); );
}); },
);
} }
List<Widget> _buildAccomadtionForm(bool isDesktop) { List<Widget> _buildAccomadtionForm(bool isDesktop) {
@ -235,7 +243,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<List<Widget>> rowBuilders = [ List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop), // _builClassType(isDesktop),
_buildSecondRow(isDesktop) _buildSecondRow(isDesktop),
]; ];
return [ return [
@ -253,19 +261,24 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<Widget> _buildFirstRow(isDesktop) { List<Widget> _buildFirstRow(isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? []; List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList List<DropdownMenuItem<String>> dropdownItems =
.map((item) => DropdownMenuItem<String>( purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'], value: item['dropdown_key'],
child: Text(item['dropdown_value']), child: Text(item['dropdown_value']),
)) ),
)
.toList(); .toList();
if (dropdownItems.isEmpty) { if (dropdownItems.isEmpty) {
dropdownItems.add( dropdownItems.add(
DropdownMenuItem<String>( DropdownMenuItem<String>(
value: null, value: null,
child: Text("No options available", child: Text(
style: TextStyle(color: Colors.grey)), "No options available",
style: TextStyle(color: Colors.grey),
),
), ),
); );
} }
@ -283,20 +296,16 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
isDesktop isDesktop
? Row(children: _buildTripType(isDesktop)) ? Row(children: _buildTripType(isDesktop))
: Column(children: _buildTripType(isDesktop)) : Column(children: _buildTripType(isDesktop)),
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -305,7 +314,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -319,8 +329,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
keyboardType: TextInputType.numberWithOptions(decimal: true), keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.allow(RegExp( FilteringTextInputFormatter.allow(
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
], ],
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Number of Passenger", labelText: "Number of Passenger",
@ -334,19 +345,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["no_of_passengers"] != null) ...[ if (errorMessages["no_of_passengers"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -355,7 +358,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -369,16 +373,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding: EdgeInsets.symmetric(
EdgeInsets.symmetric(horizontal: 10), // Proper padding horizontal: 10,
), // Proper padding
), ),
onChanged: purposeList.isNotEmpty onChanged:
purposeList.isNotEmpty
? (newValue) { ? (newValue) {
setState(() { setState(() {
selectedCarType = newValue; selectedCarType = newValue;
}); });
print( print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}"); "Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
} }
: null, : null,
@ -388,31 +395,31 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
], ],
), ),
if (isDesktop) if (isDesktop) SizedBox.shrink() else SizedBox(height: 8),
SizedBox.shrink()
else
SizedBox(
height: 8,
),
]; ];
} }
List<Widget> _buildTripType(bool isDesktop) { List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? []; List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList List<DropdownMenuItem<String>> dropdownItems =
.map((item) => DropdownMenuItem<String>( purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'], value: item['dropdown_key'],
child: Text(item['dropdown_value']), child: Text(item['dropdown_value']),
)) ),
)
.toList(); .toList();
if (dropdownItems.isEmpty) { if (dropdownItems.isEmpty) {
dropdownItems.add( dropdownItems.add(
DropdownMenuItem<String>( DropdownMenuItem<String>(
value: null, value: null,
child: Text("No options available", child: Text(
style: TextStyle(color: Colors.grey)), "No options available",
style: TextStyle(color: Colors.grey),
),
), ),
); );
} }
@ -425,7 +432,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _taxiReqFocused, isFocused: _taxiReqFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
@ -436,16 +444,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding: EdgeInsets.symmetric(
EdgeInsets.symmetric(horizontal: 10), // Proper padding horizontal: 10,
), // Proper padding
), ),
onChanged: purposeList.isNotEmpty onChanged:
purposeList.isNotEmpty
? (newValue) { ? (newValue) {
setState(() { setState(() {
selectedReqTaxi = newValue; selectedReqTaxi = newValue;
}); });
print( print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}"); "Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
} }
: null, : null,
@ -466,7 +477,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
DateTime? pickedDate = await showDatePicker( DateTime? pickedDate = await showDatePicker(
context: context, context: context,
initialDate: _selectedCheckOutDate != null && initialDate:
_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isAfter(today) _selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate! ? _selectedCheckOutDate!
: today, : today,
@ -494,8 +506,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
// Formatting time to HH:mm (24-hour format) // Formatting time to HH:mm (24-hour format)
final now = DateTime.now(); final now = DateTime.now();
final formattedTime = DateFormat('HH:mm').format( final formattedTime = DateFormat('HH:mm').format(
DateTime(now.year, now.month, now.day, pickedTime.hour, DateTime(
pickedTime.minute), now.year,
now.month,
now.day,
pickedTime.hour,
pickedTime.minute,
),
); );
_timeController.text = formattedTime; _timeController.text = formattedTime;
}); });
@ -511,7 +528,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -535,28 +553,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["destination_city"] != null) ...[ if (errorMessages["destination_city"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Location of Pickup", "Pickup Location",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -569,7 +580,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
controller: _locationController, controller: _locationController,
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Location of Pickup", labelText: "Pickup Location",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey), labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
@ -580,19 +591,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["location_of_pickup"] != null) ...[ if (errorMessages["location_of_pickup"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -601,7 +604,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -622,8 +626,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today, suffixIcon: Icon(
size: 16, color: Colors.grey), Icons.calendar_today,
size: 16,
color: Colors.grey,
),
), ),
), ),
), ),
@ -632,19 +639,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["date"] != null) ...[ if (errorMessages["date"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -653,7 +652,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -674,8 +674,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: suffixIcon: Icon(
Icon(Icons.access_time, size: 16, color: Colors.grey), Icons.access_time,
size: 16,
color: Colors.grey,
),
), ),
), ),
), ),
@ -684,10 +687,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["time"] != null) ...[ if (errorMessages["time"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
@ -704,13 +704,15 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : MediaQuery.of(context).size.width * 0.66,
@ -733,9 +735,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
], ],
), ),
if (isDesktop) Spacer(), if (isDesktop) Spacer(),
SizedBox( SizedBox(height: 5),
height: 5,
),
Column( Column(
children: [ children: [
Row( Row(
@ -756,9 +756,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
child: Text( child: Text(
@ -767,7 +765,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
), ),
SizedBox(width: 10), // Space between buttons SizedBox(width: 10), // Space between buttons
// Save Changes Button // Save Changes Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
@ -775,9 +772,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), // Primary color for save backgroundColor: Color(0xFF114D8B), // Primary color for save
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
child: Text( child: Text(

View File

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

View File

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

View File

@ -17,7 +17,6 @@ class OfficeDetails extends StatefulWidget {
final bool isViewMode; final bool isViewMode;
final String? userIdApi; final String? userIdApi;
final ValueChanged<String?>? onLevelChanged; final ValueChanged<String?>? onLevelChanged;
final ValueChanged<String?>? onDepartmentChanged; final ValueChanged<String?>? onDepartmentChanged;
final ValueChanged<String?>? onFirstApproverChanged; final ValueChanged<String?>? onFirstApproverChanged;
@ -157,17 +156,25 @@ class _OfficeDetailsState extends State<OfficeDetails> {
fetchFindGroup(); 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 { try {
// Basic validation: Check mobile number length
if (field == "employeeCode") { final response = await apiService.CheckDuplicate(
field = "employee_code"; label,
} field,
value,
final response = await apiService.CheckDuplicate(label, field, value, userId); userId,
);
if (response.isNotEmpty) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -290,7 +297,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 10), SizedBox(height: 20),
_buildFirstRow(widget.isDesktop), _buildFirstRow(widget.isDesktop),
if (widget.isDesktop) SizedBox(height: 10), if (widget.isDesktop) SizedBox(height: 10),
_buildSecondRow(widget.isDesktop), _buildSecondRow(widget.isDesktop),
@ -407,7 +414,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Employee Code", "Employee Code *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -425,8 +432,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
controller: widget.controllers["employeeCode"], controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("employeeCode"); _clearError("employee_code");
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi); apiCheckDuplicate(
"Employee Code",
"employee_code",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Employee Code", 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 SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["employeeCode"]!, widget.errorMessages["employee_code"]!,
style: TextStyle(color: Colors.red, fontSize: 12), 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() { 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( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -466,41 +542,74 @@ class _OfficeDetailsState extends State<OfficeDetails> {
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus isFocused: false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 45, // Set appropriate height height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
value: selectedDepartment, selectedItem: departmentMap[selectedDepartment],
// value: widget.isViewMode ? null : selectedDepartment, enabled: !widget.isViewMode,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), popupProps: PopupProps.menu(
decoration: InputDecoration( showSearchBox: true,
border: InputBorder.none, fit: FlexFit.loose,
contentPadding: EdgeInsets.symmetric( menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10, 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: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
: (newValue) { : (String? newValue) {
if (newValue == null) return;
final departmentId =
departmentMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() { 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( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -686,6 +806,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -806,6 +942,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -925,6 +1077,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -1047,6 +1215,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( 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 { try {
// Basic validation: Check mobile number length // Basic validation: Check mobile number length
if (field == "mobile_no" && value.length != 10) { 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 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) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -182,9 +193,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
} }
} }
void _clearError(String field) { void _clearError(String field) {
setState(() { setState(() {
widget.errorMessages.remove(field); widget.errorMessages.remove(field);
@ -305,11 +313,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 10), SizedBox(height: 20),
_buildFirstRow(widget.isDesktop), _buildFirstRow(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
_buildSecondRow(widget.isDesktop), _buildSecondRow(widget.isDesktop),
// SizedBox(height: 10), SizedBox(height: 10),
_buildThirdRow(widget.isDesktop), _buildThirdRow(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
_buildForthRow(widget.isDesktop), _buildForthRow(widget.isDesktop),
@ -731,7 +739,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"First Name", "First Name *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -781,7 +789,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Last Name", "Last Name*",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, 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() { Widget buildGenderField() {
List<String> genderOptions = ["Male", "Female"];
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -844,9 +952,45 @@ class PersonalDetailsState extends State<PersonalDetails> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
// value: selectedGender, selectedItem: selectedGender,
value: widget.isViewMode ? null : 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: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
@ -855,65 +999,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
selectedGender = newValue; selectedGender = newValue;
print("selectedGender - $selectedGender"); print("selectedGender - $selectedGender");
}); });
widget.onGenderChanged?.call(newValue); 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, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Email", "Email *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1064,7 +1152,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Mobile Number", "Mobile Number *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1083,7 +1171,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("mobile_no"); _clearError("mobile_no");
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi); apiCheckDuplicate(
"Mobile Number",
"mobile_no",
value,
widget.userIdApi,
);
}, },
keyboardType: TextInputType.numberWithOptions(decimal: true), keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [ inputFormatters: [
@ -1208,6 +1301,18 @@ class PersonalDetailsState extends State<PersonalDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height 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), constraints: BoxConstraints(maxHeight: 200),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -1323,7 +1428,74 @@ 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() { 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( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -1337,44 +1509,73 @@ class PersonalDetailsState extends State<PersonalDetails> {
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus isFocused: false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 45, // Set appropriate height height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
// value: widget.isViewMode ? null : selectedRole, selectedItem: selectedRole != null ? roleMap[selectedRole] : null,
value: selectedRole, enabled: !widget.isViewMode,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), popupProps: PopupProps.menu(
decoration: InputDecoration( showSearchBox: true,
border: InputBorder.none, fit: FlexFit.loose,
contentPadding: EdgeInsets.symmetric( constraints: BoxConstraints(maxHeight: 250),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10, 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: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
: (newValue) { : (String? newValue) {
if (newValue == null) return;
final selectedKey =
roleMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() { setState(() {
selectedRole = newValue; selectedRole = selectedKey;
isTravelAgent = selectedRole == "5"; isTravelAgent = selectedKey == "5";
// Pass the result back to parent
widget.onUserTypeChanged?.call(isTravelAgent);
}); });
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, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Password", "Password *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

View File

@ -33,7 +33,6 @@ class TravellerDetails extends StatefulWidget {
final String? passportFileUrlFromApi; final String? passportFileUrlFromApi;
final String? userIdApi; final String? userIdApi;
const TravellerDetails({ const TravellerDetails({
Key? key, Key? key,
required this.controllers, 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 { try {
if(field == "forex_card_num"){ final response = await apiService.CheckDuplicate(
field = "forex_pre_paid_card_number"; label,
} newField,
final response = await apiService.CheckDuplicate(label, field, value, userId); value,
userId,
);
if (response.isNotEmpty) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -705,6 +713,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.only(top: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
@ -1107,7 +1116,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["passportNumber"], controller: controllers["passportNumber"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("last_name"); _clearError("passport_number");
apiCheckDuplicate(
"Passport Number",
"passport_number",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Passport Number", 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 != null && _selectedDateOfIssue!.isAfter(today)
? _selectedDateOfIssue! ? _selectedDateOfIssue!
: today, : today,
firstDate: today, // firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -1271,7 +1294,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
_selectedDateOfExpiry!.isAfter(today) _selectedDateOfExpiry!.isAfter(today)
? _selectedDateOfExpiry! ? _selectedDateOfExpiry!
: today, : today,
firstDate: today, // firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -2330,8 +2354,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["forex_card_num"], controller: controllers["forex_card_num"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("forex_card_num"); _clearError("forex_pre_paid_card_number");
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi); apiCheckDuplicate(
"Forex Pre-Paid Card Number",
"forex_pre_paid_card_number",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Card Number", labelText: "Card Number",
@ -2467,9 +2496,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60, height: 60,
child: Center( child: Center(
child: Padding( 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( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -2480,7 +2516,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
), ),
), ),
), ),
], ],
) )
: Column( : Column(
@ -2491,7 +2526,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildFrequentFlierInformation(entry), buildFrequentFlierInformation(entry),
SizedBox(width: 15), SizedBox(width: 15),
IconButton( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -2782,9 +2821,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60, height: 60,
child: Center( child: Center(
child: Padding( 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( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -2804,7 +2850,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8), SizedBox(height: 8),
buildHotelMembershipNum(entry), buildHotelMembershipNum(entry),
IconButton( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -3035,9 +3085,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60, height: 60,
child: Center( child: Center(
child: Padding( 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( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -3061,7 +3118,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8), SizedBox(height: 8),
buildVisaValidUpTo(entry), buildVisaValidUpTo(entry),
IconButton( 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', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { 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 = apiData?['visa_type_of_visa'] ?? [];
// List<dynamic> purposeList = []; // List<dynamic> purposeList = [];
List<dynamic> purposeList = apiData?['visa_type_of_visa']; List<dynamic> purposeList = apiData?['visa_type_of_visa'];
@ -3402,8 +3573,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker( final pickedDate = await showDatePicker(
context: context, context: context,
initialDate: initialDate, // initialDate: initialDate,
firstDate: initialDate, // firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -3490,8 +3662,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker( final pickedDate = await showDatePicker(
context: context, context: context,
initialDate: initialDate, // initialDate: initialDate,
firstDate: initialDate, // firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );

View File

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

View File

@ -1,3 +1,3 @@
//api url //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'; // const String apiUrl = 'https://uat.tripapprovaltool.com';