UI_USR_MNGMT_APPROVER

This commit is contained in:
venbaittech 2025-07-30 12:33:02 +05:30
parent d2b3b792d9
commit 1b6188c584
9 changed files with 4688 additions and 4052 deletions

View File

@ -52,7 +52,7 @@ class StatusDashboardState extends State<StatusDashboard> {
"Partially Approved",
"Approved",
"Rejected",
"Cancelled"
"Cancelled",
];
// Extract counts for "Both" section
@ -151,7 +151,6 @@ class StatusDashboardState extends State<StatusDashboard> {
});
setState(() {
isLoading = true;
});
// If token exists, load the dashboard data
loadDashboardData();
@ -320,25 +319,27 @@ class StatusDashboardState extends State<StatusDashboard> {
setState(() {
// currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount;
typeData = selectedView == "Today"
? typeBasedTodayCount
: typeBasedWeeklyCount ;
statusData = selectedView == "Today"
typeData =
selectedView == "Today" ? typeBasedTodayCount : typeBasedWeeklyCount;
statusData =
selectedView == "Today"
? statusBasedTodayCount
: statusBasedWeeklyCount;
flightData = selectedView == "Today"
flightData =
selectedView == "Today"
? getStatusValues(todayBasedCount['flight'] ?? {})
: getStatusValues(weekBasedCount['flight'] ?? {});
accommodationData = selectedView == "Today"
accommodationData =
selectedView == "Today"
? getStatusValues(todayBasedCount['acomodation'] ?? {})
: getStatusValues(weekBasedCount['acomodation'] ?? {});
forexData = selectedView == "Today"
forexData =
selectedView == "Today"
? getStatusValues(todayBasedCount['forex'] ?? {})
: getStatusValues(weekBasedCount['forex'] ?? {});
});
print("statusBasedCount - => $statusBasedCount");
print("Current Data - => $currentData");
// 👇 Local function to create the card widget
@ -403,6 +404,7 @@ class StatusDashboardState extends State<StatusDashboard> {
print("dashboard ..");
}
}
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
Widget toggleChip(String label) {
@ -501,7 +503,8 @@ class StatusDashboardState extends State<StatusDashboard> {
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // vertically center everything
mainAxisAlignment:
MainAxisAlignment.center, // vertically center everything
children: [
Text(
count.toString(),
@ -529,8 +532,40 @@ class StatusDashboardState extends State<StatusDashboard> {
);
}
Widget buildCategoryCard(String title, IconData icon, List<String> statusLabels,List<int> values) {
Widget statusCardContainer(bool isDesktop, List<Widget> cards) {
return isDesktop
? Row(
mainAxisAlignment: MainAxisAlignment.start,
children:
cards
.map(
(card) => Padding(
padding: const EdgeInsets.only(right: 12.0),
child: card,
),
)
.toList(),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children:
cards
.map(
(card) => Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: card,
),
)
.toList(),
);
}
Widget buildCategoryCard(
String title,
IconData icon,
List<String> statusLabels,
List<int> values,
) {
final statusIcons = [
Icons.calendar_today,
Icons.assignment,
@ -584,17 +619,16 @@ class StatusDashboardState extends State<StatusDashboard> {
color: Color(0xFF004A8E),
shape: BoxShape.circle,
),
child: Icon(
icon,
color: Colors.white,
size: 20,
),
child: Icon(icon, color: Colors.white, size: 20),
),
const SizedBox(width: 10),
Text(title, style: GoogleFonts.poppins(
Text(
title,
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.bold
),),
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
@ -612,7 +646,9 @@ class StatusDashboardState extends State<StatusDashboard> {
height: 28,
decoration: BoxDecoration(
color: statusColors[index], // background color
borderRadius: BorderRadius.circular(4), // square with slight rounding
borderRadius: BorderRadius.circular(
4,
), // square with slight rounding
),
alignment: Alignment.center,
child: Icon(
@ -622,16 +658,20 @@ class StatusDashboardState extends State<StatusDashboard> {
),
),
const SizedBox(width: 6),
Text(statusLabels[index], style: GoogleFonts.poppins(
color: Colors.black87,
),),
Text(
statusLabels[index],
style: GoogleFonts.poppins(color: Colors.black87),
),
],
),
Text(values[index].toString(), style: GoogleFonts.poppins(
Text(
values[index].toString(),
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.bold,
),),
),
),
],
),
);
@ -736,35 +776,41 @@ class StatusDashboardState extends State<StatusDashboard> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
padding:
isDesktop
? const EdgeInsets.symmetric(vertical: 5)
: EdgeInsets.zero,
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 1200,
),
constraints: BoxConstraints(maxWidth: 1200),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0), // Scroll content padding
padding: const EdgeInsets.symmetric(
horizontal: 15.0,
), // Scroll content padding
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isLoading ? Center(child: CircularProgressIndicator()) :
LayoutBuilder(
isLoading
? Center(child: CircularProgressIndicator())
: LayoutBuilder(
builder: (context, constraints) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// First Row: Toggle Buttons Row
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Container(
height: 36,
decoration: BoxDecoration(
color: const Color(0xFFEAEAEA),
borderRadius: BorderRadius.circular(20),
borderRadius:
BorderRadius.circular(20),
),
child: Row(
children: [
@ -780,15 +826,20 @@ class StatusDashboardState extends State<StatusDashboard> {
// Second Row: Domestic & International and Status
isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
borderRadius:
BorderRadius.circular(
12,
),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
@ -797,7 +848,9 @@ class StatusDashboardState extends State<StatusDashboard> {
),
],
),
padding: const EdgeInsets.all(15),
padding: const EdgeInsets.all(
15,
),
child: Row(
children: [
...typeData.map((item) {
@ -805,14 +858,28 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column(
children: [
buildTopCard(
color: item['value'] == "Domestic"
? Color(0xFF0DB04B)
: Color(0xFF004A8E),
label: item['value'],
count: item['count'],
bgColor: item['value'] == "Domestic"
? const Color(0xFFD6FBE4)
: const Color(0xFFD9E8FF),
color:
item['value'] ==
"Domestic"
? Color(
0xFF0DB04B,
)
: Color(
0xFF004A8E,
),
label:
item['value'],
count:
item['count'],
bgColor:
item['value'] ==
"Domestic"
? const Color(
0xFFD6FBE4,
)
: const Color(
0xFFD9E8FF,
),
),
],
),
@ -828,7 +895,10 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
borderRadius:
BorderRadius.circular(
12,
),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
@ -837,23 +907,46 @@ class StatusDashboardState extends State<StatusDashboard> {
),
],
),
padding: const EdgeInsets.all(15),
padding: const EdgeInsets.all(
15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
"Status",
style: GoogleFonts.poppins(
style:
GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
color:
Colors
.black87,
fontWeight:
FontWeight
.bold,
),
),
const SizedBox(height: 10),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment:
MainAxisAlignment
.spaceAround,
children: [
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(),
...statusData
.map(
(
item,
) => statusCard(
item['value'],
item['count'],
isDesktop,
),
)
.toList(),
],
),
],
@ -863,12 +956,14 @@ class StatusDashboardState extends State<StatusDashboard> {
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
borderRadius:
BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
@ -877,7 +972,9 @@ class StatusDashboardState extends State<StatusDashboard> {
),
],
),
padding: const EdgeInsets.all(15),
padding: const EdgeInsets.all(
15,
),
child: Row(
children: [
...typeData.map((item) {
@ -885,14 +982,28 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column(
children: [
buildTopCard(
color: item['value'] == "Domestic"
? const Color(0xFF0DB04B)
: const Color(0xFF004A8E),
label: item['value'],
count: item['count'],
bgColor: item['value'] == "Domestic"
? const Color(0xFFD6FBE4)
: const Color(0xFFD9E8FF),
color:
item['value'] ==
"Domestic"
? const Color(
0xFF0DB04B,
)
: const Color(
0xFF004A8E,
),
label:
item['value'],
count:
item['count'],
bgColor:
item['value'] ==
"Domestic"
? const Color(
0xFFD6FBE4,
)
: const Color(
0xFFD9E8FF,
),
),
],
),
@ -905,7 +1016,8 @@ class StatusDashboardState extends State<StatusDashboard> {
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
borderRadius:
BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
@ -914,16 +1026,22 @@ class StatusDashboardState extends State<StatusDashboard> {
),
],
),
padding: const EdgeInsets.all(15),
padding: const EdgeInsets.all(
15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Status",
style: GoogleFonts.poppins(
style:
GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
color:
Colors.black87,
fontWeight:
FontWeight.bold,
),
),
const SizedBox(height: 23),
@ -931,7 +1049,17 @@ class StatusDashboardState extends State<StatusDashboard> {
spacing: 10,
runSpacing: 10,
children: [
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(),
...statusData
.map(
(
item,
) => statusCard(
item['value'],
item['count'],
isDesktop,
),
)
.toList(),
],
),
],
@ -945,33 +1073,77 @@ class StatusDashboardState extends State<StatusDashboard> {
// Third Row: Flight, Accommodation, Forex
isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(child: buildCategoryCard("Flight", Icons.flight, statusLabels, flightData)),
Expanded(
child: buildCategoryCard(
"Flight",
Icons.flight,
statusLabels,
flightData,
),
),
const SizedBox(width: 10),
Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined, statusLabels, accommodationData)),
Expanded(
child: buildCategoryCard(
"Accomodation",
Icons.hotel_outlined,
statusLabels,
accommodationData,
),
),
const SizedBox(width: 10),
Expanded(child: buildCategoryCard("Forex", Icons.attach_money, statusLabels, forexData)),
Expanded(
child: buildCategoryCard(
"Forex",
Icons.attach_money,
statusLabels,
forexData,
),
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: buildCategoryCard("Flight", Icons.flight, statusLabels, flightData)),
Expanded(
child: buildCategoryCard(
"Flight",
Icons.flight,
statusLabels,
flightData,
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined, statusLabels, accommodationData)),
Expanded(
child: buildCategoryCard(
"Accomodation",
Icons.hotel_outlined,
statusLabels,
accommodationData,
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(child: buildCategoryCard("Forex", Icons.attach_money, statusLabels, forexData)),
Expanded(
child: buildCategoryCard(
"Forex",
Icons.attach_money,
statusLabels,
forexData,
),
),
],
),
const SizedBox(height: 20),

View File

@ -926,7 +926,8 @@ class FlightScreenState extends State<FlightScreen> {
alignment: Alignment.centerRight,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: !isDesktop
minimumSize:
!isDesktop
? const Size.fromHeight(48)
: null, // No min height on desktop // height
backgroundColor: Colors.green,
@ -1744,7 +1745,8 @@ class FlightScreenState extends State<FlightScreen> {
final parts = selectedItem.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
final airport =
parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
@ -1773,7 +1775,8 @@ class FlightScreenState extends State<FlightScreen> {
selectedFrom[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
if (selectedTripType == "Roundtrip") {
@ -1848,7 +1851,8 @@ class FlightScreenState extends State<FlightScreen> {
//
onTap: () {
// Request focus when user taps
focusNodes["_to${index}FocusNode"]?.requestFocus();
focusNodes["_to${index}FocusNode"]
?.requestFocus();
},
child: DropdownSearch<String>(
enabled:
@ -2005,7 +2009,8 @@ class FlightScreenState extends State<FlightScreen> {
final parts = selectedItem.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
final airport =
parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
@ -2021,7 +2026,8 @@ class FlightScreenState extends State<FlightScreen> {
selectedTo[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
@ -2159,9 +2165,12 @@ class FlightScreenState extends State<FlightScreen> {
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
final bool isNotAllowed = item['is_allowed'] == 'No';
final bool isNotAllowed =
item['is_allowed'] == 'No';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
@ -2187,7 +2196,8 @@ class FlightScreenState extends State<FlightScreen> {
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
(focusStates["_class${index}Focused"] ??
false)
? layoutColor!
: Colors.white,
width: 0.5,
@ -2196,7 +2206,8 @@ class FlightScreenState extends State<FlightScreen> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
(focusStates["_class${index}Focused"] ??
false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
@ -2205,7 +2216,10 @@ class FlightScreenState extends State<FlightScreen> {
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
@ -2328,7 +2342,8 @@ class FlightScreenState extends State<FlightScreen> {
isFocused: focusStates["_date${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
width:
isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
@ -2416,7 +2431,8 @@ class FlightScreenState extends State<FlightScreen> {
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_time${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
width:
isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
@ -2444,7 +2460,10 @@ class FlightScreenState extends State<FlightScreen> {
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Time",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
labelStyle: TextStyle(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
@ -2499,7 +2518,9 @@ class FlightScreenState extends State<FlightScreen> {
elevation: 1,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
color: const Color(0xFFF5F5F5), // Light grey
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
@ -2530,10 +2551,12 @@ class FlightScreenState extends State<FlightScreen> {
isCountryLoading
? Center(child: CircularProgressIndicator())
: Focus(
focusNode: focusNodes["_from${index}FocusNode"],
focusNode:
focusNodes["_from${index}FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_from${index}Focused"] = hasFocus;
focusStates["_from${index}Focused"] =
hasFocus;
});
},
child: GestureDetector(
@ -2561,13 +2584,16 @@ class FlightScreenState extends State<FlightScreen> {
// },
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 220),
constraints: BoxConstraints(
maxHeight: 220,
),
showSearchBox:
true, // Enables search functionality
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search...",
contentPadding: EdgeInsets.symmetric(
contentPadding:
EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
@ -2577,21 +2603,30 @@ class FlightScreenState extends State<FlightScreen> {
menuProps: MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
itemBuilder: (
context,
item,
isSelected,
) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport =
parts.length > 1 ? parts[1] : '';
parts.length > 1
? parts[1]
: '';
// Extract city and code from "City (CODE)"
final cityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(cityAndCode);
final city = cityMatch?.group(1) ?? '';
final code = cityMatch?.group(2) ?? '';
final city =
cityMatch?.group(1) ?? '';
final code =
cityMatch?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
padding:
const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 6.0,
),
@ -2601,20 +2636,23 @@ class FlightScreenState extends State<FlightScreen> {
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
MainAxisAlignment
.spaceBetween,
children: [
Text(
city,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
fontWeight:
FontWeight.bold,
),
),
Text(
code,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
fontWeight:
FontWeight.bold,
),
),
],
@ -2625,7 +2663,8 @@ class FlightScreenState extends State<FlightScreen> {
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
overflow: TextOverflow.ellipsis,
overflow:
TextOverflow.ellipsis,
),
),
],
@ -2668,7 +2707,8 @@ class FlightScreenState extends State<FlightScreen> {
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_from${index}Focused"] ??
@ -2696,13 +2736,17 @@ class FlightScreenState extends State<FlightScreen> {
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(
contentPadding:
EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
dropdownBuilder: (context, selectedItem) {
dropdownBuilder: (
context,
selectedItem,
) {
if (selectedItem == null) {
return Align(
alignment: Alignment.centerLeft,
@ -2713,15 +2757,20 @@ class FlightScreenState extends State<FlightScreen> {
);
}
final parts = selectedItem.split('\n');
final parts = selectedItem.split(
'\n',
);
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
final airport =
parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
child: Text(
cityAndCode ?? "Select",
style: const TextStyle(fontSize: 12),
style: const TextStyle(
fontSize: 12,
),
),
);
},
@ -2736,7 +2785,9 @@ class FlightScreenState extends State<FlightScreen> {
// ),
onChanged: (String? newValue) {
setState(() {
errorMessages.remove("from_place_$index");
errorMessages.remove(
"from_place_$index",
);
// selectedFrom[index] = countryMap.entries
// .firstWhere((entry) => entry.value == newValue)
// .key;
@ -2744,13 +2795,19 @@ class FlightScreenState extends State<FlightScreen> {
selectedFrom[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value ==
newValue,
)
.key;
if (selectedTripType == "Roundtrip") {
print('rounfTo${selectedFrom[index]}');
if (selectedTripType ==
"Roundtrip") {
print(
'rounfTo${selectedFrom[index]}',
);
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
selectedTo[2] = selectedFrom[index]!;
selectedTo[2] =
selectedFrom[index]!;
}
});
},
@ -2809,17 +2866,20 @@ class FlightScreenState extends State<FlightScreen> {
isCountryLoading
? Center(child: CircularProgressIndicator())
: Focus(
focusNode: focusNodes["_to${index}FocusNode"],
focusNode:
focusNodes["_to${index}FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_to${index}Focused"] = hasFocus;
focusStates["_to${index}Focused"] =
hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_to${index}FocusNode"]?.requestFocus();
focusNodes["_to${index}FocusNode"]
?.requestFocus();
},
child: DropdownSearch<String>(
enabled:
@ -2831,13 +2891,16 @@ class FlightScreenState extends State<FlightScreen> {
: null,
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 220),
constraints: BoxConstraints(
maxHeight: 220,
),
showSearchBox:
true, // Enables search functionality
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search...",
contentPadding: EdgeInsets.symmetric(
contentPadding:
EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
@ -2847,21 +2910,30 @@ class FlightScreenState extends State<FlightScreen> {
menuProps: MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
itemBuilder: (
context,
item,
isSelected,
) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport =
parts.length > 1 ? parts[1] : '';
parts.length > 1
? parts[1]
: '';
// Extract city and code from "City (CODE)"
final cityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(cityAndCode);
final city = cityMatch?.group(1) ?? '';
final code = cityMatch?.group(2) ?? '';
final city =
cityMatch?.group(1) ?? '';
final code =
cityMatch?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
padding:
const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 6.0,
),
@ -2871,20 +2943,23 @@ class FlightScreenState extends State<FlightScreen> {
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
MainAxisAlignment
.spaceBetween,
children: [
Text(
city,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
fontWeight:
FontWeight.bold,
),
),
Text(
code,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
fontWeight:
FontWeight.bold,
),
),
],
@ -2895,7 +2970,8 @@ class FlightScreenState extends State<FlightScreen> {
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
overflow: TextOverflow.ellipsis,
overflow:
TextOverflow.ellipsis,
),
),
],
@ -2920,7 +2996,8 @@ class FlightScreenState extends State<FlightScreen> {
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_to${index}Focused"] ??
@ -2948,7 +3025,8 @@ class FlightScreenState extends State<FlightScreen> {
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(
contentPadding:
EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
@ -2963,7 +3041,10 @@ class FlightScreenState extends State<FlightScreen> {
// style: TextStyle(fontSize: 12),
// ),
// ),
dropdownBuilder: (context, selectedItem) {
dropdownBuilder: (
context,
selectedItem,
) {
if (selectedItem == null) {
return Align(
alignment: Alignment.centerLeft,
@ -2974,34 +3055,47 @@ class FlightScreenState extends State<FlightScreen> {
);
}
final parts = selectedItem.split('\n');
final parts = selectedItem.split(
'\n',
);
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
final airport =
parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
child: Text(
cityAndCode ?? "Select",
style: const TextStyle(fontSize: 12),
style: const TextStyle(
fontSize: 12,
),
),
);
},
onChanged: (String? newValue) {
setState(() {
errorMessages.remove("to_place_$index");
errorMessages.remove(
"to_place_$index",
);
selectedTo[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value ==
newValue,
)
.key;
print(selectedTo[index]);
if (selectedTripType == "Roundtrip") {
print('rounfTo${selectedTo[index]}');
if (selectedTripType ==
"Roundtrip") {
print(
'rounfTo${selectedTo[index]}',
);
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
selectedFrom[2] = selectedTo[index]!;
selectedFrom[2] =
selectedTo[index]!;
}
});
},
@ -3052,7 +3146,8 @@ class FlightScreenState extends State<FlightScreen> {
//
onTap: () {
// Request focus when user taps
focusNodes["_class${index}FocusNode"]?.requestFocus();
focusNodes["_class${index}FocusNode"]
?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
@ -3073,13 +3168,17 @@ class FlightScreenState extends State<FlightScreen> {
orElse: () => {},
)
: null,
itemAsString: (item) => item['dropdown_value'] ?? '',
itemAsString:
(item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
final bool isNotAllowed = item['is_allowed'] == 'No';
final bool isNotAllowed =
item['is_allowed'] == 'No';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
@ -3105,7 +3204,8 @@ class FlightScreenState extends State<FlightScreen> {
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
(focusStates["_class${index}Focused"] ??
false)
? layoutColor!
: Colors.white,
width: 0.5,
@ -3114,7 +3214,8 @@ class FlightScreenState extends State<FlightScreen> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
(focusStates["_class${index}Focused"] ??
false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
@ -3123,7 +3224,10 @@ class FlightScreenState extends State<FlightScreen> {
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
@ -3132,7 +3236,8 @@ class FlightScreenState extends State<FlightScreen> {
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
if (selectedItem == null ||
selectedItem.isEmpty) {
return Text(
"Select Class",
style: GoogleFonts.poppins(
@ -3151,7 +3256,9 @@ class FlightScreenState extends State<FlightScreen> {
},
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) async {
? (
Map<String, dynamic>? newValue,
) async {
// if (newValue != null &&
// newValue['is_allowed'] == 'No') {
// print('not allowed');
@ -3174,7 +3281,8 @@ class FlightScreenState extends State<FlightScreen> {
if (newValue != null &&
newValue['is_allowed'] == 'No') {
final confirm = await showNotAllowedDialog(
final confirm =
await showNotAllowedDialog(
context,
message:
"You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
@ -3224,7 +3332,10 @@ class FlightScreenState extends State<FlightScreen> {
padding: const EdgeInsets.only(top: 4),
child: Text(
errorMessages["class_$index"]!,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.red),
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.red,
),
),
),
],
@ -3246,19 +3357,24 @@ class FlightScreenState extends State<FlightScreen> {
isFocused: focusStates["_date${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.11
: null,
child: SizedBox(
height: 40,
child: GestureDetector(
onTap: () {
focusNodes["_date${index}FocusNode"]?.requestFocus();
focusNodes["_date${index}FocusNode"]
?.requestFocus();
_selectCheckOutDate(context);
},
child: AbsorbPointer(
child: TextField(
focusNode: focusNodes["_date${index}FocusNode"],
// controller: _dateController,
controller: textControllers["_date${index}Controller"],
controller:
textControllers["_date${index}Controller"],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
@ -3267,9 +3383,12 @@ class FlightScreenState extends State<FlightScreen> {
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
floatingLabelBehavior:
FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
contentPadding: EdgeInsets.symmetric(
vertical: 16,
),
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(8),
// borderSide: BorderSide(
@ -3334,13 +3453,18 @@ class FlightScreenState extends State<FlightScreen> {
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_time${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.1
: null,
child: SizedBox(
height: 40,
child: GestureDetector(
onTap: () {
focusNodes["_time${index}FocusNode"]?.requestFocus();
textControllers["_time${index}Controller"]?.text = "";
focusNodes["_time${index}FocusNode"]
?.requestFocus();
textControllers["_time${index}Controller"]?.text =
"";
_clearError("time_$index");
// validateTimeDifference(index);
// _selectCheckOutTime(context);
@ -3357,15 +3481,22 @@ class FlightScreenState extends State<FlightScreen> {
child: TextField(
focusNode: focusNodes["_time${index}FocusNode"],
// controller: _timeController,
controller: textControllers["_time${index}Controller"],
controller:
textControllers["_time${index}Controller"],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Time",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
labelStyle: TextStyle(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior:
FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
contentPadding: EdgeInsets.symmetric(
vertical: 16,
),
suffixIcon: Icon(
Icons.access_time,
size: 16,
@ -3407,7 +3538,9 @@ class FlightScreenState extends State<FlightScreen> {
width: double.infinity, // ensure full width
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(48), // set height
minimumSize: const Size.fromHeight(
48,
), // set height
backgroundColor: Colors.red,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
@ -3471,61 +3604,7 @@ class FlightScreenState extends State<FlightScreen> {
),
);
}
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Visa Required",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// // isFocused: _tripTypeFocused,
// isFocused: focusStates["_visa1Focused"] ?? false,
// isDesktop: isDesktop,
// // width: isDesktop
// // ? MediaQuery.of(context).size.width * 0.34
// // : MediaQuery.of(context).size.width * 0.66,
// child: SizedBox(
// height: 40,
// child: DropdownButtonFormField<String>(
// // focusNode: _tripTypeFocusNode, // Assign the correct focus node
// focusNode: focusNodes["_visa1FocusNode"],
// value: selectedvisa_available,
// style: TextStyle(fontSize: 12),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// visa_available.isNotEmpty
// ? (newValue) {
// setState(() {
// selectedvisa_available = newValue;
// // selectedTripType = "Oneway";
// // Reset `multiTripRowCount` when switching away from Multitrip
// });
// print(
// "Updating form data: Flight -> trip_type -> $selectedvisa_available",
// );
//
// // _initializeRows();
// }
// : null,
//
// items: dropdownItems,
// ),
// ),
// ),
// ],
// ),
//********//
return isDesktop
? [
Column(
@ -3565,14 +3644,17 @@ class FlightScreenState extends State<FlightScreen> {
child: DropdownSearch<Map<String, dynamic>>(
items: visa_available.cast<Map<String, dynamic>>(),
selectedItem: visa_available.firstWhere(
(item) => item['dropdown_key'] == selectedvisa_available,
(item) =>
item['dropdown_key'] == selectedvisa_available,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
@ -3614,7 +3696,10 @@ class FlightScreenState extends State<FlightScreen> {
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
@ -3646,7 +3731,9 @@ class FlightScreenState extends State<FlightScreen> {
setState(() {
selectedvisa_available =
newValue?['dropdown_key'];
print("Selected Visa: $selectedvisa_available");
print(
"Selected Visa: $selectedvisa_available",
);
});
}
: null,
@ -3674,7 +3761,8 @@ class FlightScreenState extends State<FlightScreen> {
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_comments1Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
width:
isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
child: TextField(
focusNode: focusNodes["_comments1FocusNode"],
// controller: _commentsController,
@ -3709,7 +3797,9 @@ class FlightScreenState extends State<FlightScreen> {
elevation: 1,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
color: const Color(0xFFF5F5F5), // Light grey
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
@ -3750,16 +3840,22 @@ class FlightScreenState extends State<FlightScreen> {
focusNodes["_visa1FocusNode"]?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: visa_available.cast<Map<String, dynamic>>(),
items:
visa_available.cast<Map<String, dynamic>>(),
selectedItem: visa_available.firstWhere(
(item) => item['dropdown_key'] == selectedvisa_available,
(item) =>
item['dropdown_key'] ==
selectedvisa_available,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
itemAsString:
(item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
@ -3783,7 +3879,8 @@ class FlightScreenState extends State<FlightScreen> {
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_visa1Focused"] ?? false)
(focusStates["_visa1Focused"] ??
false)
? layoutColor!
: Colors.white,
width: 0.5,
@ -3792,7 +3889,8 @@ class FlightScreenState extends State<FlightScreen> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_visa1Focused"] ?? false)
(focusStates["_visa1Focused"] ??
false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
@ -3801,7 +3899,10 @@ class FlightScreenState extends State<FlightScreen> {
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
@ -3810,7 +3911,8 @@ class FlightScreenState extends State<FlightScreen> {
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
if (selectedItem == null ||
selectedItem.isEmpty) {
return Text(
"Select Option",
style: GoogleFonts.poppins(
@ -3833,7 +3935,9 @@ class FlightScreenState extends State<FlightScreen> {
setState(() {
selectedvisa_available =
newValue?['dropdown_key'];
print("Selected Visa: $selectedvisa_available");
print(
"Selected Visa: $selectedvisa_available",
);
});
}
: null,
@ -3861,7 +3965,10 @@ class FlightScreenState extends State<FlightScreen> {
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_comments1Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.32
: null,
child: TextField(
focusNode: focusNodes["_comments1FocusNode"],
// controller: _commentsController,
@ -3871,7 +3978,10 @@ class FlightScreenState extends State<FlightScreen> {
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
labelStyle: TextStyle(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 1),

View File

@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
class AccomodationListWidget extends StatelessWidget {
import '../../utils/auth_utils.dart';
class AccomodationListWidget extends StatefulWidget {
final List<Map<String, dynamic>> accommodationList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteAccommodation;
final Function(String, bool) onAddNew;
final bool isViewMode;
@ -19,12 +20,57 @@ class AccomodationListWidget extends StatelessWidget {
required this.isViewMode,
});
@override
State<AccomodationListWidget> createState() => _AccomodationListWidgetState();
}
class _AccomodationListWidgetState extends State<AccomodationListWidget> {
Color? layoutColor;
Color? secondColor;
Color? thridColor;
@override
void initState() {
super.initState();
loadInitialData();
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? secondString = await getSecondaryColor();
String? thridString = await getTernaryColor();
// String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
}
@override
Widget build(BuildContext context) {
final isDesktop = MediaQuery.of(context).size.width > 1024;
return Padding(
padding: const EdgeInsets.all(16.0),
padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container(
margin: const EdgeInsets.only(top: 16.0),
child: Column(
@ -34,7 +80,7 @@ class AccomodationListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && accommodationList.isNotEmpty)
if ((!isDesktop) && widget.accommodationList.isNotEmpty)
Text(
" ",
style: const TextStyle(
@ -44,16 +90,18 @@ class AccomodationListWidget extends StatelessWidget {
),
MouseRegion(
cursor: isViewMode
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
onTap:
widget.isViewMode
? null
: () {
print("New data");
onAddNew("Accomodation", true);
widget.onAddNew("Accomodation", true);
},
child: Row(
mainAxisSize:
@ -68,7 +116,7 @@ class AccomodationListWidget extends StatelessWidget {
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
),
// Container(
// decoration: BoxDecoration(
// shape: BoxShape.circle,
@ -147,9 +195,9 @@ class AccomodationListWidget extends StatelessWidget {
],
),
const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop)
// Scroll behavior based on device
_buildData(context, isDesktop),
],
),
),
@ -158,7 +206,9 @@ class AccomodationListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
accommodationList.where((item) => item["is_active"] == "1").toList();
widget.accommodationList
.where((item) => item["is_active"] == "1")
.toList();
print("filteredList- $filteredList");
// String formatDate(String dateString) {
@ -191,8 +241,11 @@ class AccomodationListWidget extends StatelessWidget {
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");
@ -235,14 +288,18 @@ class AccomodationListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
color: isDesktop ? Colors.white : thridColor,
// color: Colors.white,
boxShadow:
isDesktop
? [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
]
: [],
border: Border(
top: BorderSide(
color: Colors.white70, // Change color to match your theme
@ -251,7 +308,7 @@ class AccomodationListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -262,25 +319,27 @@ class AccomodationListWidget extends StatelessWidget {
item["hotel_name"]!,
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),)
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w500,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Accomodation"),
onTap: () => widget.onOpen(true, item, "Accomodation"),
child: Tooltip(
message: 'Edit Accomodation Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black87,
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteAccommodation(item),
onTap: () => widget.onDeleteAccommodation(item),
child: Tooltip(
message: 'Delete Accommodation Details',
child: Image.asset(
@ -293,9 +352,7 @@ class AccomodationListWidget extends StatelessWidget {
),
],
),
Divider(
color: Colors.blueGrey.shade50,
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
@ -304,34 +361,30 @@ class AccomodationListWidget extends StatelessWidget {
flex: 2,
child: Text(
" DestinationCity",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Check (in) ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Check (out) ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
],
)
: SizedBox.shrink(),
@ -374,87 +427,99 @@ class AccomodationListWidget extends StatelessWidget {
Expanded(
flex: 2,
child: _buildComments(
"Comments:", item["comments"] ?? "N/A"),
"Comments:",
item["comments"] ?? "N/A",
),
),
],
)
: Column(
: Container(
color: Colors.white,
padding: EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_buildInfoColumn("City", item["destination_city"]),
_buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"),
_buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"),
// City - long name handled with flexible space
// Expanded(
// flex: 3,
// child: _buildInfoColumn("City", item["destination_city"]),
// ),
// SizedBox(width: 8),
// Check In and Check Out stacked right side
// Expanded(
// flex: 4,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// _buildInfoColumn(
// "Check In",
// "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
// ),
// SizedBox(height: 6),
// _buildInfoColumn(
// "Check Out",
// "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
// ),
// ],
// ),
// ),
_buildRow(
"Destination City",
item["destination_city"],
),
SizedBox(height: 5),
_buildDateTimeRow(
"Check (in)",
formatDate(item["checkin_date"]!),
formatTime(item["checkin_time"]!),
),
SizedBox(height: 5),
_buildDateTimeRow(
"Check (out)",
formatDate(item["checkout_date"]!),
formatTime(item["checkout_time"]!),
),
SizedBox(height: 5),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
),
const SizedBox(height: 10),
const Text(
"Comment",
style: TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 5),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(color: Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"],
style: const TextStyle(fontSize: 12),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
)
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("City:", item["destination_city"]),
// SizedBox(width: 10),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Check-in:",
// formatDate(item["checkin_date"]!),
// item["checkin_time"]!,
// Wrap(
// spacing: 20, // horizontal space between items
// runSpacing: 10, // vertical space between rows
// children: [
// _buildInfoColumn("City", item["destination_city"]),
// _buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"),
// _buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"),
// // City - long name handled with flexible space
// // Expanded(
// // flex: 3,
// // child: _buildInfoColumn("City", item["destination_city"]),
// // ),
//
// // SizedBox(width: 8),
//
// // Check In and Check Out stacked right side
// // Expanded(
// // flex: 4,
// // child: Column(
// // crossAxisAlignment: CrossAxisAlignment.end,
// // children: [
// // _buildInfoColumn(
// // "Check In",
// // "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
// // ),
// // SizedBox(height: 6),
// // _buildInfoColumn(
// // "Check Out",
// // "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
// // ),
// // ],
// // ),
// // ),
// ],
// ),
// SizedBox(width: 10),
// _buildRow(
// "Date(out):", formatDate(item["checkout_date"]!)),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// const SizedBox(height: 10),
// const Text(
// "Comment",
// style: TextStyle(fontWeight: FontWeight.w500),
// ),
// const SizedBox(height: 5),
// if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
// Container(
// width: double.infinity,
// padding: const EdgeInsets.all(8),
// decoration: BoxDecoration(
// border: Border.all(color: Color(0xFF7098DD), width: 1),
// borderRadius: BorderRadius.circular(6),
// ),
// child: Text(
// item["comments"],
// style: const TextStyle(fontSize: 12),
// ),
// )
// else
// const Text( "N/A", style: TextStyle(fontSize: 12), ),
// ],
// )
],
@ -485,23 +550,27 @@ class AccomodationListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: exceedsLimit
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle:
TextStyle(color: Colors.black), // Tooltip text color
textStyle: TextStyle(
color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(value.substring(0, limit) + "...",
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
@ -531,87 +600,92 @@ class AccomodationListWidget extends StatelessWidget {
SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
],
);
}
// Widget _buildRow(String title, String value) {
// // Define character limits based on title
// Map<String, int> limits = {
// // "Special Request:": 30,
// "Comments:": 10,
// // Add more keys and limits if needed
// };
//
// int limit = limits[title] ?? 50; // Default limit if title not found
// bool exceedsLimit = value.length > limit;
//
// String wrapText(String text, int maxLineLength) {
// final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
// return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
// }
//
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// ),
// SizedBox(width: 8),
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {
// "Special Request:": 30,
"Comments:": 10,
// Add more keys and limits if needed
};
int limit = limits[title] ?? 50; // Default limit if title not found
bool exceedsLimit = value.length > limit;
String wrapText(String text, int maxLineLength) {
final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
// color: Colors.yellowAccent.shade100,
width: 100,
child: Expanded(
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
),
SizedBox(width: 5),
Expanded(child: Text(value, style: TextStyle(fontSize: 12))),
// Expanded(
// child: exceedsLimit
// child:
// exceedsLimit
// ? Tooltip(
// message: wrapText(value, 50),
// decoration: BoxDecoration(
// color: Colors.grey.shade200, // Black background
// borderRadius: BorderRadius.circular(6),
// ),
// textStyle:
// TextStyle(color: Colors.black), // Tooltip text color
// textStyle: TextStyle(
// color: Colors.black,
// ), // Tooltip text color
// padding: EdgeInsets.all(8),
// preferBelow: false,
// child: Text(value.substring(0, limit) + "...",
// style: TextStyle(fontSize: 12),
// overflow: TextOverflow.ellipsis),
// )
// : Text(
// value,
// style: TextStyle(fontSize: 12),
// ),
// ),
// ],
// );
// }
// Widget _buildDateTimeRow(String title, String date, String time) {
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// SizedBox(width: 8),
// Expanded(
// child: Text(
// "$date, $time",
// style: GoogleFonts.poppins(
// fontSize: 12,
// value.substring(0, limit) + "...",
// style: TextStyle(fontSize: 12),
// overflow: TextOverflow.ellipsis,
// ),
// )
// : Text(value, style: TextStyle(fontSize: 12)),
// ),
// ),
// ],
// );
// }
],
);
}
Widget _buildDateTimeRow(String title, String date, String time) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 100,
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 5),
Expanded(
child: Text("$date, $time", style: GoogleFonts.poppins(fontSize: 12)),
),
],
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
class FlightListWidget extends StatefulWidget {
final bool hasAction;
@ -32,6 +33,9 @@ class FlightListWidget extends StatefulWidget {
class _FlightListWidgetState extends State<FlightListWidget> {
ApiService apiService = ApiService();
Color? layoutColor;
Color? secondColor;
Color? thridColor;
// late Map<String, String> countryMap;
Map<String, String> countryMap = {};
@ -40,6 +44,36 @@ class _FlightListWidgetState extends State<FlightListWidget> {
void initState() {
super.initState();
loadCountryList(); // Call your method here
loadInitialData();
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? secondString = await getSecondaryColor();
String? thridString = await getTernaryColor();
// String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
}
Future<void> loadCountryList() async {
@ -169,7 +203,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// );
return Padding(
padding: const EdgeInsets.all(16.0),
padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container(
margin: const EdgeInsets.only(top: 16.0),
child: Column(
@ -192,11 +227,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// Right side: either "Add" icon or nothing
if (widget.flightList.isNotEmpty)
MouseRegion(
cursor: widget.isViewMode
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: widget.isViewMode
onTap:
widget.isViewMode
? null
: () {
widget.onAddNew("Flight", true);
@ -223,8 +260,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
),
),
)
),
],
),
const SizedBox(height: 16),
@ -235,7 +271,6 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
),
);
}
Widget _buildData(BuildContext context, bool isDesktop) {
@ -347,10 +382,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: isDesktop ? Colors.white : Color(0xFFFFF0F5),
color: isDesktop ? Colors.white : thridColor,
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
// color: Colors.white,
boxShadow:
isDesktop
? [
BoxShadow(
color: Colors.black12,
blurRadius: 2,
@ -362,7 +400,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
blurRadius: 0.5,
offset: Offset(0, -1), // up
),
],
]
: [],
border: Border(
top: BorderSide(
color: Colors.white70, // Change color to match your theme
@ -371,18 +410,23 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Row(
children: [
Text(
tripTypeName ?? "N/A",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w500,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
// Color(0xFF114D8B)
),
),
Spacer(),
@ -394,7 +438,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color:
isDesktop ? Color(0xFF114D8B) : Colors.black87,
),
),
),
@ -413,7 +458,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
],
),
Divider(color: Colors.blueGrey.shade50),
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
if (isDesktop)
Row(
@ -600,7 +646,6 @@ class _FlightListWidgetState extends State<FlightListWidget> {
item["trips"] != null &&
item["trips"].isNotEmpty)
...item["trips"].map<Widget>((trip) {
String fromPlaceCountry =
countryMap[trip["from_place"]?.toString()] ??
"Unknown Country";
@ -631,41 +676,44 @@ class _FlightListWidgetState extends State<FlightListWidget> {
final tocity = tocityMatch?.group(1) ?? '';
final tocode = tocityMatch?.group(2) ?? '';
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0),
// child: Container(
// decoration: BoxDecoration(
// border: Border.all(color: Colors.grey.shade300),
// borderRadius: BorderRadius.circular(6),
// color: Colors.grey.shade50,
// ),
// padding: const EdgeInsets.all(8),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildKeyValueRow(
// "Class",
// getRequestForClass(trip["class"].toString()) ??
// "N/A",
// ),
// _buildKeyValueRow(
// "Sector",
// "$fromcity ($fromcode), $fromairport$tocity ($tocode), $toairport",
// ),
//
// _buildKeyValueRow(
// "Date",
// formatDate(trip["date"] ?? ""),
// ),
// _buildKeyValueRow(
// "Time",
// formatTime(trip["time"] ?? ""),
// ),
// ],
// ),
// ),
// );
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(6),
color: Colors.grey.shade50,
),
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildKeyValueRow(
"Class",
getRequestForClass(trip["class"].toString()) ??
"N/A",
),
_buildKeyValueRow(
"From",
"$fromcity ($fromcode), $fromairport ",
),
_buildKeyValueRow(
"To",
"$tocity ($tocode), $toairport",
),
_buildKeyValueRow(
"Date",
formatDate(trip["date"] ?? ""),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
),
],
),
),
);
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0),
@ -701,9 +749,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// ),
// ),
// const Padding(
// padding: EdgeInsets.symmetric(horizontal: 6),
// padding: EdgeInsets.symmetric(
// horizontal: 6,
// ),
// child: Image(
// image: AssetImage('assets/images/IconsImg/Frame.png'),
// image: AssetImage(
// 'assets/images/IconsImg/Frame.png',
// ),
// width: 18,
// height: 18,
// ),
@ -738,68 +790,67 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// ),
// );
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 4,
children: [
Text(
'${getRequestForClass(trip["class"].toString()) ?? "N/A"} (',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
Text(
fromcode,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 4),
child: Image(
image: AssetImage('assets/images/IconsImg/Frame.png'),
width: 18,
height: 18,
),
),
Text(
'$tocode)',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
],
),
const SizedBox(height: 6),
Align(
alignment: Alignment.centerRight,
child: Text(
'${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}',
textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 13,
color: Colors.black87,
),
),
),
],
),
),
);
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0),
// child: Container(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Wrap(
// crossAxisAlignment: WrapCrossAlignment.center,
// spacing: 4,
// runSpacing: 4,
// children: [
// Text(
// '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (',
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// Text(
// fromcode,
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// const Padding(
// padding: EdgeInsets.symmetric(horizontal: 4),
// child: Image(
// image: AssetImage('assets/images/IconsImg/Frame.png'),
// width: 18,
// height: 18,
// ),
// ),
// Text(
// '$tocode)',
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// ],
// ),
// const SizedBox(height: 6),
// Align(
// alignment: Alignment.centerRight,
// child: Text(
// '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}',
// textAlign: TextAlign.right,
// style: const TextStyle(
// fontSize: 13,
// color: Colors.black87,
// ),
// ),
// ),
// ],
// ),
// ),
// );
}).toList(),
],
),
@ -816,12 +867,12 @@ class _FlightListWidgetState extends State<FlightListWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 80, // adjust width as needed
width: 70, // adjust width as needed
child: Text(
"$key:",
"$key",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w700,
fontWeight: FontWeight.w600,
),
),
),

View File

@ -5,8 +5,9 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
class ForexListWidget extends StatelessWidget {
class ForexListWidget extends StatefulWidget {
final List<Map<String, dynamic>> forexList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteForex;
@ -16,15 +17,60 @@ class ForexListWidget extends StatelessWidget {
final Function(String, bool) onAddNew;
final bool isViewMode;
const ForexListWidget(
{super.key,
const ForexListWidget({
super.key,
required this.forexList,
required this.onOpen,
required this.onDeleteForex,
required this.apiCountryData,
required this.onAddNew,
required this.apiData,
required this.isViewMode});
required this.isViewMode,
});
@override
State<ForexListWidget> createState() => _ForexListWidgetState();
}
class _ForexListWidgetState extends State<ForexListWidget> {
Color? layoutColor;
Color? secondColor;
Color? thridColor;
@override
void initState() {
super.initState();
loadInitialData();
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? secondString = await getSecondaryColor();
String? thridString = await getTernaryColor();
// String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
}
@override
Widget build(BuildContext context) {
@ -32,7 +78,8 @@ class ForexListWidget extends StatelessWidget {
final ApiService apiService = ApiService();
return Padding(
padding: const EdgeInsets.all(16.0),
padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container(
margin: const EdgeInsets.only(top: 16.0),
child: Column(
@ -135,26 +182,23 @@ class ForexListWidget extends StatelessWidget {
// ],
// ),
const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop)
// Scroll behavior based on device
_buildData(context, isDesktop),
],
),
),
);
}
Widget _buildData(
BuildContext context,
bool isDesktop,
) {
Widget _buildData(BuildContext context, bool isDesktop) {
final ApiService apiService = ApiService();
List<Map<String, dynamic>> filteredList =
forexList.where((item) => item["is_active"] == "1").toList();
widget.forexList.where((item) => item["is_active"] == "1").toList();
print("filteredList- $filteredList");
List<dynamic> visatypeList = apiData?['visa_type_of_visa'] ?? [];
List<dynamic> countryList = apiCountryData ?? [];
List<dynamic> visatypeList = widget.apiData?['visa_type_of_visa'] ?? [];
List<dynamic> countryList = widget.apiCountryData ?? [];
String getRequestForVisa(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
@ -209,8 +253,11 @@ class ForexListWidget extends StatelessWidget {
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");
@ -231,27 +278,34 @@ class ForexListWidget extends StatelessWidget {
itemBuilder: (context, index) {
final item = filteredList[index];
final double transport = double.tryParse(item["transport"] ?? "0") ?? 0;
final double accommodation = double.tryParse(item["accommodation"] ?? "0") ?? 0;
final double accommodation =
double.tryParse(item["accommodation"] ?? "0") ?? 0;
final double telephone = double.tryParse(item["telephone"] ?? "0") ?? 0;
final double perdiemAmount = double.tryParse(item["perdiem_amount"] ?? "0") ?? 0;
final double perdiemAmount =
double.tryParse(item["perdiem_amount"] ?? "0") ?? 0;
final double calculatedValue = transport + accommodation + telephone;
final String calculatedOtherExpenses = calculatedValue.toStringAsFixed(0);
final String calculatedOtherExpenses = calculatedValue.toStringAsFixed(
0,
);
final double finalTotal = calculatedValue + perdiemAmount;
return Container(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
// color: Colors.white,
color: isDesktop ? Colors.white : thridColor,
boxShadow:
isDesktop
? [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
]
: [],
border: Border(
top: BorderSide(
color: Colors.white70, // Change color to match your theme
@ -260,7 +314,7 @@ class ForexListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -271,12 +325,12 @@ class ForexListWidget extends StatelessWidget {
getRequestForCountry(item["country_code"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w700,
fontWeight: FontWeight.w600,
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Forex"),
onTap: () => widget.onOpen(true, item, "Forex"),
child: Tooltip(
message: 'Edit Forex Details',
child: Image.asset(
@ -284,7 +338,7 @@ class ForexListWidget extends StatelessWidget {
width: 20,
height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
),
@ -303,8 +357,11 @@ class ForexListWidget extends StatelessWidget {
// ),
item['forex_id'] != null
? IconButton(
icon: Icon(Icons.download,
color: Color(0xFF114D8B), size: 18),
icon: Icon(
Icons.download,
color: Color(0xFF114D8B),
size: 18,
),
onPressed: () {
print("PDF- ${item['forex_id']}");
final forexIdString = item['forex_id'];
@ -320,10 +377,8 @@ class ForexListWidget extends StatelessWidget {
: SizedBox.shrink(), // or Container()
],
),
Divider(
color: Colors.blueGrey.shade50,
),
SizedBox(height: 4),
Divider(color: Colors.blueGrey.shade50),
// SizedBox(height: 4),
isDesktop
? Row(
children: [
@ -331,26 +386,23 @@ class ForexListWidget extends StatelessWidget {
flex: 2,
child: Text(
"Currency",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Duration",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Time Period ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
// Expanded(
// flex: 2,
// child: Text(
@ -362,50 +414,44 @@ class ForexListWidget extends StatelessWidget {
flex: 2,
child: Text(
" Perdiem ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Others ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Total ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Cash ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Card ",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
style: GoogleFonts.poppins(fontSize: 11),
),
),
)),
],
)
: SizedBox.shrink(),
@ -503,85 +549,113 @@ class ForexListWidget extends StatelessWidget {
Expanded(
flex: 2,
child: _buildComments(
"Comments:", item["comments"] ?? "N/A"),
"Comments:",
item["comments"] ?? "N/A",
),
),
],
): Column(
)
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoBlock("Country code", item["country_code"] ?? "N/A"),
_infoBlock("Currency", item["currency"] ?? "N/A"),
_infoBlock("Total Amount", item["total_amount"]?.toString() ?? "0"),
_buildRow("Currency", item["currency"]),
SizedBox(height: 2),
_buildRow("Duration", item["duration"]),
SizedBox(height: 2),
_buildRow(
"Time Period",
"${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}",
// "${item["start_date"]!} - ${item["end_date"]!}",
),
SizedBox(height: 2),
_buildRow("Perdiem", "$perdiemAmount"),
SizedBox(height: 2),
_buildRow("Others", "$calculatedOtherExpenses"),
SizedBox(height: 2),
_buildRow("Total", "$finalTotal"),
SizedBox(height: 2),
_buildRow("Cash", item["deposit_on_cash"]!),
SizedBox(height: 2),
_buildRow("Card", item["deposit_on_card"]!),
SizedBox(height: 2),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
const SizedBox(height: 12),
// Second Row (Start Date, End Date, Duration)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoBlock("Start Date", item["start_date"] ?? "N/A"),
_infoBlock("End Date", item["end_date"] ?? "N/A"),
_infoBlock("Duration", item["duration"]?.toString() ?? "N/A"),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// old code
// : Column(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "Currency:",
// item["currency"],
// // Top Row (Country, Currency, Total)
// Wrap(
// spacing: 20, // horizontal space between items
// runSpacing: 10, // vertical space between rows
// // Row(
// // mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoBlock(
// "Country code",
// item["country_code"] ?? "N/A",
// ),
// // SizedBox(height: 6),
// _buildRow(
// "Duration:",
// item["duration"],
// _infoBlock("Currency", item["currency"] ?? "N/A"),
// _infoBlock(
// "Total Amount",
// item["total_amount"]?.toString() ?? "0",
// ),
// // SizedBox(height: 6),
// _buildRow("StartDate:", item["start_date"]!),
// _buildRow("EndDate:", item["end_date"]!),
// _buildRow("Perdiem:", "$perdiemAmount",),
// _buildRow("Others:", "$calculatedOtherExpenses"),
// _buildRow("Total:", "$finalTotal"),
// _buildRow("Cash:", item["deposit_on_cash"]!),
// _buildRow("Card:", item["deposit_on_card"]!),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
// const SizedBox(height: 12),
//
// // Second Row (Start Date, End Date, Duration)
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoBlock(
// "Start Date",
// item["start_date"] ?? "N/A",
// ),
// _infoBlock("End Date", item["end_date"] ?? "N/A"),
// _infoBlock(
// "Duration",
// item["duration"]?.toString() ?? "N/A",
// ),
// ],
// ),
// const SizedBox(height: 16),
//
// // Comment label
// Text(
// "Comment",
// style: GoogleFonts.poppins(
// fontSize: 14,
// fontWeight: FontWeight.w600,
// ),
// ),
// const SizedBox(height: 8),
// if (item["comments"] != null &&
// item["comments"].toString().trim().isNotEmpty)
// Container(
// width: double.infinity,
// padding: const EdgeInsets.all(12),
// decoration: BoxDecoration(
// border: Border.all(
// color: const Color(0xFF7098DD),
// width: 1,
// ),
// borderRadius: BorderRadius.circular(6),
// ),
// child: Text(
// item["comments"] ?? "N/A",
// style: GoogleFonts.poppins(
// fontSize: 12,
// color: Colors.black87,
// ),
// ),
// )
// else
// const Text("N/A", style: TextStyle(fontSize: 12)),
// ],
// ),
],
@ -612,23 +686,27 @@ class ForexListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: exceedsLimit
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle:
TextStyle(color: Colors.black), // Tooltip text color
textStyle: TextStyle(
color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(value.substring(0, limit) + "...",
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
@ -660,10 +738,7 @@ class ForexListWidget extends StatelessWidget {
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
],
),
@ -671,60 +746,59 @@ class ForexListWidget extends StatelessWidget {
);
}
// Widget _buildRow(String title, String value) {
// // Define character limits based on title
// Map<String, int> limits = {
// // "Special Request:": 30,
// "Comments:": 10,
// // Add more keys and limits if needed
// };
//
// int limit = limits[title] ?? 50; // Default limit if title not found
// bool exceedsLimit = value.length > limit;
//
// String wrapText(String text, int maxLineLength) {
// final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
// return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
// }
//
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// SizedBox(width: 8),
// Expanded(
// child: exceedsLimit
// ? Tooltip(
// message: wrapText(value, 50),
// decoration: BoxDecoration(
// color: Colors.grey.shade200, // Black background
// borderRadius: BorderRadius.circular(6),
// ),
// textStyle:
// TextStyle(color: Colors.black), // Tooltip text color
// padding: EdgeInsets.all(8),
// preferBelow: false,
// child: Text(value.substring(0, limit) + "...",
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// overflow: TextOverflow.ellipsis),
// )
// : Text(
// value,
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// ),
// ),
// ],
// );
// }
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {
// "Special Request:": 30,
"Comments:": 10,
// Add more keys and limits if needed
};
int limit = limits[title] ?? 50; // Default limit if title not found
bool exceedsLimit = value.length > limit;
String wrapText(String text, int maxLineLength) {
final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 100,
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
SizedBox(width: 8),
Expanded(
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
)
: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
),
],
);
}
}

View File

@ -856,7 +856,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
margin: EdgeInsets.only(
top: 40,
), // Push it down to make room for the tab bar
padding: EdgeInsets.all(12),
padding: EdgeInsets.only(top: 12, bottom: 12, left: 3, right: 3),
decoration: BoxDecoration(
color: Colors.white, // Card background
// color: Colors.yellow.shade50, // Card background

View File

@ -181,7 +181,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"first_approver": selectedFirstApprover,
"second_approver": selectedSecondApprover,
"third_approver": selectedThirdApprover,
"exceptional_approver": selectedExceptionalApprover,
"fourth_approver": selectedExceptionalApprover,
// "exceptional_approver": selectedExceptionalApprover,
"delegated_to_user_id": selectedSubstituteApprover,
// "passport_number": controllers["passportNumber"]?.text,
// "place_of_issue": controllers["placeOfIssue"]?.text,
@ -300,9 +301,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
apiselectedUser?["third_approver"]?.toString() ?? "";
}
if (apiselectedUser?["exceptional_approver"] != null) {
// if (apiselectedUser?["exceptional_approver"] != null) {
// selectedExceptionalApprover =
// apiselectedUser?["exceptional_approver"]?.toString() ?? "";
// }
if (apiselectedUser?["fourth_approver"] != null) {
selectedExceptionalApprover =
apiselectedUser?["exceptional_approver"]?.toString() ?? "";
apiselectedUser?["fourth_approver"]?.toString() ?? "";
}
if (apiselectedUser?["delegated_to_user_id"] != null) {
@ -1329,9 +1335,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("📨 Response: ${response.body}");
if(roleId == "4"){ context.go('/listPlan'); }
else{ context.go('/listUser'); }
if (roleId == "4") {
context.go('/listPlan');
} else {
context.go('/listUser');
}
} else {
print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}");

View File

@ -191,18 +191,34 @@ class OfficeDetailsState extends State<OfficeDetails> {
fetchUsers();
fetchFindGroup();
_addFocusListener(_employeeCodeFocusNode, (focus) => _employeeCodeFocus = focus);
_addFocusListener(_departmentFocusNode, (focus) => _departmentFocus = focus);
_addFocusListener(
_employeeCodeFocusNode,
(focus) => _employeeCodeFocus = focus,
);
_addFocusListener(
_departmentFocusNode,
(focus) => _departmentFocus = focus,
);
_addFocusListener(_groupFocusNode, (focus) => _groupFocus = focus);
_addFocusListener(_firstApprovalFocusNode, (focus) => _firstApprovalFocus = focus);
_addFocusListener(_secondApprovalFocusNode, (focus) => _secondApprovalFocus = focus);
_addFocusListener(_thirdApprovalFocusNode, (focus) => _thirdApprovalFocus = focus);
_addFocusListener(_exceptionalApprovalFocusNode, (focus) => _exceptionalApprovalFocus = focus);
_addFocusListener(
_firstApprovalFocusNode,
(focus) => _firstApprovalFocus = focus,
);
_addFocusListener(
_secondApprovalFocusNode,
(focus) => _secondApprovalFocus = focus,
);
_addFocusListener(
_thirdApprovalFocusNode,
(focus) => _thirdApprovalFocus = focus,
);
_addFocusListener(
_exceptionalApprovalFocusNode,
(focus) => _exceptionalApprovalFocus = focus,
);
_addFocusListener(_delegateFocusNode, (focus) => _delegateFocus = focus);
_addFocusListener(_startDateFocusNode, (focus) => _startDateFocus = focus);
_addFocusListener(_endDateFocusNode, (focus) => _endDateFocus = focus);
}
void _addFocusListener(FocusNode node, Function(bool) updateState) {
@ -465,10 +481,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
widget.isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildExceptionApprover(isDesktop),
Spacer(),
],
children: [buildExceptionApprover(isDesktop), Spacer()],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -703,27 +716,28 @@ class OfficeDetailsState extends State<OfficeDetails> {
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_departmentFocus)
? (layoutColor)
: Colors.white,
(_departmentFocus) ? (layoutColor) : Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_departmentFocus)
? (layoutColor)
: Colors.white,
(_departmentFocus) ? (layoutColor) : Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color: (layoutColor ?? Colors.grey),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
@ -746,7 +760,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
final departmentId =
departmentMap.entries
.firstWhere((entry) => entry.value == newValue)
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
setState(() {
@ -757,7 +773,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
departmentId,
); // Send department_id
},
),),),
),
),
),
),
),
],
@ -914,9 +932,14 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color: (layoutColor ?? Colors.grey),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -934,7 +957,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
final levelId =
groupMap.entries
.firstWhere((entry) => entry.value == newValue)
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
setState(() {
@ -946,7 +971,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
); // pass the ID not the name
},
),
),),
),
),
),
),
],
@ -1003,16 +1029,20 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
)
: DropdownSearch<String>(
selectedItem: userMap[selectedFirstApprover],
selectedItem:
userMap[selectedFirstApprover],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
fit:
FlexFit
.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
(context, item, isSelected) =>
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
@ -1024,7 +1054,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
),
),
constraints: BoxConstraints(maxHeight: 250),
constraints: BoxConstraints(
maxHeight: 250,
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search User...",
@ -1038,14 +1070,19 @@ class OfficeDetailsState extends State<OfficeDetails> {
apiUserData!.map((user) {
return "${user['first_name']} ${user['last_name']}";
}).toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
dropdownDecoratorProps:
DropDownDecoratorProps(
dropdownSearchDecoration:
InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_firstApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_firstApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
),
@ -1053,18 +1090,29 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_firstApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_firstApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color:
(layoutColor ??
Colors.grey),
width: 0.5,
),
),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -1098,7 +1146,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
final approverId =
userMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
@ -1111,7 +1160,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
); // not newValue, but approverId
},
),
),),
),
),
),
),
],
@ -1175,16 +1225,20 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
)
: DropdownSearch<String>(
selectedItem: userMap[selectedSecondApprover],
selectedItem:
userMap[selectedSecondApprover],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
fit:
FlexFit
.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
(context, item, isSelected) =>
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
@ -1196,7 +1250,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
),
),
constraints: BoxConstraints(maxHeight: 250),
constraints: BoxConstraints(
maxHeight: 250,
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search User...",
@ -1210,14 +1266,19 @@ class OfficeDetailsState extends State<OfficeDetails> {
apiUserData!.map((user) {
return "${user['first_name']} ${user['last_name']}";
}).toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
dropdownDecoratorProps:
DropDownDecoratorProps(
dropdownSearchDecoration:
InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_secondApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_secondApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
),
@ -1225,18 +1286,29 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_secondApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_secondApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color:
(layoutColor ??
Colors.grey),
width: 0.5,
),
),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -1257,7 +1329,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
final approverId =
userMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
@ -1282,7 +1355,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
// });
// },
),
),),
),
),
),
),
],
@ -1346,16 +1420,20 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
)
: DropdownSearch<String>(
selectedItem: userMap[selectedThirdApprover],
selectedItem:
userMap[selectedThirdApprover],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
fit:
FlexFit
.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
(context, item, isSelected) =>
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
@ -1367,7 +1445,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
),
),
constraints: BoxConstraints(maxHeight: 250),
constraints: BoxConstraints(
maxHeight: 250,
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search User...",
@ -1381,14 +1461,19 @@ class OfficeDetailsState extends State<OfficeDetails> {
apiUserData!.map((user) {
return "${user['first_name']} ${user['last_name']}";
}).toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
dropdownDecoratorProps:
DropDownDecoratorProps(
dropdownSearchDecoration:
InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_thirdApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_thirdApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
),
@ -1396,18 +1481,29 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_thirdApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_thirdApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color:
(layoutColor ??
Colors.grey),
width: 0.5,
),
),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -1427,7 +1523,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
final approverId =
userMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
@ -1452,7 +1549,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
// });
// },
),
),),
),
),
),
),
],
@ -1480,7 +1578,7 @@ class OfficeDetailsState extends State<OfficeDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Exceptional Approver",
"Fourth Approver",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
@ -1516,16 +1614,20 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
)
: DropdownSearch<String>(
selectedItem: userMap[selectedExceptionalApprover],
selectedItem:
userMap[selectedExceptionalApprover],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
fit:
FlexFit
.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
(context, item, isSelected) =>
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
@ -1537,7 +1639,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
),
),
constraints: BoxConstraints(maxHeight: 250),
constraints: BoxConstraints(
maxHeight: 250,
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search User...",
@ -1554,11 +1658,15 @@ class OfficeDetailsState extends State<OfficeDetails> {
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(
8,
),
borderSide: BorderSide(
color:
(_exceptionalApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_exceptionalApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
),
@ -1566,8 +1674,10 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_exceptionalApprovalFocus ?? false)
? (layoutColor ?? Colors.white)
(_exceptionalApprovalFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
@ -1575,9 +1685,15 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.white), width: 0.5),
color:
(layoutColor ?? Colors.white),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -1598,12 +1714,14 @@ class OfficeDetailsState extends State<OfficeDetails> {
final approverId =
userMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
setState(() {
selectedExceptionalApprover = approverId;
selectedExceptionalApprover =
approverId;
});
widget.onExceptionalApproverChanged?.call(
@ -1611,7 +1729,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
); // not newValue, but approverId
},
),
),),
),
),
),
),
],
@ -1625,7 +1744,6 @@ class OfficeDetailsState extends State<OfficeDetails> {
);
}
Widget buildApproverSubstitute1(bool isDesktop) {
return Container(
color: Colors.white,
@ -1683,12 +1801,15 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height
fit:
FlexFit
.loose, // Allows flexible height
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
itemBuilder:
(context, item, isSelected) => Container(
(context, item, isSelected) =>
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
@ -1700,7 +1821,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
),
),
),
constraints: BoxConstraints(maxHeight: 133),
constraints: BoxConstraints(
maxHeight: 133,
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search User...",
@ -1714,14 +1837,19 @@ class OfficeDetailsState extends State<OfficeDetails> {
apiUserData!.map((user) {
return "${user['first_name']} ${user['last_name']}";
}).toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
dropdownDecoratorProps:
DropDownDecoratorProps(
dropdownSearchDecoration:
InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8),
borderSide: BorderSide(
color:
(_delegateFocus ?? false)
? (layoutColor ?? Colors.white)
(_delegateFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
),
@ -1729,18 +1857,29 @@ class OfficeDetailsState extends State<OfficeDetails> {
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_delegateFocus ?? false)
? (layoutColor ?? Colors.white)
(_delegateFocus ??
false)
? (layoutColor ??
Colors.white)
: Colors.white,
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 0.5),
color:
(layoutColor ??
Colors.grey),
width: 0.5,
),
),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
),
),
dropdownBuilder:
@ -1774,7 +1913,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
final approverId =
userMap.entries
.firstWhere(
(entry) => entry.value == newValue,
(entry) =>
entry.value == newValue,
)
.key;
@ -1787,7 +1927,8 @@ class OfficeDetailsState extends State<OfficeDetails> {
); // not newValue, but approverId
},
),
),),
),
),
),
),
],
@ -1892,7 +2033,10 @@ class OfficeDetailsState extends State<OfficeDetails> {
child: TextField(
controller: widget.controllers["delegationStartDate"],
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
decoration: InputDecoration(
labelText: "Select Date",
labelStyle: GoogleFonts.poppins(
@ -2049,7 +2193,10 @@ class OfficeDetailsState extends State<OfficeDetails> {
child: TextField(
controller: widget.controllers["delegationEndDate"],
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
decoration: InputDecoration(
labelText: "Select Date",
labelStyle: GoogleFonts.poppins(

View File

@ -1,7 +1,7 @@
//api url
// const String apiUrl = 'http://localhost/tstat_be';
const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
// const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be';
// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be';
/** Note : Adfactor UAT BE URL
* File : web/index.html - change below