user mangement bugs
This commit is contained in:
parent
7c9968c159
commit
b246c79789
@ -63,11 +63,13 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -239,8 +241,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
// print("Error fetching plan: $e");
|
||||
// }
|
||||
|
||||
bool confirmed =
|
||||
await apiService.showCancelConfirmationDialog(context, layoutColor);
|
||||
bool confirmed = await apiService.showCancelConfirmationDialog(
|
||||
context,
|
||||
layoutColor,
|
||||
);
|
||||
|
||||
if (confirmed) {
|
||||
try {
|
||||
@ -282,17 +286,23 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
}
|
||||
}
|
||||
|
||||
void viewPlanforApprover(String planId,
|
||||
{bool isViewMode = false, bool isApprover = true}) async {
|
||||
void viewPlanforApprover(
|
||||
String planId, {
|
||||
bool isViewMode = false,
|
||||
bool isApprover = true,
|
||||
}) async {
|
||||
try {
|
||||
Map<String, dynamic> planData = await getViewPlan(planId);
|
||||
|
||||
print("ViewAAA - $planData");
|
||||
context.go('/createPlan', extra: {
|
||||
context.go(
|
||||
'/createPlan',
|
||||
extra: {
|
||||
'planData': planData,
|
||||
'isViewMode': isViewMode,
|
||||
'isApprover': isApprover
|
||||
});
|
||||
'isApprover': isApprover,
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
print("Error fetching plan: $e");
|
||||
}
|
||||
@ -314,12 +324,15 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
print("allPlans before filtering: $allPlans");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredPlans = allPlans.where((plan) {
|
||||
filteredPlans =
|
||||
allPlans.where((plan) {
|
||||
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
|
||||
@ -330,8 +343,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -340,23 +355,27 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||
Expanded(child: buildGroupListLayout(isDesktop))
|
||||
Expanded(child: buildGroupListLayout(isDesktop)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildGroupListLayout(bool isDesktop) {
|
||||
@ -383,11 +402,14 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
// }
|
||||
// }
|
||||
|
||||
final adjHgt = MediaQuery.of(context).size.height;
|
||||
|
||||
String _formatDate(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd, MMM yyyy HH:mm')
|
||||
.format(dateTime); // 24-hour format
|
||||
return DateFormat(
|
||||
'dd, MMM yyyy HH:mm',
|
||||
).format(dateTime); // 24-hour format
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
@ -396,11 +418,13 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
return Container(
|
||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
decoration: BoxDecoration(
|
||||
border: isDesktop
|
||||
border:
|
||||
isDesktop
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Colors.white,
|
||||
@ -444,9 +468,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.23,
|
||||
),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.23),
|
||||
|
||||
if (isDesktop)
|
||||
Container(
|
||||
@ -457,8 +479,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -470,27 +494,26 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
|
||||
if (!isDesktop)
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
if (!isDesktop) SizedBox(height: 5),
|
||||
isDesktop
|
||||
? SizedBox.shrink()
|
||||
: Row(
|
||||
@ -505,7 +528,9 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -517,17 +542,19 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -548,7 +575,9 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: const [
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// Icon(Icons.error_outline,
|
||||
// color: Colors.redAccent, size: 60),
|
||||
// SizedBox(height: 1),
|
||||
@ -557,14 +586,18 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
// fontSize: 22,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Colors.redAccent)),
|
||||
SizedBox(height: 15),
|
||||
Text("No Trips Pending For Your Approvals",
|
||||
SizedBox(height: adjHgt / 4),
|
||||
Text(
|
||||
" No Trips Pending For Your Approvals",
|
||||
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontFamily: "Inter",
|
||||
// fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black54)),
|
||||
color: Colors.black54,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -580,10 +613,13 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
List<Plan> plans =
|
||||
searchController.text.isEmpty ? allPlans : filteredPlans;
|
||||
|
||||
plans.sort((a, b) =>
|
||||
int.parse(b.planId).compareTo(int.parse(a.planId)));
|
||||
plans.sort(
|
||||
(a, b) =>
|
||||
int.parse(b.planId).compareTo(int.parse(a.planId)),
|
||||
);
|
||||
|
||||
List<Plan> paginatedPlans = plans
|
||||
List<Plan> paginatedPlans =
|
||||
plans
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
@ -593,125 +629,178 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: minWidth,
|
||||
),
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
child: DataTable(
|
||||
dividerThickness: 0.5,
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
width: 0.5,
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Trip ID',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Trip Name',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Emp Code',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Traveller',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Trip Type',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Created On',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Status',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Actions',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: paginatedPlans.map((plan) {
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(plan.planId,
|
||||
rows:
|
||||
paginatedPlans.map((plan) {
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text(
|
||||
plan.planId,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Archivo",
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
DataCell(Text(plan.tripTitle,
|
||||
DataCell(
|
||||
Text(
|
||||
plan.tripTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
DataCell(Text(plan.employeeCode ?? " - ",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
plan.employeeCode ?? " - ",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(plan.tripType,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
plan.tripType,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
|
||||
DataCell(Text(
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
DataCell(
|
||||
Text(
|
||||
// plan.createdOn,
|
||||
_formatDate(plan.createdOn),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Container(
|
||||
width: double
|
||||
width:
|
||||
double
|
||||
.infinity, // Set your desired fixed size (equal width and height)
|
||||
height: 25,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: getStatusColor(
|
||||
plan.statusValue,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(
|
||||
8,
|
||||
),
|
||||
),
|
||||
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color:
|
||||
getStatusTextColor(plan.statusValue),
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue,
|
||||
),
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w400,
|
||||
@ -732,96 +821,143 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
color: Color(0xFF475569),
|
||||
size: 14,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
itemBuilder:
|
||||
(context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
padding:
|
||||
EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.remove_red_eye,
|
||||
color:
|
||||
Color(0xFF475569),
|
||||
size: 18),
|
||||
tooltip: 'View The Trip Details',
|
||||
Icons
|
||||
.remove_red_eye,
|
||||
color: Color(
|
||||
0xFF475569,
|
||||
),
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'View The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
context,
|
||||
); // Close popup manually
|
||||
viewPlanforApprover(
|
||||
plan.planId,
|
||||
isViewMode: true,
|
||||
isApprover: true);
|
||||
}),
|
||||
isViewMode:
|
||||
true,
|
||||
isApprover:
|
||||
true,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
tooltip: 'Edit The Trip Details',
|
||||
height: 15,
|
||||
),
|
||||
tooltip:
|
||||
'Edit The Trip Details',
|
||||
onPressed: () {
|
||||
print(
|
||||
"Approver Edit : ${plan.approverId}");
|
||||
"Approver Edit : ${plan.approverId}",
|
||||
);
|
||||
print(
|
||||
"Approver Edit2 : ${plan.delegaterId}");
|
||||
Navigator.pop(context);
|
||||
ApiService
|
||||
.viewPlanForApprover(
|
||||
"Approver Edit2 : ${plan.delegaterId}",
|
||||
);
|
||||
Navigator.pop(
|
||||
context,
|
||||
);
|
||||
ApiService.viewPlanForApprover(
|
||||
context,
|
||||
plan.planId,
|
||||
plan.approverId,
|
||||
plan.delegaterId,
|
||||
isViewMode: false,
|
||||
isApprover: true);
|
||||
isViewMode:
|
||||
false,
|
||||
isApprover:
|
||||
true,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.cancel_rounded,
|
||||
size: 18),
|
||||
tooltip: 'Cancellation The Trip Details',
|
||||
Icons
|
||||
.cancel_rounded,
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'Cancellation The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
Navigator.pop(
|
||||
context,
|
||||
);
|
||||
deletePlan(
|
||||
plan.planId,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
tooltip: 'Download The Trip Details',
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: Color(
|
||||
0xFF114D8B,
|
||||
),
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'Download The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
Navigator.pop(
|
||||
context,
|
||||
);
|
||||
apiService
|
||||
.getPdfDownload(
|
||||
plan.planId,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.comment,
|
||||
color: Color(0xFF475569),
|
||||
color: Color(
|
||||
0xFF475569,
|
||||
),
|
||||
size: 11,
|
||||
),
|
||||
tooltip: 'Approver Comment',
|
||||
tooltip:
|
||||
'Approver Comment',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
CommentModalList(
|
||||
context:
|
||||
context,
|
||||
builder:
|
||||
(
|
||||
context,
|
||||
) => CommentModalList(
|
||||
// planId: plan.planId,
|
||||
planId: plan
|
||||
.planId
|
||||
planId:
|
||||
plan.planId
|
||||
.toString(),
|
||||
layoutColorForUser:
|
||||
layoutColor!,
|
||||
role:
|
||||
"Approver"),
|
||||
"Approver",
|
||||
),
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -880,7 +1016,8 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
// apiService.getPdfDownload(plan.planId);
|
||||
// }),
|
||||
// ])),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
@ -894,8 +1031,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
final plan = paginatedPlans[index];
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -912,7 +1051,9 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
@ -921,7 +1062,8 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
plan.statusValue,
|
||||
style: TextStyle(
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue),
|
||||
plan.statusValue,
|
||||
),
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@ -936,92 +1078,119 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
color: Color(0xFF475569),
|
||||
size: 14,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
itemBuilder:
|
||||
(context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
horizontal: 8,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.remove_red_eye,
|
||||
color:
|
||||
Color(0xFF475569),
|
||||
size: 18),
|
||||
tooltip: 'View The Trip Details',
|
||||
color: Color(
|
||||
0xFF475569,
|
||||
),
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'View The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
context,
|
||||
); // Close popup manually
|
||||
viewPlanforApprover(
|
||||
plan.planId,
|
||||
isViewMode: true,
|
||||
isApprover: true);
|
||||
}),
|
||||
isApprover: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
tooltip: 'Edit The Trip Details',
|
||||
height: 15,
|
||||
),
|
||||
tooltip:
|
||||
'Edit The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService
|
||||
.viewPlanForApprover(
|
||||
ApiService.viewPlanForApprover(
|
||||
context,
|
||||
plan.planId,
|
||||
plan.approverId,
|
||||
plan.delegaterId,
|
||||
isViewMode: false,
|
||||
isApprover: true);
|
||||
isApprover: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.cancel_rounded,
|
||||
size: 18),
|
||||
tooltip: 'Cancellation The Trip Details',
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'Cancellation The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
tooltip: 'Download The Trip Details',
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: Color(
|
||||
0xFF114D8B,
|
||||
),
|
||||
size: 18,
|
||||
),
|
||||
tooltip:
|
||||
'Download The Trip Details',
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
apiService
|
||||
.getPdfDownload(
|
||||
plan.planId,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.comment,
|
||||
color: Color(0xFF475569),
|
||||
color: Color(
|
||||
0xFF475569,
|
||||
),
|
||||
size: 11,
|
||||
),
|
||||
tooltip: 'Trip Comments',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
CommentModalList(
|
||||
builder:
|
||||
(
|
||||
context,
|
||||
) => CommentModalList(
|
||||
// planId: plan.planId,
|
||||
planId: plan
|
||||
.planId
|
||||
planId:
|
||||
plan.planId
|
||||
.toString(),
|
||||
layoutColorForUser:
|
||||
layoutColor!,
|
||||
role:
|
||||
"Approver"),
|
||||
"Approver",
|
||||
),
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -1039,11 +1208,14 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(' ${plan.tripTitle}',
|
||||
Text(
|
||||
' ${plan.tripTitle}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.bold)),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -1058,24 +1230,28 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(' ${plan.tripType}',
|
||||
Text(
|
||||
' ${plan.tripType}',
|
||||
style: TextStyle(
|
||||
fontSize: 9,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('${_formatDate(plan.createdOn)}',
|
||||
Text(
|
||||
'${_formatDate(plan.createdOn)}',
|
||||
style: TextStyle(
|
||||
fontSize: 9,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -1095,7 +1271,8 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
style: TextStyle(
|
||||
fontSize: 9,
|
||||
fontFamily: "Inter",
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -1109,7 +1286,8 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
style: TextStyle(
|
||||
fontSize: 9,
|
||||
fontFamily: "Inter",
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -1130,14 +1308,17 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredPlans.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14, color: Colors.grey),
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
@ -1150,7 +1331,9 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
child: Text(
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14, color: Colors.grey),
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedPlans)),
|
||||
@ -1183,7 +1366,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -156,6 +156,8 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
_emailController.clear();
|
||||
_passwordController.clear();
|
||||
// Fluttertoast.showToast(
|
||||
// msg: "Login Failed: $errorMessage",
|
||||
// toastLength: Toast.LENGTH_LONG,
|
||||
|
||||
@ -67,11 +67,13 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -97,7 +99,6 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
}
|
||||
|
||||
Future<List<dynamic>> fetchGetCostCenter() async {
|
||||
|
||||
final String apiUrlData = '$apiUrl/api/getCostCenterMaster';
|
||||
|
||||
final String? token = await getToken();
|
||||
@ -143,26 +144,30 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
print("all before filtering: $query");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredCostCenter = allCostCenter.where((object) {
|
||||
filteredCostCenter =
|
||||
allCostCenter.where((object) {
|
||||
final isActiveStatus =
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['cost_center_id']?.toLowerCase().contains(lowerQuery) ??
|
||||
return (object['cost_center_id']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
false) ||
|
||||
(object['name']?.toLowerCase().contains(lowerQuery) ??
|
||||
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(object['description']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['description']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
}).toList();
|
||||
currentPage = 0;
|
||||
});
|
||||
print("filteredCostCenter: $filteredCostCenter");
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -171,11 +176,14 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
@ -188,7 +196,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildGroupList(bool isDesktop) {
|
||||
@ -216,7 +225,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
// ? EdgeInsets.all(10.0)
|
||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
|
||||
@ -238,7 +248,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'CostCenter Details',
|
||||
'Cost Center Details',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: isDesktop ? 16 : 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -248,9 +258,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.16,
|
||||
),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
if (isDesktop)
|
||||
Container(
|
||||
@ -262,7 +270,9 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -274,17 +284,19 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -298,16 +310,18 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side:
|
||||
BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 12),
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => CostCenterData(
|
||||
builder:
|
||||
(context) => CostCenterData(
|
||||
isDesktop: isDesktop,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetCostCenter: refreshData,
|
||||
@ -339,10 +353,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
],
|
||||
),
|
||||
|
||||
if (!isDesktop)
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
if (!isDesktop) SizedBox(height: 5),
|
||||
isDesktop
|
||||
? SizedBox.shrink()
|
||||
: Row(
|
||||
@ -357,7 +368,9 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -370,17 +383,18 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -418,14 +432,17 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Please Create CostCenter Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16, color: Colors.grey),
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
@ -435,19 +452,21 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
}
|
||||
/* Here collect the list to displayed the data in table or card Used */
|
||||
List<dynamic> object =
|
||||
filteredCostCenter.isNotEmpty ? filteredCostCenter : allCostCenter;
|
||||
filteredCostCenter.isNotEmpty
|
||||
? filteredCostCenter
|
||||
: allCostCenter;
|
||||
|
||||
/* List is Sorting here */
|
||||
object.sort((a, b) {
|
||||
DateTime dateA = DateTime.parse(a['created_on']);
|
||||
DateTime dateB = DateTime.parse(b['created_on']);
|
||||
|
||||
return dateB
|
||||
.compareTo(dateA); // Descending: newest first
|
||||
return dateB.compareTo(dateA); // Descending: newest first
|
||||
});
|
||||
|
||||
/* For pagination for list ... */
|
||||
List paginatedCostCenter = object
|
||||
List paginatedCostCenter =
|
||||
object
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
@ -455,8 +474,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
/* Table ... */
|
||||
Widget table = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
double minWidth =
|
||||
isDesktop ? constraints.maxWidth : 1300;
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
@ -465,7 +483,9 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
width: 0.5,
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(
|
||||
@ -473,48 +493,68 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
'Name',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Description',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Status',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Actions',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: paginatedCostCenter.map((tableObject) {
|
||||
String costcenterId = tableObject['cost_center_id']
|
||||
rows:
|
||||
paginatedCostCenter.map((tableObject) {
|
||||
String costcenterId =
|
||||
tableObject['cost_center_id']
|
||||
.toString(); // Get user ID
|
||||
bool isSelected = selectedCostCenterId == costcenterId;
|
||||
bool isSelected =
|
||||
selectedCostCenterId == costcenterId;
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(tableObject['name'] ?? '',
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text(
|
||||
tableObject['name'] ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(tableObject['description'] ?? 'N/A',
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
tableObject['description'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
tableObject['is_active'] == "1"
|
||||
@ -523,7 +563,10 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
color: tableObject['is_active'] == "1" ? Colors.green : Colors.red,
|
||||
color:
|
||||
tableObject['is_active'] == "1"
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -550,22 +593,31 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
//
|
||||
final costcenterId = int.tryParse(
|
||||
tableObject['cost_center_id']
|
||||
.toString());
|
||||
.toString(),
|
||||
);
|
||||
|
||||
if (costcenterId != null) {
|
||||
print("Table cell - costcenter Id -- $costcenterId");
|
||||
final data = await apiService.getCostCenterDetailsFind(costcenterId);
|
||||
print(
|
||||
"Table cell - costcenter Id -- $costcenterId",
|
||||
);
|
||||
final data = await apiService
|
||||
.getCostCenterDetailsFind(
|
||||
costcenterId,
|
||||
);
|
||||
print("CostCenterId -- $data");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => CostCenterData(
|
||||
builder:
|
||||
(context) => CostCenterData(
|
||||
isDesktop: isDesktop,
|
||||
costcenterId: costcenterId, // Pass the ID
|
||||
costcenterId:
|
||||
costcenterId, // Pass the ID
|
||||
costcenterData: data,
|
||||
layoutColor: layoutColor!,
|
||||
// fetchGetForex: fetchGetForex,
|
||||
fetchGetCostCenter: refreshData,
|
||||
fetchGetCostCenter:
|
||||
refreshData,
|
||||
// role:
|
||||
// "Travel Agent"
|
||||
),
|
||||
@ -576,7 +628,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
@ -592,7 +645,9 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -612,7 +667,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w700),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
|
||||
GestureDetector(
|
||||
@ -630,23 +686,31 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
//
|
||||
final costcenterId = int.tryParse(
|
||||
cardObject['cost_center_id']
|
||||
.toString());
|
||||
.toString(),
|
||||
);
|
||||
|
||||
if (costcenterId != null) {
|
||||
print("costcenterId -- $costcenterId");
|
||||
print(
|
||||
"costcenterId -- $costcenterId",
|
||||
);
|
||||
final data = await apiService
|
||||
.getCostCenterDetailsFind(costcenterId);
|
||||
.getCostCenterDetailsFind(
|
||||
costcenterId,
|
||||
);
|
||||
print("CostCenterId -- $data");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => CostCenterData(
|
||||
builder:
|
||||
(context) => CostCenterData(
|
||||
isDesktop: isDesktop,
|
||||
costcenterId:costcenterId, // Pass the ID
|
||||
costcenterData:data,
|
||||
layoutColor:layoutColor!,
|
||||
costcenterId:
|
||||
costcenterId, // Pass the ID
|
||||
costcenterData: data,
|
||||
layoutColor: layoutColor!,
|
||||
// fetchGetCostCenter: fetchGetCostCenter,
|
||||
fetchGetCostCenter: refreshData,
|
||||
fetchGetCostCenter:
|
||||
refreshData,
|
||||
// role:
|
||||
// "Travel Agent"
|
||||
),
|
||||
@ -745,13 +809,12 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
cardObject['description'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@ -760,7 +823,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
cardObject['description'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -776,13 +840,13 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredCostCenter.isEmpty
|
||||
? Center(
|
||||
@ -790,7 +854,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
@ -804,10 +869,13 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedCostCenter)),
|
||||
: buildMobileCardView(
|
||||
paginatedCostCenter,
|
||||
)),
|
||||
),
|
||||
// Expanded(
|
||||
// child: isDesktop
|
||||
@ -838,9 +906,11 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
]),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -67,11 +67,13 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -141,10 +143,13 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
print("all before filtering: $query");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredDepartment = allDepartment.where((object) {
|
||||
filteredDepartment =
|
||||
allDepartment.where((object) {
|
||||
final isActiveStatus =
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['department_id']?.toLowerCase().contains(lowerQuery) ??
|
||||
return (object['department_id']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
false) ||
|
||||
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(object['description']?.toLowerCase().contains(lowerQuery) ??
|
||||
@ -158,8 +163,10 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -168,11 +175,14 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
@ -185,7 +195,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildGroupList(bool isDesktop) {
|
||||
@ -213,7 +224,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
// ? EdgeInsets.all(10.0)
|
||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
|
||||
@ -245,9 +257,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.16,
|
||||
),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
if (isDesktop)
|
||||
Container(
|
||||
@ -259,7 +269,9 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -271,17 +283,19 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -295,16 +309,18 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side:
|
||||
BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 12),
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DepartmentData(
|
||||
builder:
|
||||
(context) => DepartmentData(
|
||||
isDesktop: isDesktop,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetDepartment: refreshData,
|
||||
@ -336,10 +352,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
],
|
||||
),
|
||||
|
||||
if (!isDesktop)
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
if (!isDesktop) SizedBox(height: 5),
|
||||
isDesktop
|
||||
? SizedBox.shrink()
|
||||
: Row(
|
||||
@ -354,7 +367,9 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -367,17 +382,18 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -415,14 +431,17 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Please Create Department Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16, color: Colors.grey),
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
@ -431,7 +450,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
);
|
||||
}
|
||||
/* Here collect the list to displayed the data in table or card Used */
|
||||
List<dynamic> object = filteredDepartment.isNotEmpty
|
||||
List<dynamic> object =
|
||||
filteredDepartment.isNotEmpty
|
||||
? filteredDepartment
|
||||
: allDepartment;
|
||||
|
||||
@ -440,12 +460,12 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
DateTime dateA = DateTime.parse(a['created_on']);
|
||||
DateTime dateB = DateTime.parse(b['created_on']);
|
||||
|
||||
return dateB
|
||||
.compareTo(dateA); // Descending: newest first
|
||||
return dateB.compareTo(dateA); // Descending: newest first
|
||||
});
|
||||
|
||||
/* For pagination for list ... */
|
||||
List paginatedDepartment = object
|
||||
List paginatedDepartment =
|
||||
object
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
@ -453,8 +473,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
/* Table ... */
|
||||
Widget table = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
double minWidth =
|
||||
isDesktop ? constraints.maxWidth : 1300;
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
@ -463,7 +482,9 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
width: 0.5,
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(
|
||||
@ -471,51 +492,68 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
'Name',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Description',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Status',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Actions',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: paginatedDepartment.map((tableObject) {
|
||||
rows:
|
||||
paginatedDepartment.map((tableObject) {
|
||||
String departmentId =
|
||||
tableObject['department_id']
|
||||
.toString(); // Get user ID
|
||||
bool isSelected =
|
||||
selectedDepartmentId == departmentId;
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(tableObject['name'] ?? '',
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text(
|
||||
tableObject['name'] ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(tableObject['description'] ?? 'N/A',
|
||||
Text(
|
||||
tableObject['description'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
tableObject['is_active'] == "1"
|
||||
@ -524,7 +562,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
color: tableObject['is_active'] == "1"
|
||||
color:
|
||||
tableObject['is_active'] == "1"
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
@ -539,37 +578,45 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
// apiService.getSingleUser(id),
|
||||
// ),
|
||||
GestureDetector(
|
||||
child: Tooltip(
|
||||
message: 'Edit Department Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
height: 15,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
// final userId = getUserId(user['user_id']);
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final departmentId = int.tryParse(
|
||||
tableObject['department_id']
|
||||
.toString());
|
||||
.toString(),
|
||||
);
|
||||
|
||||
if (departmentId != null) {
|
||||
print(
|
||||
"Table cell - department Id -- $departmentId");
|
||||
"Table cell - department Id -- $departmentId",
|
||||
);
|
||||
final data = await apiService
|
||||
.getDepartmentDetailsFind(
|
||||
departmentId);
|
||||
departmentId,
|
||||
);
|
||||
print("DepartmentId -- $data");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
DepartmentData(
|
||||
builder:
|
||||
(context) => DepartmentData(
|
||||
isDesktop: isDesktop,
|
||||
departmentId:
|
||||
departmentId, // Pass the ID
|
||||
departmentData: data,
|
||||
layoutColor: layoutColor!,
|
||||
// fetchGetForex: fetchGetForex,
|
||||
fetchGetDepartment: refreshData,
|
||||
fetchGetDepartment:
|
||||
refreshData,
|
||||
// role:
|
||||
// "Travel Agent"
|
||||
),
|
||||
@ -580,7 +627,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
@ -596,7 +644,9 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -616,7 +666,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w700),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
|
||||
GestureDetector(
|
||||
@ -634,20 +685,23 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
//
|
||||
final departmentId = int.tryParse(
|
||||
cardObject['department_id']
|
||||
.toString());
|
||||
.toString(),
|
||||
);
|
||||
|
||||
if (departmentId != null) {
|
||||
print(
|
||||
"departmentId -- $departmentId");
|
||||
"departmentId -- $departmentId",
|
||||
);
|
||||
final data = await apiService
|
||||
.getDepartmentDetailsFind(
|
||||
departmentId);
|
||||
departmentId,
|
||||
);
|
||||
print("DepartmentId -- $data");
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
DepartmentData(
|
||||
builder:
|
||||
(context) => DepartmentData(
|
||||
isDesktop: isDesktop,
|
||||
departmentId:
|
||||
departmentId, // Pass the ID
|
||||
@ -754,13 +808,12 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
cardObject['description'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@ -769,7 +822,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
cardObject['description'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -790,7 +844,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredDepartment.isEmpty
|
||||
? Center(
|
||||
@ -798,7 +853,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
@ -812,11 +868,13 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(
|
||||
paginatedDepartment)),
|
||||
paginatedDepartment,
|
||||
)),
|
||||
),
|
||||
// Expanded(
|
||||
// child: isDesktop
|
||||
@ -847,9 +905,11 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
]),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,11 +83,13 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -151,7 +153,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
|
||||
if (!data.containsKey('data') || data['data'] is! List) {
|
||||
throw Exception(
|
||||
"Invalid response format: 'data' field is missing or not a List");
|
||||
"Invalid response format: 'data' field is missing or not a List",
|
||||
);
|
||||
}
|
||||
|
||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||
@ -180,7 +183,10 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
}
|
||||
|
||||
Future<void> createUserData(
|
||||
Map<String, dynamic> userData, String userId, String newStatus) async {
|
||||
Map<String, dynamic> userData,
|
||||
String userId,
|
||||
String newStatus,
|
||||
) async {
|
||||
final uri = Uri.parse('$apiUrl/api/users/update/$userId');
|
||||
|
||||
final String? token = await getToken();
|
||||
@ -230,8 +236,11 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleToggleUserStatus(String userId, String currentStatus,
|
||||
Map<String, dynamic> userData) async {
|
||||
void handleToggleUserStatus(
|
||||
String userId,
|
||||
String currentStatus,
|
||||
Map<String, dynamic> userData,
|
||||
) async {
|
||||
print("Toggling user status - $userId (Current: $currentStatus)");
|
||||
|
||||
final String apiUrlData =
|
||||
@ -274,7 +283,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
// }
|
||||
}
|
||||
|
||||
// Refresh user list after update
|
||||
// Refresh user list after update
|
||||
void refreshUserList() {
|
||||
setState(() {
|
||||
futureForex = fetchGetForex(); // Re-fetch users after status update
|
||||
@ -282,48 +291,35 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
});
|
||||
}
|
||||
|
||||
void filterForex1(String query) {
|
||||
print("allUsers before filtering: $query");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredForex = allForex.where((forex) {
|
||||
return (forex['country_code']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(forex['country_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ??
|
||||
false);
|
||||
}).toList();
|
||||
currentPage = 0;
|
||||
});
|
||||
print("filteredPlans: $filteredForex");
|
||||
}
|
||||
|
||||
void filterForex(String query) {
|
||||
print("allForex before filtering: $query");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredForex = allForex.where((forex) {
|
||||
filteredForex =
|
||||
allForex.where((forex) {
|
||||
final isActiveStatus =
|
||||
forex['is_active'] == "1" ? "active" : "inactive";
|
||||
return (forex['country_code']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(forex['country_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(forex['currency']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
}).toList();
|
||||
currentPage = 0;
|
||||
});
|
||||
print("filteredForex: $filteredForex");
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -332,11 +328,14 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
@ -349,7 +348,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildGroupList(bool isDesktop) {
|
||||
@ -377,7 +377,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
// ? EdgeInsets.all(10.0)
|
||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
|
||||
@ -409,9 +410,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.16,
|
||||
),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
if (isDesktop)
|
||||
Container(
|
||||
@ -423,7 +422,9 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -435,17 +436,19 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -459,16 +462,18 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side:
|
||||
BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 12),
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ForexData(
|
||||
builder:
|
||||
(context) => ForexData(
|
||||
isDesktop: isDesktop,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetForex: refreshData,
|
||||
@ -499,10 +504,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
],
|
||||
),
|
||||
|
||||
if (!isDesktop)
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
if (!isDesktop) SizedBox(height: 5),
|
||||
isDesktop
|
||||
? SizedBox.shrink()
|
||||
: Row(
|
||||
@ -517,7 +519,9 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -530,17 +534,18 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -578,14 +583,17 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Please Create Perdiem Amount",
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16, color: Colors.grey),
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
@ -601,19 +609,18 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
DateTime dateA = DateTime.parse(a['created_on']);
|
||||
DateTime dateB = DateTime.parse(b['created_on']);
|
||||
|
||||
return dateB
|
||||
.compareTo(dateA); // Descending: newest first
|
||||
return dateB.compareTo(dateA); // Descending: newest first
|
||||
});
|
||||
|
||||
List paginatedForex = forex
|
||||
List paginatedForex =
|
||||
forex
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
|
||||
Widget table = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
double minWidth =
|
||||
isDesktop ? constraints.maxWidth : 1300;
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
@ -622,7 +629,9 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
width: 0.5,
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(
|
||||
@ -630,76 +639,105 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
'Country Code',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Country',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Currency',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Perdiem Amount',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Status',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Actions',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: paginatedForex.map((forex) {
|
||||
String forexId = forex['forex_perdiem_id']
|
||||
rows:
|
||||
paginatedForex.map((forex) {
|
||||
String forexId =
|
||||
forex['forex_perdiem_id']
|
||||
.toString(); // Get user ID
|
||||
bool isSelected = selectedUserId == forexId;
|
||||
|
||||
return DataRow(cells: [
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text("${forex['country_code'] ?? ''}",
|
||||
Text(
|
||||
"${forex['country_code'] ?? ''}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(forex['country_name'] ?? '',
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
forex['country_name'] ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(forex['currency'] ?? 'N/A',
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
forex['currency'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(forex['perdiem_amount'] ?? 'N/A',
|
||||
Text(
|
||||
forex['perdiem_amount'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
forex['is_active'] == "1"
|
||||
@ -737,7 +775,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
//
|
||||
final forexId = int.tryParse(
|
||||
forex['forex_perdiem_id']
|
||||
.toString());
|
||||
.toString(),
|
||||
);
|
||||
|
||||
if (forexId != null) {
|
||||
print("ForexId -- $forexId");
|
||||
@ -747,9 +786,11 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ForexData(
|
||||
builder:
|
||||
(context) => ForexData(
|
||||
isDesktop: isDesktop,
|
||||
forexId: forexId, // Pass the ID
|
||||
forexId:
|
||||
forexId, // Pass the ID
|
||||
forexData: data,
|
||||
layoutColor: layoutColor!,
|
||||
// fetchGetForex: fetchGetForex,
|
||||
@ -764,7 +805,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
@ -779,7 +821,9 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -799,7 +843,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w700),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
|
||||
GestureDetector(
|
||||
@ -816,8 +861,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final forexId = int.tryParse(
|
||||
forex['forex_perdiem_id']
|
||||
.toString());
|
||||
forex['forex_perdiem_id'].toString(),
|
||||
);
|
||||
|
||||
if (forexId != null) {
|
||||
print("ForexId -- $forexId");
|
||||
@ -827,7 +872,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ForexData(
|
||||
builder:
|
||||
(context) => ForexData(
|
||||
isDesktop: isDesktop,
|
||||
forexId:
|
||||
forexId, // Pass the ID
|
||||
@ -933,7 +979,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -952,13 +999,12 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
forex['currency'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@ -967,7 +1013,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
forex['perdiem_amount'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -988,7 +1035,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredForex.isEmpty
|
||||
? Center(
|
||||
@ -996,7 +1044,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
@ -1010,7 +1059,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedForex)),
|
||||
@ -1044,11 +1094,11 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
]),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@ import '../../utils/auth_utils.dart';
|
||||
import '../../utils/pagination.dart';
|
||||
import 'groupDetails.dart';
|
||||
|
||||
|
||||
|
||||
class GroupList extends StatefulWidget {
|
||||
@override
|
||||
_GroupListState createState() => _GroupListState();
|
||||
@ -39,7 +37,6 @@ class _GroupListState extends State<GroupList> {
|
||||
List filteredGroups = [];
|
||||
TextEditingController searchController = TextEditingController();
|
||||
|
||||
|
||||
int currentPage = 0;
|
||||
int itemsPerPage = 10;
|
||||
|
||||
@ -87,15 +84,11 @@ class _GroupListState extends State<GroupList> {
|
||||
return prefs.getString('auth_token');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Future<List<dynamic>> fetchGroups() async {
|
||||
final result = await apiService.fetchAllGroup();
|
||||
return result; // Returning raw JSON list
|
||||
}
|
||||
|
||||
|
||||
Future<void> loadAllGroups() async {
|
||||
try {
|
||||
final result = await apiService.fetchAllGroup();
|
||||
@ -117,13 +110,20 @@ class _GroupListState extends State<GroupList> {
|
||||
allGroups.where((group) {
|
||||
return (group['name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(group['domestic_policy_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false)
|
||||
(group['international_policy_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(group['domestic_policy_name']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
false)(
|
||||
group['international_policy_name']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
false,
|
||||
) ||
|
||||
(group['description']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(group['is_active']?.toLowerCase().contains(lowerQuery) ?? false);}).toList();
|
||||
(group['is_active']?.toLowerCase().contains(lowerQuery) ??
|
||||
false);
|
||||
}).toList();
|
||||
currentPage = 0;
|
||||
});
|
||||
|
||||
@ -159,7 +159,7 @@ class _GroupListState extends State<GroupList> {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
"is_active": newStatus // Set new status dynamically
|
||||
"is_active": newStatus, // Set new status dynamically
|
||||
}),
|
||||
);
|
||||
|
||||
@ -189,7 +189,6 @@ class _GroupListState extends State<GroupList> {
|
||||
loadAllGroups();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(
|
||||
@ -213,11 +212,7 @@ class _GroupListState extends State<GroupList> {
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: buildGroupList(isDesktop)),
|
||||
],
|
||||
),
|
||||
child: Row(children: [Expanded(child: buildGroupList(isDesktop))]),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -346,15 +341,14 @@ class _GroupListState extends State<GroupList> {
|
||||
// context.go('/CreateGroup');
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => GroupData(
|
||||
builder:
|
||||
(context) => GroupData(
|
||||
isDesktop: isDesktop,
|
||||
groupId: null,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetGroup: refreshData
|
||||
fetchGetGroup: refreshData,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
@ -556,7 +550,8 @@ class _GroupListState extends State<GroupList> {
|
||||
rows:
|
||||
paginatedGroup.map((group) {
|
||||
String groupId =
|
||||
group['group_id'].toString(); // Get group ID
|
||||
group['group_id']
|
||||
.toString(); // Get group ID
|
||||
bool isSelected = selectedGroupId == groupId;
|
||||
|
||||
return DataRow(
|
||||
@ -571,7 +566,8 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text("${group['domestic_policy_name'] ?? 'N/A'}",
|
||||
Text(
|
||||
"${group['domestic_policy_name'] ?? 'N/A'}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
@ -613,31 +609,39 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
DataCell(
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
if (group['group_id'] != null) {
|
||||
final newGroupID = int.tryParse(
|
||||
group['group_id'].toString());
|
||||
group['group_id'].toString(),
|
||||
);
|
||||
if (newGroupID != null) {
|
||||
final data = await apiService.getGroupDetailsFind(
|
||||
newGroupID); // ✅ Always an int
|
||||
final data = await apiService
|
||||
.getGroupDetailsFind(
|
||||
newGroupID,
|
||||
); // ✅ Always an int
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
GroupData(
|
||||
builder:
|
||||
(context) => GroupData(
|
||||
isDesktop: isDesktop,
|
||||
groupId: newGroupID,
|
||||
// Pass the ID
|
||||
groupData: data,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetGroup: refreshData
|
||||
layoutColor:
|
||||
layoutColor!,
|
||||
fetchGetGroup:
|
||||
refreshData,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
print("something went wrong check properly");
|
||||
print(
|
||||
"something went wrong check properly",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@ -646,16 +650,20 @@ class _GroupListState extends State<GroupList> {
|
||||
// },
|
||||
child: Tooltip(
|
||||
message: 'Edit Group Details',
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15), ),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final idStr = group['group_id'];
|
||||
final id = int.tryParse(idStr.toString());
|
||||
final id = int.tryParse(
|
||||
idStr.toString(),
|
||||
);
|
||||
|
||||
if (id == null) {
|
||||
print("group_id is null");
|
||||
@ -667,8 +675,12 @@ class _GroupListState extends State<GroupList> {
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Delete Group Details',
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -688,7 +700,10 @@ class _GroupListState extends State<GroupList> {
|
||||
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -700,7 +715,8 @@ class _GroupListState extends State<GroupList> {
|
||||
children: [
|
||||
// Row 1: Policy Name and Actions
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: RichText(
|
||||
@ -718,11 +734,12 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "${object['name'] ?? 'N/A'}",
|
||||
text:
|
||||
"${object['name'] ?? 'N/A'}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.normal
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -736,42 +753,54 @@ class _GroupListState extends State<GroupList> {
|
||||
onTap: () async {
|
||||
if (object['group_id'] != null) {
|
||||
final newGroupID = int.tryParse(
|
||||
object['group_id'].toString());
|
||||
object['group_id'].toString(),
|
||||
);
|
||||
if (newGroupID != null) {
|
||||
final data = await apiService.getGroupDetailsFind(
|
||||
newGroupID); // ✅ Always an int
|
||||
final data = await apiService
|
||||
.getGroupDetailsFind(
|
||||
newGroupID,
|
||||
); // ✅ Always an int
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
GroupData(
|
||||
builder:
|
||||
(context) => GroupData(
|
||||
isDesktop: isDesktop,
|
||||
groupId: newGroupID,
|
||||
// Pass the ID
|
||||
groupData: data,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetGroup: refreshData
|
||||
layoutColor:
|
||||
layoutColor!,
|
||||
fetchGetGroup:
|
||||
refreshData,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
print("something went wrong check properly");
|
||||
print(
|
||||
"something went wrong check properly",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// onTap: () {
|
||||
// context.go("/CreateGroup", extra: group);
|
||||
// },
|
||||
child: Tooltip( message: 'Edit Group Details',
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),),
|
||||
child: Tooltip(
|
||||
message: 'Edit Group Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final idStr = object['group_id'];
|
||||
final id = int.tryParse(idStr.toString());
|
||||
final id = int.tryParse(
|
||||
idStr.toString(),
|
||||
);
|
||||
|
||||
if (id == null) {
|
||||
print("group_id is null");
|
||||
@ -783,8 +812,12 @@ class _GroupListState extends State<GroupList> {
|
||||
},
|
||||
child: Tooltip(
|
||||
message: 'Edit Group Details',
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -792,7 +825,6 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
|
||||
SizedBox(height: 8), // Spacing
|
||||
|
||||
// Row 2:
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
@ -809,18 +841,19 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "${object['domestic_policy_name'] ?? 'N/A'}",
|
||||
text:
|
||||
"${object['domestic_policy_name'] ?? 'N/A'}",
|
||||
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.normal
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8), // Spacing
|
||||
|
||||
// Row 3:
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
@ -837,18 +870,18 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "${object['international_policy_name']}",
|
||||
text:
|
||||
"${object['international_policy_name'] ?? 'N/A'}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.normal
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8), // Spacing
|
||||
|
||||
// Row 4:
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
@ -865,11 +898,12 @@ class _GroupListState extends State<GroupList> {
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "${object['description'] ?? 'N/A'}",
|
||||
text:
|
||||
"${object['description'] ?? 'N/A'}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.normal
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -83,11 +83,13 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -150,7 +152,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
|
||||
if (!data.containsKey('data') || data['data'] is! List) {
|
||||
throw Exception(
|
||||
"Invalid response format: 'data' field is missing or not a List");
|
||||
"Invalid response format: 'data' field is missing or not a List",
|
||||
);
|
||||
}
|
||||
|
||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||
@ -174,8 +177,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Refresh user list after update
|
||||
// Refresh user list after update
|
||||
void refreshUserList() {
|
||||
setState(() {
|
||||
futureHotels = fetchGetHotels(); // Re-fetch users after status update
|
||||
@ -187,15 +189,19 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
print("allHotels before filtering: $query");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredHotels = allHotels.where((hotels) {
|
||||
filteredHotels =
|
||||
allHotels.where((hotels) {
|
||||
final isActiveStatus =
|
||||
hotels['is_active'] == "1" ? "active" : "inactive";
|
||||
return (hotels['country_code']?.toLowerCase().contains(lowerQuery) ??
|
||||
return (hotels['country_code']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
false) ||
|
||||
(hotels['country_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(hotels['city']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(hotels['hotel_chain']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(hotels['hotel_chain']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(hotels['hotel_name']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
@ -207,8 +213,10 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -217,11 +225,14 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
@ -234,7 +245,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildGroupList(bool isDesktop) {
|
||||
@ -262,7 +274,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
// ? EdgeInsets.all(10.0)
|
||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
|
||||
@ -294,9 +307,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.16,
|
||||
),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
if (isDesktop)
|
||||
Container(
|
||||
@ -308,7 +319,9 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -320,17 +333,19 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -344,16 +359,18 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side:
|
||||
BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 12),
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => HotelsData(
|
||||
builder:
|
||||
(context) => HotelsData(
|
||||
isDesktop: isDesktop,
|
||||
layoutColor: layoutColor!,
|
||||
fetchGetHotels: refreshData,
|
||||
@ -384,10 +401,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
],
|
||||
),
|
||||
|
||||
if (!isDesktop)
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
if (!isDesktop) SizedBox(height: 5),
|
||||
isDesktop
|
||||
? SizedBox.shrink()
|
||||
: Row(
|
||||
@ -402,7 +416,9 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9E9DBD),
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
@ -415,17 +431,18 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200,
|
||||
width: 0.5),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
color: Colors.grey.shade300,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 16),
|
||||
@ -463,14 +480,17 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Please Create Hotels",
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16, color: Colors.grey),
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
@ -486,19 +506,18 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
DateTime dateA = DateTime.parse(a['created_on']);
|
||||
DateTime dateB = DateTime.parse(b['created_on']);
|
||||
|
||||
return dateB
|
||||
.compareTo(dateA); // Descending: newest first
|
||||
return dateB.compareTo(dateA); // Descending: newest first
|
||||
});
|
||||
|
||||
List paginatedHotels = hotels
|
||||
List paginatedHotels =
|
||||
hotels
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
|
||||
Widget table = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
double minWidth =
|
||||
isDesktop ? constraints.maxWidth : 1300;
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
@ -507,7 +526,9 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
width: 0.5,
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(
|
||||
@ -515,74 +536,105 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
'Hotel Name',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Hotel Chain',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'City',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Country',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Status',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Actions',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600),
|
||||
)),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: paginatedHotels.map((hotels) {
|
||||
String hotelsId = hotels['hotel_id']
|
||||
rows:
|
||||
paginatedHotels.map((hotels) {
|
||||
String hotelsId =
|
||||
hotels['hotel_id']
|
||||
.toString(); // Get user ID
|
||||
bool isSelected = selectedUserId == hotelsId;
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(hotels['hotel_name'] ?? 'N/A',
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text(
|
||||
hotels['hotel_name'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
DataCell(Text(hotels['hotel_chain'] ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
hotels['hotel_chain'] ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(hotels['city'] ?? 'N/A',
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
hotels['city'] ?? 'N/A',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
DataCell(Text(hotels['country_name'] ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
hotels['country_name'] ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
hotels['is_active'] == "1"
|
||||
@ -591,7 +643,10 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
color: hotels['is_active'] == "1" ? Colors.green : Colors.red,
|
||||
color:
|
||||
hotels['is_active'] == "1"
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -605,9 +660,9 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
// ),
|
||||
GestureDetector(
|
||||
child: Tooltip(
|
||||
message: 'Delete Hotel Details',
|
||||
message: 'Edit Hotel Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15,
|
||||
),
|
||||
@ -617,8 +672,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final hotelsId = int.tryParse(
|
||||
hotels['hotel_id']
|
||||
.toString());
|
||||
hotels['hotel_id'].toString(),
|
||||
);
|
||||
|
||||
if (hotelsId != null) {
|
||||
print("HotelsId -- $hotelsId");
|
||||
@ -628,9 +683,11 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => HotelsData(
|
||||
builder:
|
||||
(context) => HotelsData(
|
||||
isDesktop: isDesktop,
|
||||
hotelsId: hotelsId, // Pass the ID
|
||||
hotelsId:
|
||||
hotelsId, // Pass the ID
|
||||
hotelsData: data,
|
||||
layoutColor: layoutColor!,
|
||||
// fetchGetHotels: fetchGetHotels,
|
||||
@ -645,7 +702,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
@ -660,7 +718,9 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
@ -680,21 +740,26 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w700),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
|
||||
GestureDetector(
|
||||
child: Tooltip(
|
||||
message: 'Edit Hotel Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
height: 15,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
// final userId = getUserId(user['user_id']);
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final hotelsId = int.tryParse(
|
||||
hotels['hotel_id']
|
||||
.toString());
|
||||
hotels['hotel_id'].toString(),
|
||||
);
|
||||
|
||||
if (hotelsId != null) {
|
||||
print("HotelsId -- $hotelsId");
|
||||
@ -704,7 +769,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => HotelsData(
|
||||
builder:
|
||||
(context) => HotelsData(
|
||||
isDesktop: isDesktop,
|
||||
hotelsId:
|
||||
hotelsId, // Pass the ID
|
||||
@ -737,7 +803,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -755,7 +822,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -772,7 +840,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
hotels['country_name'] ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87),
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -792,7 +861,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredHotels.isEmpty
|
||||
? Center(
|
||||
@ -800,7 +870,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
@ -814,7 +885,8 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
"No matches found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey),
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedHotels)),
|
||||
@ -848,9 +920,11 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
]),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,12 +14,13 @@ class TaxiScreen extends StatefulWidget {
|
||||
final Map<String, dynamic>? selectedItem;
|
||||
final String? loginUser;
|
||||
|
||||
TaxiScreen(
|
||||
{required this.onClose,
|
||||
TaxiScreen({
|
||||
required this.onClose,
|
||||
this.apiData,
|
||||
required this.onSavetaxi,
|
||||
required this.selectedItem,
|
||||
required this.loginUser});
|
||||
required this.loginUser,
|
||||
});
|
||||
|
||||
@override
|
||||
_TaxiScreenState createState() => _TaxiScreenState();
|
||||
@ -97,13 +98,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
super.initState();
|
||||
|
||||
_addFocusListener(
|
||||
_destinationFocusNode, (focus) => _destinationFocus = focus);
|
||||
_destinationFocusNode,
|
||||
(focus) => _destinationFocus = focus,
|
||||
);
|
||||
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
|
||||
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
|
||||
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
|
||||
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
|
||||
_addFocusListener(
|
||||
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus);
|
||||
_numPassengerFocusNode,
|
||||
(focus) => _numPassengerFocus = focus,
|
||||
);
|
||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||
|
||||
_destinationController = initController("destination_city");
|
||||
@ -168,7 +173,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
"location_of_pickup",
|
||||
"no_of_passengers",
|
||||
"date",
|
||||
"time"
|
||||
"time",
|
||||
];
|
||||
|
||||
// Check validation for each field
|
||||
@ -199,9 +204,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isMobile = sizingInfo.isMobile;
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Container(
|
||||
// color: Color(0xFFF4F4FB),
|
||||
@ -216,13 +223,14 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
child: Center(
|
||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||
@ -235,7 +243,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
|
||||
List<List<Widget>> rowBuilders = [
|
||||
// _builClassType(isDesktop),
|
||||
_buildSecondRow(isDesktop)
|
||||
_buildSecondRow(isDesktop),
|
||||
];
|
||||
|
||||
return [
|
||||
@ -253,19 +261,24 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
List<Widget> _buildFirstRow(isDesktop) {
|
||||
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
|
||||
|
||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
List<DropdownMenuItem<String>> dropdownItems =
|
||||
purposeList
|
||||
.map(
|
||||
(item) => DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(item['dropdown_value']),
|
||||
))
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (dropdownItems.isEmpty) {
|
||||
dropdownItems.add(
|
||||
DropdownMenuItem<String>(
|
||||
value: null,
|
||||
child: Text("No options available",
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
child: Text(
|
||||
"No options available",
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -283,20 +296,16 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
isDesktop
|
||||
? Row(children: _buildTripType(isDesktop))
|
||||
: Column(children: _buildTripType(isDesktop))
|
||||
: Column(children: _buildTripType(isDesktop)),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -305,7 +314,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -319,8 +329,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: const TextStyle(fontSize: 12),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(
|
||||
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp(r'^\d*\.?\d*$'),
|
||||
), // Allow only positive numbers with optional decimal
|
||||
],
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Number of Passenger",
|
||||
@ -334,19 +345,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
if (errorMessages["no_of_passengers"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -355,7 +358,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -369,16 +373,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
), // Proper padding
|
||||
),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
onChanged:
|
||||
purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedCarType = newValue;
|
||||
});
|
||||
print(
|
||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
|
||||
);
|
||||
}
|
||||
: null,
|
||||
|
||||
@ -388,31 +395,31 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox.shrink()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) SizedBox.shrink() else SizedBox(height: 8),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildTripType(bool isDesktop) {
|
||||
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
|
||||
|
||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
List<DropdownMenuItem<String>> dropdownItems =
|
||||
purposeList
|
||||
.map(
|
||||
(item) => DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(item['dropdown_value']),
|
||||
))
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (dropdownItems.isEmpty) {
|
||||
dropdownItems.add(
|
||||
DropdownMenuItem<String>(
|
||||
value: null,
|
||||
child: Text("No options available",
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
child: Text(
|
||||
"No options available",
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -425,7 +432,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _taxiReqFocused,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
@ -436,16 +444,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
), // Proper padding
|
||||
),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
onChanged:
|
||||
purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedReqTaxi = newValue;
|
||||
});
|
||||
print(
|
||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
|
||||
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
|
||||
);
|
||||
}
|
||||
: null,
|
||||
|
||||
@ -466,7 +477,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
|
||||
DateTime? pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: _selectedCheckOutDate != null &&
|
||||
initialDate:
|
||||
_selectedCheckOutDate != null &&
|
||||
_selectedCheckOutDate!.isAfter(today)
|
||||
? _selectedCheckOutDate!
|
||||
: today,
|
||||
@ -494,8 +506,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
// Formatting time to HH:mm (24-hour format)
|
||||
final now = DateTime.now();
|
||||
final formattedTime = DateFormat('HH:mm').format(
|
||||
DateTime(now.year, now.month, now.day, pickedTime.hour,
|
||||
pickedTime.minute),
|
||||
DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
),
|
||||
);
|
||||
_timeController.text = formattedTime;
|
||||
});
|
||||
@ -511,7 +528,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -535,28 +553,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
if (errorMessages["destination_city"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Location of Pickup",
|
||||
"Pickup Location",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -569,7 +580,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
controller: _locationController,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Location of Pickup",
|
||||
labelText: "Pickup Location",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
@ -580,19 +591,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
if (errorMessages["location_of_pickup"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -601,7 +604,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -622,8 +626,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon: Icon(Icons.calendar_today,
|
||||
size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -632,19 +639,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
if (errorMessages["date"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -653,7 +652,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -674,8 +674,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon:
|
||||
Icon(Icons.access_time, size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.access_time,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -684,10 +687,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
if (errorMessages["time"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
@ -704,13 +704,15 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
|
||||
@ -733,9 +735,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
],
|
||||
),
|
||||
if (isDesktop) Spacer(),
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
@ -756,9 +756,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.grey[400], // Light grey color
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
@ -767,7 +765,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10), // Space between buttons
|
||||
|
||||
// Save Changes Button
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
@ -775,9 +772,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@ -85,7 +85,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
return AlertDialog(
|
||||
title: const Text('Select Trip Type'),
|
||||
content: const Text(
|
||||
'Please select a trip type before adding a flight.'),
|
||||
'Please select a trip type before adding a flight.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
@ -118,11 +119,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
MouseRegion(
|
||||
cursor: widget.isViewMode
|
||||
cursor:
|
||||
widget.isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: widget.isViewMode
|
||||
onTap:
|
||||
widget.isViewMode
|
||||
? null
|
||||
: () {
|
||||
checkClass();
|
||||
@ -141,7 +144,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
Icons.add_circle_sharp,
|
||||
size: 30,
|
||||
color: Color(0xFF114D8B),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -149,9 +152,9 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
// Scroll behavior based on device
|
||||
_buildData(context, isDesktop),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -224,8 +227,11 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
|
||||
if (hour == 24 && minute == 0) {
|
||||
// 24:00 is treated as 00:00 on the next day
|
||||
dateTime = DateTime(now.year, now.month, now.day)
|
||||
.add(const Duration(days: 1));
|
||||
dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
).add(const Duration(days: 1));
|
||||
} else {
|
||||
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
||||
throw FormatException("Invalid hour or minute");
|
||||
@ -245,7 +251,21 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
String? tripTypeName = '';
|
||||
switch (item["trip_type"]?.toString()) {
|
||||
case "Roundtrip":
|
||||
tripTypeName = "Round Trip";
|
||||
break;
|
||||
case "Multitrip":
|
||||
tripTypeName = "Multi-Trip";
|
||||
break;
|
||||
case "Oneway":
|
||||
tripTypeName = "One-Way";
|
||||
break;
|
||||
default:
|
||||
tripTypeName = item["trip_type"]?.toString();
|
||||
break;
|
||||
}
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
@ -281,7 +301,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
item["trip_type"]?.toString() ?? "N/A",
|
||||
tripTypeName ?? "N/A",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
@ -313,9 +333,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
Divider(color: Colors.blueGrey.shade50),
|
||||
SizedBox(height: 4),
|
||||
if (isDesktop)
|
||||
Row(
|
||||
@ -324,39 +342,35 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Class",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Text(
|
||||
"Sector",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Date",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Time",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
// Trip Rows
|
||||
|
||||
// Trip Rows
|
||||
if (isDesktop)
|
||||
if (item["trips"] != null && item["trips"].isNotEmpty)
|
||||
...item["trips"].map<Widget>((trip) {
|
||||
@ -385,7 +399,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Text(
|
||||
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
||||
"$fromPlaceCountry (From) - (To) $toPlaceCountry",
|
||||
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
@ -437,13 +451,20 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
_buildKeyValueRow(
|
||||
"Class",
|
||||
getRequestForClass(trip["class"].toString()) ??
|
||||
"N/A"),
|
||||
_buildKeyValueRow("Sector",
|
||||
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}"),
|
||||
"N/A",
|
||||
),
|
||||
_buildKeyValueRow(
|
||||
"Date", formatDate(trip["date"] ?? "")),
|
||||
"Sector",
|
||||
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}",
|
||||
),
|
||||
_buildKeyValueRow(
|
||||
"Time", formatTime(trip["time"] ?? "")),
|
||||
"Date",
|
||||
formatDate(trip["date"] ?? ""),
|
||||
),
|
||||
_buildKeyValueRow(
|
||||
"Time",
|
||||
formatTime(trip["time"] ?? ""),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -474,12 +495,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
child: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -131,7 +131,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
"delegationEndDate",
|
||||
// "dateOfIssue",
|
||||
// "dateOfExpiry",
|
||||
"changePassword"
|
||||
"changePassword",
|
||||
];
|
||||
|
||||
Color? layoutColor;
|
||||
@ -286,7 +286,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
if (apiselectedUser?["delegated_to_user_id"] != null) {
|
||||
print(
|
||||
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}");
|
||||
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}",
|
||||
);
|
||||
selectedSubstituteApprover =
|
||||
apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
|
||||
|
||||
@ -303,11 +304,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
List<dynamic> decodedList = jsonDecode(fixedJson);
|
||||
|
||||
selectedServiceIds = decodedList.map<Map<String, dynamic>>((item) {
|
||||
selectedServiceIds =
|
||||
decodedList.map<Map<String, dynamic>>((item) {
|
||||
final map = Map<String, dynamic>.from(item);
|
||||
return {
|
||||
"service_id": map['service_id'].toString(),
|
||||
};
|
||||
return {"service_id": map['service_id'].toString()};
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
print("❌ Error decoding fixed agent_supported_service_ids: $e");
|
||||
@ -380,7 +380,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
// userIdsApi = userMap.keys.toList();
|
||||
|
||||
// Handle selectedUser as a Map (not a List)
|
||||
apiselectedUser = extraData['selectedUser']
|
||||
apiselectedUser =
|
||||
extraData['selectedUser']
|
||||
as Map<String, dynamic>?; // Cast it as a Map
|
||||
isViewMode = extraData['isViewMode'] ?? false;
|
||||
isEditProfile = extraData['isEditProfile'] ?? false;
|
||||
@ -443,7 +444,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
userMap = {
|
||||
for (var user in userList)
|
||||
user['user_id'].toString():
|
||||
"${user['first_name']} ${user['last_name']}"
|
||||
"${user['first_name']} ${user['last_name']}",
|
||||
};
|
||||
userIdsApi = userMap.keys.toList();
|
||||
});
|
||||
@ -481,11 +482,13 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
layoutColor =
|
||||
layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
bodyColor =
|
||||
bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
@ -538,6 +541,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleGoBack() async {
|
||||
print("hello, please Go Back");
|
||||
printFormData();
|
||||
}
|
||||
|
||||
void handleNext() async {
|
||||
print("USR Detail Next");
|
||||
printFormData();
|
||||
@ -552,14 +560,6 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
print("USERDETAILS : $data");
|
||||
|
||||
if (!isValidData(data)) {
|
||||
print("USERDETAILS : $userDetials");
|
||||
print("Validation Failed: Required fields are missing.");
|
||||
setState(() {});
|
||||
return; // Stop execution if validation fails
|
||||
} else {
|
||||
print("USERDETAILS : $userDetials");
|
||||
|
||||
final tabs = {
|
||||
"personal": "Personal Details",
|
||||
"office": "Office Details",
|
||||
@ -570,17 +570,57 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
|
||||
|
||||
print("currentIndex - $currentIndex");
|
||||
|
||||
bool isValid = false;
|
||||
|
||||
final currentTab = tabKeys[currentIndex];
|
||||
if (currentTab == "personal") {
|
||||
isValid = isValidData(userDetials);
|
||||
} else if (currentTab == "office") {
|
||||
isValid = isValidDataTwo(userDetials);
|
||||
} else {
|
||||
isValid = true; // Travel tab might not need validation at this point
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
print("Validation Failed on $currentTab: $userDetials");
|
||||
setState(() {}); // To trigger UI update showing errors
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentIndex < tabKeys.length - 1) {
|
||||
// Move to next tab
|
||||
setState(() {
|
||||
selectedTab = tabKeys[currentIndex + 1];
|
||||
});
|
||||
} else {
|
||||
// Already at last tab (travel), maybe submit form or show done message
|
||||
// Final step — submit or show done
|
||||
print("All tabs completed!");
|
||||
// You can trigger full form submit here
|
||||
}
|
||||
// Submit the full form here
|
||||
}
|
||||
|
||||
// if (!isValidData(data))
|
||||
// {
|
||||
// print("USERDETAILS : $userDetials");
|
||||
// print("Validation Failed: Required fields are missing.");
|
||||
// setState(() {});
|
||||
// return; // Stop execution if validation fails
|
||||
// } else
|
||||
// {
|
||||
// print("USERDETAILS : $userDetials");
|
||||
//
|
||||
// if (currentIndex < tabKeys.length - 1) {
|
||||
// // Move to next tab
|
||||
// setState(() {
|
||||
// selectedTab = tabKeys[currentIndex + 1];
|
||||
// });
|
||||
// } else {
|
||||
// // Already at last tab (travel), maybe submit form or show done message
|
||||
// print("All tabs completed!");
|
||||
// // You can trigger full form submit here
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void handleSubmit() async {
|
||||
@ -601,7 +641,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
// Map<String, dynamic> data = userDetials;
|
||||
|
||||
if (!isValidData(data)) {
|
||||
if (!isValidData(data) && isValidDataTwo(data)) {
|
||||
print("USERDETAILS : $userDetials");
|
||||
print("Validation Failed: Required fields are missing.");
|
||||
setState(() {});
|
||||
@ -623,7 +663,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
"last_name",
|
||||
"email",
|
||||
"mobile_no",
|
||||
// "employeeCode"
|
||||
// "employeeCode",
|
||||
];
|
||||
|
||||
if (apiselectedUser == null) {
|
||||
@ -647,8 +687,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
if (data["alternate_mobile_no"] != null &&
|
||||
data["alternate_mobile_no"].toString().isNotEmpty) {
|
||||
if (!RegExp(r"^\d{10}$")
|
||||
.hasMatch(data["alternate_mobile_no"].toString())) {
|
||||
if (!RegExp(
|
||||
r"^\d{10}$",
|
||||
).hasMatch(data["alternate_mobile_no"].toString())) {
|
||||
errorMessages["alternate_mobile_no"] =
|
||||
"Enter 10 digits"; // Invalid mobile number format
|
||||
}
|
||||
@ -656,14 +697,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
// Email validation
|
||||
if (data["email"] != null && data["email"].toString().isNotEmpty) {
|
||||
if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
|
||||
.hasMatch(data["email"].toString())) {
|
||||
if (!RegExp(
|
||||
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
|
||||
).hasMatch(data["email"].toString())) {
|
||||
errorMessages["email"] = "Invalid email format"; // Invalid email format
|
||||
}
|
||||
}
|
||||
return errorMessages.isEmpty; // Valid if there are no errors
|
||||
}
|
||||
|
||||
bool isValidDataTwo(Map<String, dynamic> data) {
|
||||
errorMessages.clear(); // Reset errors
|
||||
|
||||
// Required fields that must not be empty
|
||||
List<String> requiredFields = ["employee_code"];
|
||||
|
||||
// Check validation for each field
|
||||
for (String field in requiredFields) {
|
||||
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
||||
errorMessages[field] = "Required";
|
||||
}
|
||||
}
|
||||
|
||||
return errorMessages.isEmpty; // Valid if there are no errors
|
||||
}
|
||||
|
||||
void _clearError(String field) {
|
||||
if (mounted && errorMessages.containsKey(field)) {
|
||||
setState(() {
|
||||
@ -814,8 +872,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
print("enteredPassword - $enteredPassword ");
|
||||
|
||||
if (hashedPassword != null && hashedPassword.isNotEmpty) {
|
||||
bool isMatch =
|
||||
BCrypt.checkpw(enteredPassword, hashedPassword); // Compare passwords
|
||||
bool isMatch = BCrypt.checkpw(
|
||||
enteredPassword,
|
||||
hashedPassword,
|
||||
); // Compare passwords
|
||||
|
||||
setState(() {
|
||||
// ✅ Ensure UI updates
|
||||
@ -825,8 +885,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
print(" Password match!");
|
||||
} else {
|
||||
print(" Password NOT match!");
|
||||
errorMessages
|
||||
.remove("password"); // Clear error if password is different
|
||||
errorMessages.remove(
|
||||
"password",
|
||||
); // Clear error if password is different
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -836,8 +897,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
@ -846,22 +909,24 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
padding:
|
||||
isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
horizontal:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
vertical:
|
||||
MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: buildData(isDesktop, context)),
|
||||
],
|
||||
children: [Expanded(child: buildData(isDesktop, context))],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildData(bool isDesktop, context) {
|
||||
@ -875,7 +940,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: isDesktop
|
||||
height:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
child: Padding(
|
||||
@ -888,24 +954,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: isDesktop
|
||||
child:
|
||||
isDesktop
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: (selectedTab == "travel" ||
|
||||
children:
|
||||
(selectedTab == "travel" ||
|
||||
selectedRole == "5" ||
|
||||
setSelectesUserType == true)
|
||||
? _buildSubmit(isDesktop, layoutColor!)
|
||||
: _buildNext(isDesktop, layoutColor!),
|
||||
: _buildNext(
|
||||
isDesktop,
|
||||
layoutColor!,
|
||||
), // _buildGoBack(isDesktop, layoutColor!),
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: (selectedTab == "travel" ||
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children:
|
||||
(selectedTab == "travel" ||
|
||||
selectedRole == "5" ||
|
||||
setSelectesUserType == true)
|
||||
? _buildSubmit(isDesktop, layoutColor!)
|
||||
: _buildNext(isDesktop, layoutColor!),
|
||||
)),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -944,9 +1017,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
// })
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 18,
|
||||
),
|
||||
SizedBox(height: 18),
|
||||
isDesktop
|
||||
? buildTabsForUser()
|
||||
: SingleChildScrollView(
|
||||
@ -955,14 +1026,13 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
),
|
||||
Container(
|
||||
// color: Colors.yellow.shade50,
|
||||
|
||||
height: MediaQuery.of(context).size.height * 0.64,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: buildTabContents(isDesktop, isViewMode)),
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -977,7 +1047,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
personalDetailsKey: personalDetailsKey,
|
||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||
isViewMode: isViewMode,
|
||||
userIdApi:userIdApi,
|
||||
userIdApi: userIdApi,
|
||||
controllers: controllers,
|
||||
errorMessages: errorMessages,
|
||||
selectedGender: selectedGender,
|
||||
@ -1012,7 +1082,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
return OfficeDetails(
|
||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||
isViewMode: isViewMode,
|
||||
userIdApi:userIdApi,
|
||||
userIdApi: userIdApi,
|
||||
controllers: controllers,
|
||||
errorMessages: errorMessages,
|
||||
selectedLevel: selectedLevel,
|
||||
@ -1063,14 +1133,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
errorMessages: errorMessages,
|
||||
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
|
||||
passportFileUrlFromApi: passportFileUrlFromApi,
|
||||
userIdApi:userIdApi,
|
||||
userIdApi: userIdApi,
|
||||
);
|
||||
default:
|
||||
return PersonalDetails(
|
||||
personalDetailsKey: personalDetailsKey,
|
||||
isDesktop: isDesktop, // pass isDesktop as a named argument
|
||||
isViewMode: isViewMode,
|
||||
userIdApi:userIdApi,
|
||||
userIdApi: userIdApi,
|
||||
controllers: controllers,
|
||||
errorMessages: errorMessages,
|
||||
selectedGender: selectedGender,
|
||||
@ -1101,9 +1171,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
Map<String, String> getTabs(bool setSelectesUserType) {
|
||||
if (setSelectesUserType || selectedRole == "5") {
|
||||
return {
|
||||
"personal": "Personal Details",
|
||||
};
|
||||
return {"personal": "Personal Details"};
|
||||
} else {
|
||||
return allTabs;
|
||||
}
|
||||
@ -1113,16 +1181,37 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end, // important
|
||||
children: tabs.entries.map((entry) {
|
||||
children:
|
||||
tabs.entries.map((entry) {
|
||||
final isSelected = selectedTab == entry.key;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
bool isValid = false;
|
||||
|
||||
final currentTab = selectedTab;
|
||||
if (currentTab == "personal") {
|
||||
isValid = isValidData(userDetials);
|
||||
|
||||
if (isValid) {
|
||||
selectedTab = entry.key;
|
||||
}
|
||||
} else if (currentTab == "office") {
|
||||
isValid = isValidDataTwo(userDetials);
|
||||
if (isValid) {
|
||||
selectedTab = entry.key;
|
||||
}
|
||||
} else {
|
||||
isValid =
|
||||
true; // Travel tab might not need validation at this point
|
||||
selectedTab = entry.key;
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 24.0), // space between tabs
|
||||
padding: const EdgeInsets.only(
|
||||
right: 24.0,
|
||||
), // space between tabs
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -1131,7 +1220,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||
color:
|
||||
isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@ -1149,12 +1239,42 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Submit ---------------------------------------
|
||||
// ---- Submit ---------------------------------------
|
||||
|
||||
List<Widget> _buildGoBack(isDesktop, Color layoutColor) {
|
||||
return [
|
||||
MouseRegion(
|
||||
cursor:
|
||||
isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isViewMode ? layoutColor : layoutColor, // Keep original color
|
||||
foregroundColor:
|
||||
isViewMode ? Colors.white : Colors.white, // Keep original color
|
||||
disabledBackgroundColor:
|
||||
layoutColor, // Ensure color remains when disabled
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: layoutColor, width: 2),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: handleGoBack,
|
||||
child: Text("Back"),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildNext(isDesktop, Color layoutColor) {
|
||||
return [
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
cursor:
|
||||
isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
@ -1177,7 +1297,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
// isViewMode ? null : handleNext, // Disable when in view mode
|
||||
child: Text("Next"),
|
||||
),
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -1196,20 +1316,21 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
onPressed: () {
|
||||
isEditProfile ? context.go('/listPlan') : context.go('/listUser');
|
||||
},
|
||||
child: Text("Cancel")),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
if (!isViewMode)
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
cursor:
|
||||
isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isViewMode ? layoutColor : layoutColor, // Keep original color
|
||||
foregroundColor: isViewMode
|
||||
foregroundColor:
|
||||
isViewMode
|
||||
? Colors.white
|
||||
: Colors.white, // Keep original color
|
||||
disabledBackgroundColor:
|
||||
@ -1225,7 +1346,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
isViewMode ? null : handleSubmit, // Disable when in view mode
|
||||
child: Text("Submit"),
|
||||
),
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,6 @@ class OfficeDetails extends StatefulWidget {
|
||||
final bool isViewMode;
|
||||
final String? userIdApi;
|
||||
|
||||
|
||||
final ValueChanged<String?>? onLevelChanged;
|
||||
final ValueChanged<String?>? onDepartmentChanged;
|
||||
final ValueChanged<String?>? onFirstApproverChanged;
|
||||
@ -157,17 +156,25 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
fetchFindGroup();
|
||||
}
|
||||
|
||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
||||
Future<void> apiCheckDuplicate(
|
||||
String label,
|
||||
String field,
|
||||
String value,
|
||||
String? userId,
|
||||
) async {
|
||||
try {
|
||||
// Basic validation: Check mobile number length
|
||||
|
||||
if (field == "employeeCode") {
|
||||
field = "employee_code";
|
||||
}
|
||||
|
||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
||||
final response = await apiService.CheckDuplicate(
|
||||
label,
|
||||
field,
|
||||
value,
|
||||
userId,
|
||||
);
|
||||
if (response.isNotEmpty) {
|
||||
_clearError(field);
|
||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
||||
widget.errorMessages[field] =
|
||||
response['message'] ?? "$label Already Exists";
|
||||
print("Duplicate found: ${response['message']}");
|
||||
return;
|
||||
} else {
|
||||
@ -290,7 +297,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
SizedBox(height: 20),
|
||||
_buildFirstRow(widget.isDesktop),
|
||||
if (widget.isDesktop) SizedBox(height: 10),
|
||||
_buildSecondRow(widget.isDesktop),
|
||||
@ -407,7 +414,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Employee Code",
|
||||
"Employee Code *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -425,8 +432,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
controller: widget.controllers["employeeCode"],
|
||||
enabled: !widget.isViewMode,
|
||||
onChanged: (value) {
|
||||
_clearError("employeeCode");
|
||||
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi);
|
||||
_clearError("employee_code");
|
||||
apiCheckDuplicate(
|
||||
"Employee Code",
|
||||
"employee_code",
|
||||
value,
|
||||
widget.userIdApi,
|
||||
);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "Employee Code",
|
||||
@ -441,10 +453,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.errorMessages["employeeCode"] != null) ...[
|
||||
if (widget.errorMessages["employee_code"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
widget.errorMessages["employeeCode"]!,
|
||||
widget.errorMessages["employee_code"]!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
],
|
||||
@ -452,7 +464,71 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
);
|
||||
}
|
||||
|
||||
// Widget buildDepartmentFieldOld() {
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Department",
|
||||
// style: GoogleFonts.poppins(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF575A74),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 5),
|
||||
// CustomTextFieldUserWrapper(
|
||||
// isFocused: false, // Dropdown doesn't use focus
|
||||
// isDesktop: widget.isDesktop,
|
||||
// child: SizedBox(
|
||||
// height: 45, // Set appropriate height
|
||||
// child: DropdownButtonFormField<String>(
|
||||
// value: selectedDepartment,
|
||||
// // value: widget.isViewMode ? null : selectedDepartment,
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// decoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
// contentPadding: EdgeInsets.symmetric(
|
||||
// horizontal: 10,
|
||||
// ), // Proper padding
|
||||
// ),
|
||||
// onChanged:
|
||||
// widget.isViewMode
|
||||
// ? null
|
||||
// : (newValue) {
|
||||
// setState(() {
|
||||
// selectedDepartment = newValue;
|
||||
// });
|
||||
// widget.onDepartmentChanged?.call(newValue);
|
||||
// },
|
||||
//
|
||||
// items:
|
||||
// apiCostData?.map<DropdownMenuItem<String>>((item) {
|
||||
// return DropdownMenuItem(
|
||||
//
|
||||
// value: item['department_id'], // ID as value
|
||||
// child: Text(item['name'] ?? "Unknown"),
|
||||
// );
|
||||
// }).toList(),
|
||||
// hint: Text("Select"),
|
||||
// disabledHint: Text(
|
||||
// selectedDepartment ?? "Select Department",
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget buildDepartmentField() {
|
||||
// Map department_id to department_name
|
||||
Map<String, String> departmentMap = {
|
||||
for (var item in apiCostData ?? [])
|
||||
item['department_id'] as String: item['name'] as String,
|
||||
};
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -466,41 +542,74 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false, // Dropdown doesn't use focus
|
||||
isFocused: false,
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 45, // Set appropriate height
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: selectedDepartment,
|
||||
// value: widget.isViewMode ? null : selectedDepartment,
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
height: 40,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: departmentMap[selectedDepartment],
|
||||
enabled: !widget.isViewMode,
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose,
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
), // Proper padding
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search Department...",
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: departmentMap.values.toList(),
|
||||
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select Department",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged:
|
||||
widget.isViewMode
|
||||
? null
|
||||
: (newValue) {
|
||||
: (String? newValue) {
|
||||
if (newValue == null) return;
|
||||
|
||||
final departmentId =
|
||||
departmentMap.entries
|
||||
.firstWhere((entry) => entry.value == newValue)
|
||||
.key;
|
||||
|
||||
setState(() {
|
||||
selectedDepartment = newValue;
|
||||
selectedDepartment = departmentId;
|
||||
});
|
||||
widget.onDepartmentChanged?.call(newValue);
|
||||
|
||||
widget.onDepartmentChanged?.call(
|
||||
departmentId,
|
||||
); // Send department_id
|
||||
},
|
||||
items:
|
||||
apiCostData?.map<DropdownMenuItem<String>>((item) {
|
||||
return DropdownMenuItem(
|
||||
value: item['department_id'], // ID as value
|
||||
child: Text(item['name'] ?? "Unknown"),
|
||||
);
|
||||
}).toList(),
|
||||
hint: Text("Select"),
|
||||
disabledHint: Text(
|
||||
selectedDepartment ?? "Select Department",
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -585,6 +694,17 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
@ -686,6 +806,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
@ -806,6 +942,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
@ -925,6 +1077,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
@ -1047,6 +1215,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
|
||||
@ -157,7 +157,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
||||
Future<void> apiCheckDuplicate(
|
||||
String label,
|
||||
String field,
|
||||
String value,
|
||||
String? userId,
|
||||
) async {
|
||||
try {
|
||||
// Basic validation: Check mobile number length
|
||||
if (field == "mobile_no" && value.length != 10) {
|
||||
@ -167,10 +172,16 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
return; // Skip the API call if input is invalid
|
||||
}
|
||||
|
||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
||||
final response = await apiService.CheckDuplicate(
|
||||
label,
|
||||
field,
|
||||
value,
|
||||
userId,
|
||||
);
|
||||
if (response.isNotEmpty) {
|
||||
_clearError(field);
|
||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
||||
widget.errorMessages[field] =
|
||||
response['message'] ?? "$label Already Exists";
|
||||
print("Duplicate found: ${response['message']}");
|
||||
return;
|
||||
} else {
|
||||
@ -182,9 +193,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void _clearError(String field) {
|
||||
setState(() {
|
||||
widget.errorMessages.remove(field);
|
||||
@ -305,11 +313,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
SizedBox(height: 20),
|
||||
_buildFirstRow(widget.isDesktop),
|
||||
SizedBox(height: 10),
|
||||
_buildSecondRow(widget.isDesktop),
|
||||
// SizedBox(height: 10),
|
||||
SizedBox(height: 10),
|
||||
_buildThirdRow(widget.isDesktop),
|
||||
SizedBox(height: 10),
|
||||
_buildForthRow(widget.isDesktop),
|
||||
@ -731,7 +739,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"First Name",
|
||||
"First Name *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -781,7 +789,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Last Name",
|
||||
"Last Name*",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -822,7 +830,107 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
);
|
||||
}
|
||||
|
||||
// Widget buildGenderFieldOld() {
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Gender",
|
||||
// style: GoogleFonts.poppins(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF575A74),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 5),
|
||||
// CustomTextFieldUserWrapper(
|
||||
// width:
|
||||
// widget.isDesktop
|
||||
// ? MediaQuery.of(context).size.width * 0.12
|
||||
// : null,
|
||||
// isFocused: false,
|
||||
// isDesktop: widget.isDesktop,
|
||||
// child: SizedBox(
|
||||
// height: 40,
|
||||
// child: DropdownButtonFormField<String>(
|
||||
// // value: selectedGender,
|
||||
// value: widget.isViewMode ? null : selectedGender,
|
||||
// onChanged:
|
||||
// widget.isViewMode
|
||||
// ? null
|
||||
// : (String? newValue) {
|
||||
// setState(() {
|
||||
// selectedGender = newValue;
|
||||
// print("selectedGender - $selectedGender");
|
||||
// });
|
||||
//
|
||||
// widget.onGenderChanged?.call(newValue);
|
||||
// },
|
||||
// decoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
// enabled: !widget.isViewMode, // Disables input when in view mode
|
||||
// ),
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// items: [
|
||||
// DropdownMenuItem(value: "Male", child: Text("Male")),
|
||||
// DropdownMenuItem(value: "Female", child: Text("Female")),
|
||||
// ],
|
||||
// hint: Text(
|
||||
// selectedGender ?? "Select Gender",
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// ),
|
||||
// disabledHint: Text(
|
||||
// selectedGender ?? "Select Gender",
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// ),
|
||||
// ),
|
||||
//
|
||||
// // child: DropdownSearch<String>(
|
||||
// // selectedItem: selectedGender,
|
||||
// // // key: ValueKey(selectedGender),
|
||||
// // popupProps: PopupProps.menu(
|
||||
// // fit: FlexFit.loose, // Allows flexible height
|
||||
// // constraints: BoxConstraints(maxHeight: 250),
|
||||
// //
|
||||
// // ),
|
||||
// // items: ["Male", "Female", "Others"],
|
||||
// // dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
// // dropdownSearchDecoration: InputDecoration(
|
||||
// // border: InputBorder.none,
|
||||
// // contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
||||
// // ),
|
||||
// // ),
|
||||
// // dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
||||
// // alignment: Alignment.centerLeft,
|
||||
// // child: Text(
|
||||
// // selectedItem ?? "Select",
|
||||
// // style: TextStyle(fontSize: 12),
|
||||
// // ),
|
||||
// // ),
|
||||
// // onChanged: isViewMode
|
||||
// // ? null
|
||||
// // : (String? newValue) {
|
||||
// // setState(() {
|
||||
// // // Find the country_code based on selected country_name
|
||||
// // selectedGender = newValue;
|
||||
// // print("selectedGender - $selectedGender");
|
||||
// // // if (selectedCountry!.isNotEmpty) {
|
||||
// // // errorMessages.remove("country_code");
|
||||
// // // }
|
||||
// // });
|
||||
// // },
|
||||
// //
|
||||
// //
|
||||
// // ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget buildGenderField() {
|
||||
List<String> genderOptions = ["Male", "Female"];
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -844,9 +952,45 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownButtonFormField<String>(
|
||||
// value: selectedGender,
|
||||
value: widget.isViewMode ? null : selectedGender,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: selectedGender,
|
||||
enabled: !widget.isViewMode,
|
||||
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: false, // Set true if you want search
|
||||
fit: FlexFit.loose,
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: genderOptions,
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select Gender",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged:
|
||||
widget.isViewMode
|
||||
? null
|
||||
@ -855,65 +999,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
selectedGender = newValue;
|
||||
print("selectedGender - $selectedGender");
|
||||
});
|
||||
|
||||
widget.onGenderChanged?.call(newValue);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
enabled: !widget.isViewMode, // Disables input when in view mode
|
||||
),
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
items: [
|
||||
DropdownMenuItem(value: "Male", child: Text("Male")),
|
||||
DropdownMenuItem(value: "Female", child: Text("Female")),
|
||||
],
|
||||
hint: Text(
|
||||
selectedGender ?? "Select Gender",
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
),
|
||||
disabledHint: Text(
|
||||
selectedGender ?? "Select Gender",
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
),
|
||||
),
|
||||
|
||||
// child: DropdownSearch<String>(
|
||||
// selectedItem: selectedGender,
|
||||
// // key: ValueKey(selectedGender),
|
||||
// popupProps: PopupProps.menu(
|
||||
// fit: FlexFit.loose, // Allows flexible height
|
||||
// constraints: BoxConstraints(maxHeight: 250),
|
||||
//
|
||||
// ),
|
||||
// items: ["Male", "Female", "Others"],
|
||||
// dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
// dropdownSearchDecoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 1,),
|
||||
// ),
|
||||
// ),
|
||||
// dropdownBuilder: (context, selectedItem) => Align( // Center-align selected item
|
||||
// alignment: Alignment.centerLeft,
|
||||
// child: Text(
|
||||
// selectedItem ?? "Select",
|
||||
// style: TextStyle(fontSize: 12),
|
||||
// ),
|
||||
// ),
|
||||
// onChanged: isViewMode
|
||||
// ? null
|
||||
// : (String? newValue) {
|
||||
// setState(() {
|
||||
// // Find the country_code based on selected country_name
|
||||
// selectedGender = newValue;
|
||||
// print("selectedGender - $selectedGender");
|
||||
// // if (selectedCountry!.isNotEmpty) {
|
||||
// // errorMessages.remove("country_code");
|
||||
// // }
|
||||
// });
|
||||
// },
|
||||
//
|
||||
//
|
||||
// ),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -1014,7 +1102,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Email",
|
||||
"Email *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -1032,7 +1120,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
controller: widget.controllers["email"],
|
||||
onChanged: (value) {
|
||||
_clearError("email");
|
||||
apiCheckDuplicate("Email", "email",value,widget.userIdApi);
|
||||
apiCheckDuplicate("Email", "email", value, widget.userIdApi);
|
||||
},
|
||||
enabled: !widget.isViewMode,
|
||||
decoration: InputDecoration(
|
||||
@ -1064,7 +1152,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Mobile Number",
|
||||
"Mobile Number *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -1083,7 +1171,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
enabled: !widget.isViewMode,
|
||||
onChanged: (value) {
|
||||
_clearError("mobile_no");
|
||||
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi);
|
||||
apiCheckDuplicate(
|
||||
"Mobile Number",
|
||||
"mobile_no",
|
||||
value,
|
||||
widget.userIdApi,
|
||||
);
|
||||
},
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [
|
||||
@ -1208,6 +1301,18 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true, // Enables search functionality
|
||||
fit: FlexFit.loose, // Allows flexible height
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
@ -1323,12 +1428,79 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
);
|
||||
}
|
||||
|
||||
// Widget buildRoleOld() {
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Role ",
|
||||
// style: GoogleFonts.poppins(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF575A74),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 5),
|
||||
// CustomTextFieldUserWrapper(
|
||||
// isFocused: false, // Dropdown doesn't use focus
|
||||
// isDesktop: widget.isDesktop,
|
||||
// child: SizedBox(
|
||||
// height: 45, // Set appropriate height
|
||||
// child: DropdownButtonFormField<String>(
|
||||
// // value: widget.isViewMode ? null : selectedRole,
|
||||
// value: selectedRole,
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// decoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
// contentPadding: EdgeInsets.symmetric(
|
||||
// horizontal: 10,
|
||||
// ), // Proper padding
|
||||
// ),
|
||||
// onChanged:
|
||||
// widget.isViewMode
|
||||
// ? null
|
||||
// : (newValue) {
|
||||
// setState(() {
|
||||
// selectedRole = newValue;
|
||||
// isTravelAgent = selectedRole == "5";
|
||||
// // Pass the result back to parent
|
||||
// widget.onUserTypeChanged?.call(isTravelAgent);
|
||||
// });
|
||||
// widget.onRoleChanged?.call(newValue);
|
||||
// },
|
||||
// items:
|
||||
// apiRoleData?.map<DropdownMenuItem<String>>((item) {
|
||||
// return DropdownMenuItem(
|
||||
// value: item['dropdown_key'], // ID as value
|
||||
// child: Text(item['dropdown_value'] ?? "Select Role"),
|
||||
// );
|
||||
// }).toList(),
|
||||
// hint: Text("Select Role"),
|
||||
// disabledHint: Text(
|
||||
// selectedRole ?? "Select Role",
|
||||
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget buildRole() {
|
||||
// Map dropdown_key (ID) -> dropdown_value (Name)
|
||||
Map<String, String> roleMap = {
|
||||
for (var item in apiRoleData ?? [])
|
||||
item['dropdown_key'] as String: item['dropdown_value'] as String,
|
||||
};
|
||||
|
||||
List<String> roleNames = roleMap.values.toList();
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Role ",
|
||||
"Role",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -1337,44 +1509,73 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
isFocused: false, // Dropdown doesn't use focus
|
||||
isFocused: false,
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 45, // Set appropriate height
|
||||
child: DropdownButtonFormField<String>(
|
||||
// value: widget.isViewMode ? null : selectedRole,
|
||||
value: selectedRole,
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
height: 40,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: selectedRole != null ? roleMap[selectedRole] : null,
|
||||
enabled: !widget.isViewMode,
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose,
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
), // Proper padding
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search Role...",
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: roleNames,
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select Role",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged:
|
||||
widget.isViewMode
|
||||
? null
|
||||
: (newValue) {
|
||||
: (String? newValue) {
|
||||
if (newValue == null) return;
|
||||
final selectedKey =
|
||||
roleMap.entries
|
||||
.firstWhere((entry) => entry.value == newValue)
|
||||
.key;
|
||||
|
||||
setState(() {
|
||||
selectedRole = newValue;
|
||||
isTravelAgent = selectedRole == "5";
|
||||
// Pass the result back to parent
|
||||
widget.onUserTypeChanged?.call(isTravelAgent);
|
||||
selectedRole = selectedKey;
|
||||
isTravelAgent = selectedKey == "5";
|
||||
});
|
||||
widget.onRoleChanged?.call(newValue);
|
||||
|
||||
widget.onUserTypeChanged?.call(isTravelAgent);
|
||||
widget.onRoleChanged?.call(selectedKey);
|
||||
},
|
||||
items:
|
||||
apiRoleData?.map<DropdownMenuItem<String>>((item) {
|
||||
return DropdownMenuItem(
|
||||
value: item['dropdown_key'], // ID as value
|
||||
child: Text(item['dropdown_value'] ?? "Select Role"),
|
||||
);
|
||||
}).toList(),
|
||||
hint: Text("Select Role"),
|
||||
disabledHint: Text(
|
||||
selectedRole ?? "Select Role",
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1429,7 +1630,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Password",
|
||||
"Password *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -33,7 +33,6 @@ class TravellerDetails extends StatefulWidget {
|
||||
final String? passportFileUrlFromApi;
|
||||
final String? userIdApi;
|
||||
|
||||
|
||||
const TravellerDetails({
|
||||
Key? key,
|
||||
required this.controllers,
|
||||
@ -149,15 +148,24 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
|
||||
Future<void> apiCheckDuplicate(
|
||||
String label,
|
||||
String field,
|
||||
String value,
|
||||
String? userId,
|
||||
) async {
|
||||
var newField = "";
|
||||
try {
|
||||
if(field == "forex_card_num"){
|
||||
field = "forex_pre_paid_card_number";
|
||||
}
|
||||
final response = await apiService.CheckDuplicate(label, field, value, userId);
|
||||
final response = await apiService.CheckDuplicate(
|
||||
label,
|
||||
newField,
|
||||
value,
|
||||
userId,
|
||||
);
|
||||
if (response.isNotEmpty) {
|
||||
_clearError(field);
|
||||
widget.errorMessages[field] = response['message'] ?? "$label already exists";
|
||||
widget.errorMessages[field] =
|
||||
response['message'] ?? "$label already exists";
|
||||
print("Duplicate found: ${response['message']}");
|
||||
return;
|
||||
} else {
|
||||
@ -705,6 +713,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
@ -1107,7 +1116,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
controller: controllers["passportNumber"],
|
||||
enabled: !widget.isViewMode,
|
||||
onChanged: (value) {
|
||||
_clearError("last_name");
|
||||
_clearError("passport_number");
|
||||
apiCheckDuplicate(
|
||||
"Passport Number",
|
||||
"passport_number",
|
||||
value,
|
||||
widget.userIdApi,
|
||||
);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "Passport Number",
|
||||
@ -1122,6 +1137,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.errorMessages["passport_number"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
widget.errorMessages["passport_number"]!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -1181,7 +1203,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
_selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today)
|
||||
? _selectedDateOfIssue!
|
||||
: today,
|
||||
firstDate: today,
|
||||
// firstDate: today,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
@ -1271,7 +1294,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
_selectedDateOfExpiry!.isAfter(today)
|
||||
? _selectedDateOfExpiry!
|
||||
: today,
|
||||
firstDate: today,
|
||||
// firstDate: today,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
@ -2330,8 +2354,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
controller: controllers["forex_card_num"],
|
||||
enabled: !widget.isViewMode,
|
||||
onChanged: (value) {
|
||||
_clearError("forex_card_num");
|
||||
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi);
|
||||
_clearError("forex_pre_paid_card_number");
|
||||
apiCheckDuplicate(
|
||||
"Forex Pre-Paid Card Number",
|
||||
"forex_pre_paid_card_number",
|
||||
value,
|
||||
widget.userIdApi,
|
||||
);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: "Card Number",
|
||||
@ -2467,9 +2496,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
height: 60,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
||||
padding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 8,
|
||||
), // 👈 Add top padding here
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -2480,7 +2516,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
@ -2491,7 +2526,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
buildFrequentFlierInformation(entry),
|
||||
SizedBox(width: 15),
|
||||
IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -2782,9 +2821,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
height: 60,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
||||
padding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 8,
|
||||
), // 👈 Add top padding here
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -2804,7 +2850,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
SizedBox(height: 8),
|
||||
buildHotelMembershipNum(entry),
|
||||
IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -3035,9 +3085,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
height: 60,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
|
||||
padding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 8,
|
||||
), // 👈 Add top padding here
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -3061,7 +3118,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
SizedBox(height: 8),
|
||||
buildVisaValidUpTo(entry),
|
||||
IconButton(
|
||||
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
color: Colors.red,
|
||||
size: 15,
|
||||
),
|
||||
tooltip: 'Cancel the Details',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -3187,6 +3248,116 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
);
|
||||
}
|
||||
|
||||
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
|
||||
|
||||
// Map for id => name
|
||||
Map<String, String> visaTypeMap = {
|
||||
for (var item in purposeList)
|
||||
item['dropdown_key'].toString(): item['dropdown_value'].toString(),
|
||||
};
|
||||
|
||||
// Selected value from entry
|
||||
String? selectedPurpose = entry['visa_type_id']?.toString();
|
||||
|
||||
if (!visaTypeMap.containsKey(selectedPurpose)) {
|
||||
selectedPurpose = null;
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Visa Type",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserTravellerWrapper(
|
||||
width:
|
||||
widget.isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.17
|
||||
: null,
|
||||
isFocused: false,
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: visaTypeMap[selectedPurpose],
|
||||
enabled: purposeList.isNotEmpty,
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true,
|
||||
fit: FlexFit.loose,
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) => Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search Visa Type...",
|
||||
hintStyle: GoogleFonts.poppins(fontSize: 11.5),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: visaTypeMap.values.toList(),
|
||||
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select Visa Type",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
if (newValue == null) return;
|
||||
|
||||
final selectedId =
|
||||
visaTypeMap.entries
|
||||
.firstWhere((entry) => entry.value == newValue)
|
||||
.key;
|
||||
|
||||
setState(() {
|
||||
entry['visa_type_id'] = selectedId;
|
||||
});
|
||||
|
||||
print("Updating form data: visa_type_id -> $selectedId");
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildVisaType3(entry) {
|
||||
if (apiData == null || apiData?['visa_type_of_visa'] == null) {
|
||||
return Center(
|
||||
child: Transform.scale(scale: 0.5, child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
// List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? [];
|
||||
// List<dynamic> purposeList = [];
|
||||
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
|
||||
@ -3402,8 +3573,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: initialDate,
|
||||
// initialDate: initialDate,
|
||||
// firstDate: initialDate,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
@ -3490,8 +3662,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
||||
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: initialDate,
|
||||
// initialDate: initialDate,
|
||||
// firstDate: initialDate,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'dart:html' as html;
|
||||
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
||||
import 'package:frontend/services/apiService.dart';
|
||||
@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
||||
SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
||||
if (kIsWeb) {
|
||||
final uri = Uri.parse(html.window.location.href);
|
||||
if (uri.path == '/authredirection' &&
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
//api url
|
||||
const String apiUrl = 'http://apitest.tripapprovaltool.com';
|
||||
const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be';
|
||||
// const String apiUrl = 'https://uat.tripapprovaltool.com';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user