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,14 +52,14 @@ class StatusDashboardState extends State<StatusDashboard> {
"Partially Approved", "Partially Approved",
"Approved", "Approved",
"Rejected", "Rejected",
"Cancelled" "Cancelled",
]; ];
// Extract counts for "Both" section // Extract counts for "Both" section
List<int> getStatusValues(Map<String, dynamic> serviceData) { List<int> getStatusValues(Map<String, dynamic> serviceData) {
final both = serviceData['Both'] ?? {}; final both = serviceData['Both'] ?? {};
return statusLabels.map((label) => (both[label] ?? 0) as int).toList(); return statusLabels.map((label) => (both[label] ?? 0) as int).toList();
} }
@override @override
void initState() { void initState() {
@ -150,8 +150,7 @@ class StatusDashboardState extends State<StatusDashboard> {
checkbackbutton(); checkbackbutton();
}); });
setState(() { setState(() {
isLoading = true; isLoading = true;
}); });
// If token exists, load the dashboard data // If token exists, load the dashboard data
loadDashboardData(); loadDashboardData();
@ -320,25 +319,27 @@ class StatusDashboardState extends State<StatusDashboard> {
setState(() { setState(() {
// currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount; // currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount;
typeData = selectedView == "Today" typeData =
? typeBasedTodayCount selectedView == "Today" ? typeBasedTodayCount : typeBasedWeeklyCount;
: typeBasedWeeklyCount ; statusData =
statusData = selectedView == "Today" selectedView == "Today"
? statusBasedTodayCount ? statusBasedTodayCount
: statusBasedWeeklyCount ; : statusBasedWeeklyCount;
flightData = selectedView == "Today" flightData =
? getStatusValues(todayBasedCount['flight'] ?? {}) selectedView == "Today"
: getStatusValues(weekBasedCount['flight'] ?? {}); ? getStatusValues(todayBasedCount['flight'] ?? {})
accommodationData = selectedView == "Today" : getStatusValues(weekBasedCount['flight'] ?? {});
? getStatusValues(todayBasedCount['acomodation'] ?? {}) accommodationData =
: getStatusValues(weekBasedCount['acomodation'] ?? {}); selectedView == "Today"
forexData = selectedView == "Today" ? getStatusValues(todayBasedCount['acomodation'] ?? {})
? getStatusValues(todayBasedCount['forex'] ?? {}) : getStatusValues(weekBasedCount['acomodation'] ?? {});
: getStatusValues(weekBasedCount['forex'] ?? {}); forexData =
selectedView == "Today"
? getStatusValues(todayBasedCount['forex'] ?? {})
: getStatusValues(weekBasedCount['forex'] ?? {});
}); });
print("statusBasedCount - => $statusBasedCount"); print("statusBasedCount - => $statusBasedCount");
print("Current Data - => $currentData"); print("Current Data - => $currentData");
// 👇 Local function to create the card widget // 👇 Local function to create the card widget
@ -403,6 +404,7 @@ class StatusDashboardState extends State<StatusDashboard> {
print("dashboard .."); print("dashboard ..");
} }
} }
String capitalize(String s) => s[0].toUpperCase() + s.substring(1); String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
Widget toggleChip(String label) { Widget toggleChip(String label) {
@ -450,7 +452,7 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column( child: Column(
children: [ children: [
Tooltip( Tooltip(
message: label , message: label,
child: Image.asset( child: Image.asset(
label == 'Domestic' label == 'Domestic'
? 'assets/images/IconsImg/Domestic_new.png' ? 'assets/images/IconsImg/Domestic_new.png'
@ -501,7 +503,8 @@ class StatusDashboardState extends State<StatusDashboard> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, // vertically center everything mainAxisAlignment:
MainAxisAlignment.center, // vertically center everything
children: [ children: [
Text( Text(
count.toString(), 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 = [ final statusIcons = [
Icons.calendar_today, Icons.calendar_today,
Icons.assignment, Icons.assignment,
@ -541,9 +576,9 @@ class StatusDashboardState extends State<StatusDashboard> {
final statusColors = [ final statusColors = [
Color(0xFFFBFFCA), Color(0xFFFBFFCA),
Color(0xFFFFF1CD),// Colors.yellow.shade100, // Color(0xFFCAE77B), Color(0xFFFFF1CD), // Colors.yellow.shade100, // Color(0xFFCAE77B),
Color(0xFFDAFFE8),// Colors.green.shade100, // Color(0xFF72D480), Color(0xFFDAFFE8), // Colors.green.shade100, // Color(0xFF72D480),
Color(0xFFFFD6D3),// Colors.red.shade100, // Color(0xFFF88C8C), Color(0xFFFFD6D3), // Colors.red.shade100, // Color(0xFFF88C8C),
Color(0xFFFFA8A8), // Colors.red.shade200, // Color(0xFFE94B4B), Color(0xFFFFA8A8), // Colors.red.shade200, // Color(0xFFE94B4B),
]; ];
@ -584,17 +619,16 @@ class StatusDashboardState extends State<StatusDashboard> {
color: Color(0xFF004A8E), color: Color(0xFF004A8E),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon( child: Icon(icon, color: Colors.white, size: 20),
icon,
color: Colors.white,
size: 20,
),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text(title, style: GoogleFonts.poppins( Text(
title,
style: GoogleFonts.poppins(
color: Colors.black87, color: Colors.black87,
fontWeight: FontWeight.bold fontWeight: FontWeight.bold,
),), ),
),
], ],
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
@ -612,7 +646,9 @@ class StatusDashboardState extends State<StatusDashboard> {
height: 28, height: 28,
decoration: BoxDecoration( decoration: BoxDecoration(
color: statusColors[index], // background color color: statusColors[index], // background color
borderRadius: BorderRadius.circular(4), // square with slight rounding borderRadius: BorderRadius.circular(
4,
), // square with slight rounding
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: Icon( child: Icon(
@ -622,16 +658,20 @@ class StatusDashboardState extends State<StatusDashboard> {
), ),
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text(statusLabels[index], style: GoogleFonts.poppins( Text(
color: Colors.black87, statusLabels[index],
),), style: GoogleFonts.poppins(color: Colors.black87),
),
], ],
), ),
Text(values[index].toString(), style: GoogleFonts.poppins( Text(
fontSize: 10, values[index].toString(),
color: Colors.black87, style: GoogleFonts.poppins(
fontWeight: FontWeight.bold, fontSize: 10,
),), color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
], ],
), ),
); );
@ -736,251 +776,383 @@ class StatusDashboardState extends State<StatusDashboard> {
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
? const EdgeInsets.symmetric(vertical: 5) isDesktop
: EdgeInsets.zero, ? const EdgeInsets.symmetric(vertical: 5)
: EdgeInsets.zero,
child: Center( child: Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(maxWidth: 1200),
maxWidth: 1200,
),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0), // Scroll content padding padding: const EdgeInsets.symmetric(
horizontal: 15.0,
), // Scroll content padding
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
isLoading ? Center(child: CircularProgressIndicator()) : isLoading
LayoutBuilder( ? Center(child: CircularProgressIndicator())
builder: (context, constraints) { : LayoutBuilder(
return Column( builder: (context, constraints) {
crossAxisAlignment: CrossAxisAlignment.start, return Column(
children: [ crossAxisAlignment:
// First Row: Toggle Buttons Row CrossAxisAlignment.start,
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Container( // First Row: Toggle Buttons Row
height: 36, const SizedBox(height: 10),
decoration: BoxDecoration( Row(
color: const Color(0xFFEAEAEA), mainAxisAlignment:
borderRadius: BorderRadius.circular(20), MainAxisAlignment.end,
), children: [
child: Row( Container(
children: [ height: 36,
toggleChip("Today"), decoration: BoxDecoration(
toggleChip("This Week"), color: const Color(0xFFEAEAEA),
], borderRadius:
), BorderRadius.circular(20),
), ),
], child: Row(
), children: [
const SizedBox(height: 20), toggleChip("Today"),
toggleChip("This Week"),
// Second Row: Domestic & International and Status ],
isDesktop ),
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
blurRadius: 5,
offset: Offset(0, 2),
),
],
), ),
padding: const EdgeInsets.all(15), ],
child: Row( ),
const SizedBox(height: 20),
// Second Row: Domestic & International and Status
isDesktop
? Row(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
...typeData.map((item) { Expanded(
return Expanded( flex: 2,
child: Column( child: Container(
children: [ decoration: BoxDecoration(
buildTopCard( color: Colors.white,
color: item['value'] == "Domestic" borderRadius:
? Color(0xFF0DB04B) BorderRadius.circular(
: Color(0xFF004A8E), 12,
label: item['value'], ),
count: item['count'], boxShadow: [
bgColor: item['value'] == "Domestic" BoxShadow(
? const Color(0xFFD6FBE4) color: Colors.blueGrey,
: const Color(0xFFD9E8FF), blurRadius: 5,
offset: Offset(0, 2),
), ),
], ],
), ),
); padding: const EdgeInsets.all(
}).toList(), 15,
], ),
), child: Row(
), children: [
), ...typeData.map((item) {
const SizedBox(width: 20), return Expanded(
Expanded( child: Column(
flex: 3, children: [
child: Container( buildTopCard(
decoration: BoxDecoration( color:
color: Colors.white, item['value'] ==
borderRadius: BorderRadius.circular(12), "Domestic"
boxShadow: [ ? Color(
BoxShadow( 0xFF0DB04B,
color: Colors.blueGrey, )
blurRadius: 5, : Color(
offset: Offset(0, 2), 0xFF004A8E,
), ),
], label:
), item['value'],
padding: const EdgeInsets.all(15), count:
child: Column( item['count'],
crossAxisAlignment: CrossAxisAlignment.start, bgColor:
children: [ item['value'] ==
Text( "Domestic"
"Status", ? const Color(
style: GoogleFonts.poppins( 0xFFD6FBE4,
fontSize: 19, )
color: Colors.black87, : const Color(
fontWeight: FontWeight.bold, 0xFFD9E8FF,
),
),
],
),
);
}).toList(),
],
),
), ),
), ),
const SizedBox(height: 10), const SizedBox(width: 20),
Row( Expanded(
mainAxisAlignment: MainAxisAlignment.spaceAround, flex: 3,
children: [ child: Container(
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(), decoration: BoxDecoration(
], color: Colors.white,
borderRadius:
BorderRadius.circular(
12,
),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
blurRadius: 5,
offset: Offset(0, 2),
),
],
),
padding: const EdgeInsets.all(
15,
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
"Status",
style:
GoogleFonts.poppins(
fontSize: 19,
color:
Colors
.black87,
fontWeight:
FontWeight
.bold,
),
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceAround,
children: [
...statusData
.map(
(
item,
) => statusCard(
item['value'],
item['count'],
isDesktop,
),
)
.toList(),
],
),
],
),
),
), ),
], ],
), )
), : Column(
), crossAxisAlignment:
], CrossAxisAlignment.start,
) children: [
: Column( Container(
crossAxisAlignment: CrossAxisAlignment.start, decoration: BoxDecoration(
children: [ color: Colors.white,
Container( borderRadius:
decoration: BoxDecoration( BorderRadius.circular(12),
color: Colors.white, boxShadow: [
borderRadius: BorderRadius.circular(12), BoxShadow(
boxShadow: [ color: Colors.blueGrey,
BoxShadow( blurRadius: 5,
color: Colors.blueGrey, offset: Offset(0, 2),
blurRadius: 5,
offset: Offset(0, 2),
),
],
),
padding: const EdgeInsets.all(15),
child: Row(
children: [
...typeData.map((item) {
return Expanded(
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),
), ),
], ],
), ),
); padding: const EdgeInsets.all(
}).toList(), 15,
], ),
), child: Row(
), children: [
const SizedBox(height: 20), ...typeData.map((item) {
Container( return Expanded(
decoration: BoxDecoration( child: Column(
color: Colors.white, children: [
borderRadius: BorderRadius.circular(12), buildTopCard(
boxShadow: [ color:
BoxShadow( item['value'] ==
color: Colors.blueGrey, "Domestic"
blurRadius: 5, ? const Color(
offset: Offset(0, 2), 0xFF0DB04B,
), )
], : const Color(
), 0xFF004A8E,
padding: const EdgeInsets.all(15), ),
child: Column( label:
crossAxisAlignment: CrossAxisAlignment.start, item['value'],
children: [ count:
Text( item['count'],
"Status", bgColor:
style: GoogleFonts.poppins( item['value'] ==
fontSize: 19, "Domestic"
color: Colors.black87, ? const Color(
fontWeight: FontWeight.bold, 0xFFD6FBE4,
)
: const Color(
0xFFD9E8FF,
),
),
],
),
);
}).toList(),
],
),
), ),
), const SizedBox(height: 20),
const SizedBox(height: 23), Container(
Wrap( decoration: BoxDecoration(
spacing: 10, color: Colors.white,
runSpacing: 10, borderRadius:
children: [ BorderRadius.circular(12),
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(), boxShadow: [
], BoxShadow(
), color: Colors.blueGrey,
], blurRadius: 5,
), offset: Offset(0, 2),
), ),
], ],
), ),
padding: const EdgeInsets.all(
15,
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Status",
style:
GoogleFonts.poppins(
fontSize: 19,
color:
Colors.black87,
fontWeight:
FontWeight.bold,
),
),
const SizedBox(height: 23),
Wrap(
spacing: 10,
runSpacing: 10,
children: [
...statusData
.map(
(
item,
) => statusCard(
item['value'],
item['count'],
isDesktop,
),
)
.toList(),
],
),
],
),
),
],
),
const SizedBox(height: 20), const SizedBox(height: 20),
// Third Row: Flight, Accommodation, Forex // Third Row: Flight, Accommodation, Forex
isDesktop isDesktop
? Row( ? Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
children: [ CrossAxisAlignment.start,
Expanded(child: buildCategoryCard("Flight", Icons.flight, statusLabels, flightData)), children: [
const SizedBox(width: 10), Expanded(
Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined, statusLabels, accommodationData)), child: buildCategoryCard(
const SizedBox(width: 10), "Flight",
Expanded(child: buildCategoryCard("Forex", Icons.attach_money, statusLabels, forexData)), Icons.flight,
statusLabels,
flightData,
),
),
const SizedBox(width: 10),
Expanded(
child: buildCategoryCard(
"Accomodation",
Icons.hotel_outlined,
statusLabels,
accommodationData,
),
),
const SizedBox(width: 10),
Expanded(
child: buildCategoryCard(
"Forex",
Icons.attach_money,
statusLabels,
forexData,
),
),
],
)
: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: buildCategoryCard(
"Flight",
Icons.flight,
statusLabels,
flightData,
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: buildCategoryCard(
"Accomodation",
Icons.hotel_outlined,
statusLabels,
accommodationData,
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: buildCategoryCard(
"Forex",
Icons.attach_money,
statusLabels,
forexData,
),
),
],
),
const SizedBox(height: 20),
],
),
], ],
) );
: Column( },
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [
Row(
children: [
Expanded(child: buildCategoryCard("Flight", Icons.flight, statusLabels, flightData)),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined, statusLabels, accommodationData)),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(child: buildCategoryCard("Forex", Icons.attach_money, statusLabels, forexData)),
],
),
const SizedBox(height: 20),
],
),
],
);
},
) ,
], ],
), ),
), ),

File diff suppressed because it is too large Load Diff

View File

@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.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 List<Map<String, dynamic>> accommodationList;
final Function(bool, Map<String, dynamic>, String) onOpen; final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteAccommodation; final Function(Map<String, dynamic>) onDeleteAccommodation;
final Function(String, bool) onAddNew; final Function(String, bool) onAddNew;
final bool isViewMode; final bool isViewMode;
@ -19,12 +20,57 @@ class AccomodationListWidget extends StatelessWidget {
required this.isViewMode, 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDesktop = MediaQuery.of(context).size.width > 1024; final isDesktop = MediaQuery.of(context).size.width > 1024;
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container( child: Container(
margin: const EdgeInsets.only(top: 16.0), margin: const EdgeInsets.only(top: 16.0),
child: Column( child: Column(
@ -34,7 +80,7 @@ class AccomodationListWidget extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop) && accommodationList.isNotEmpty) if ((!isDesktop) && widget.accommodationList.isNotEmpty)
Text( Text(
" ", " ",
style: const TextStyle( style: const TextStyle(
@ -44,17 +90,19 @@ class AccomodationListWidget extends StatelessWidget {
), ),
MouseRegion( MouseRegion(
cursor: isViewMode cursor:
? SystemMouseCursors.forbidden widget.isViewMode
: SystemMouseCursors.click, ? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: isViewMode onTap:
? null widget.isViewMode
: () { ? null
print("New data"); : () {
onAddNew("Accomodation", true); print("New data");
}, widget.onAddNew("Accomodation", true);
},
child: Row( child: Row(
mainAxisSize: mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely MainAxisSize.min, // Ensures content fits nicely
@ -68,7 +116,7 @@ class AccomodationListWidget extends StatelessWidget {
Icons.add_circle_sharp, Icons.add_circle_sharp,
size: 30, size: 30,
color: Color(0xFF114D8B), color: Color(0xFF114D8B),
) ),
// Container( // Container(
// decoration: BoxDecoration( // decoration: BoxDecoration(
// shape: BoxShape.circle, // shape: BoxShape.circle,
@ -147,9 +195,9 @@ class AccomodationListWidget extends StatelessWidget {
], ],
), ),
const SizedBox(height: 16), 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) { Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList = 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"); print("filteredList- $filteredList");
// String formatDate(String dateString) { // String formatDate(String dateString) {
@ -191,8 +241,11 @@ class AccomodationListWidget extends StatelessWidget {
if (hour == 24 && minute == 0) { if (hour == 24 && minute == 0) {
// 24:00 is treated as 00:00 on the next day // 24:00 is treated as 00:00 on the next day
dateTime = DateTime(now.year, now.month, now.day) dateTime = DateTime(
.add(const Duration(days: 1)); now.year,
now.month,
now.day,
).add(const Duration(days: 1));
} else { } else {
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw FormatException("Invalid hour or minute"); throw FormatException("Invalid hour or minute");
@ -235,14 +288,18 @@ class AccomodationListWidget extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50, // color: Colors.orange.shade50,
color: Colors.white, color: isDesktop ? Colors.white : thridColor,
boxShadow: [ // color: Colors.white,
BoxShadow( boxShadow:
color: Colors.black12, isDesktop
blurRadius: 3, ? [
offset: Offset(0, 1), BoxShadow(
), color: Colors.black12,
], blurRadius: 3,
offset: Offset(0, 1),
),
]
: [],
border: Border( border: Border(
top: BorderSide( top: BorderSide(
color: Colors.white70, // Change color to match your theme color: Colors.white70, // Change color to match your theme
@ -251,7 +308,7 @@ class AccomodationListWidget extends StatelessWidget {
), ),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(12), padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -261,26 +318,28 @@ class AccomodationListWidget extends StatelessWidget {
Text( Text(
item["hotel_name"]!, item["hotel_name"]!,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight:
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),) isDesktop ? FontWeight.w800 : FontWeight.w500,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
), ),
Spacer(), Spacer(),
GestureDetector( GestureDetector(
onTap: () => onOpen(true, item, "Accomodation"), onTap: () => widget.onOpen(true, item, "Accomodation"),
child: Tooltip( child: Tooltip(
message: 'Edit Accomodation Details', message: 'Edit Accomodation Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B), color: isDesktop ? Color(0xFF114D8B) : Colors.black87,
), ),
), ),
), ),
SizedBox(width: 10), SizedBox(width: 10),
GestureDetector( GestureDetector(
onTap: () => onDeleteAccommodation(item), onTap: () => widget.onDeleteAccommodation(item),
child: Tooltip( child: Tooltip(
message: 'Delete Accommodation Details', message: 'Delete Accommodation Details',
child: Image.asset( child: Image.asset(
@ -293,170 +352,176 @@ class AccomodationListWidget extends StatelessWidget {
), ),
], ],
), ),
Divider( // Divider(color: Colors.blueGrey.shade50),
color: Colors.blueGrey.shade50,
),
SizedBox(height: 4), SizedBox(height: 4),
isDesktop isDesktop
? Row( ? Row(
children: [ children: [
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
" DestinationCity", " DestinationCity",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)), Expanded(
Expanded( flex: 2,
flex: 2, child: Text(
child: Text( " Check (in) ",
" Check (in) ", style: GoogleFonts.poppins(fontSize: 11),
style: GoogleFonts.poppins( ),
fontSize: 11, ),
), Expanded(
)), flex: 2,
Expanded( child: Text(
flex: 2, " Check (out) ",
child: Text( style: GoogleFonts.poppins(fontSize: 11),
" Check (out) ", ),
style: GoogleFonts.poppins( ),
fontSize: 11, Expanded(
), flex: 2,
)), child: Text(
Expanded( " Comments",
flex: 2, style: GoogleFonts.poppins(fontSize: 11),
child: Text( ),
" Comments", ),
style: GoogleFonts.poppins( ],
fontSize: 11, )
),
)),
],
)
: SizedBox.shrink(), : SizedBox.shrink(),
isDesktop isDesktop
? Row( ? Row(
children: [ children: [
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
item["destination_city"], item["destination_city"],
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
),
), ),
), ),
SizedBox(width: 10), ),
Expanded( SizedBox(width: 10),
flex: 2, Expanded(
child: Text( flex: 2,
"${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}", child: Text(
style: GoogleFonts.poppins( "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
fontSize: 12, style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 12,
), fontWeight: FontWeight.w600,
), ),
), ),
SizedBox(width: 10), ),
Expanded( SizedBox(width: 10),
flex: 2, Expanded(
child: Text( flex: 2,
"${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}", child: Text(
style: GoogleFonts.poppins( "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
fontSize: 12, style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 12,
), fontWeight: FontWeight.w600,
), ),
), ),
SizedBox(width: 10), ),
Expanded( SizedBox(width: 10),
flex: 2, Expanded(
child: _buildComments( flex: 2,
"Comments:", item["comments"] ?? "N/A"), child: _buildComments(
"Comments:",
item["comments"] ?? "N/A",
), ),
], ),
) ],
: Column( )
: Container(
color: Colors.white,
padding: EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Wrap( _buildRow(
spacing: 20, // horizontal space between items "Destination City",
runSpacing: 10, // vertical space between rows item["destination_city"],
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"]!)}",
// ),
// ],
// ),
// ),
],
), ),
const SizedBox(height: 10), SizedBox(height: 5),
const Text( _buildDateTimeRow(
"Comment", "Check (in)",
style: TextStyle(fontWeight: FontWeight.w500), formatDate(item["checkin_date"]!),
formatTime(item["checkin_time"]!),
), ),
const SizedBox(height: 5), SizedBox(height: 5),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty) _buildDateTimeRow(
Container( "Check (out)",
width: double.infinity, formatDate(item["checkout_date"]!),
padding: const EdgeInsets.all(8), formatTime(item["checkout_time"]!),
decoration: BoxDecoration( ),
border: Border.all(color: Color(0xFF7098DD), width: 1), SizedBox(height: 5),
borderRadius: BorderRadius.circular(6), _buildRow("Comments:", item["comments"] ?? "N/A"),
), ],
child: Text( ),
item["comments"], ),
style: const TextStyle(fontSize: 12),
), // Column(
) // crossAxisAlignment: CrossAxisAlignment.start,
else // children: [
const Text( "N/A", style: TextStyle(fontSize: 12), ), // Wrap(
], // spacing: 20, // horizontal space between items
) // runSpacing: 10, // vertical space between rows
// Column( // children: [
// crossAxisAlignment: CrossAxisAlignment.start, // _buildInfoColumn("City", item["destination_city"]),
// children: [ // _buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"),
// _buildRow("City:", item["destination_city"]), // _buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"),
// SizedBox(width: 10), // // City - long name handled with flexible space
// SizedBox(width: 10), // // Expanded(
// _buildDateTimeRow( // // flex: 3,
// "Check-in:", // // child: _buildInfoColumn("City", item["destination_city"]),
// formatDate(item["checkin_date"]!), // // ),
// item["checkin_time"]!, //
// ), // // SizedBox(width: 8),
// SizedBox(width: 10), //
// _buildRow( // // Check In and Check Out stacked right side
// "Date(out):", formatDate(item["checkout_date"]!)), // // Expanded(
// SizedBox(width: 10), // // flex: 4,
// _buildRow("Comments:", item["comments"] ?? "N/A"), // // 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"]!)}",
// // ),
// // ],
// // ),
// // ),
// ],
// ),
// 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,31 +550,35 @@ class AccomodationListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: exceedsLimit child:
? Tooltip( exceedsLimit
message: wrapText(value, 50), ? Tooltip(
decoration: BoxDecoration( message: wrapText(value, 50),
color: Colors.grey.shade200, // Black background decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6), color: Colors.grey.shade200, // Black background
), borderRadius: BorderRadius.circular(6),
textStyle: ),
TextStyle(color: Colors.black), // Tooltip text color textStyle: TextStyle(
padding: EdgeInsets.all(8), color: Colors.black,
preferBelow: false, ), // Tooltip text color
child: Text(value.substring(0, limit) + "...", padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
overflow: TextOverflow.ellipsis), overflow: TextOverflow.ellipsis,
) ),
: Text( )
value, : Text(
style: GoogleFonts.poppins( value,
fontSize: 12, style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 12,
fontWeight: FontWeight.w600,
),
), ),
),
), ),
], ],
); );
@ -531,87 +600,92 @@ class AccomodationListWidget extends StatelessWidget {
SizedBox(height: 4), SizedBox(height: 4),
Text( Text(
value, value,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
fontSize: 12,
color: Colors.black87,
),
), ),
], ],
); );
} }
// Widget _buildRow(String title, String value) { Widget _buildRow(String title, String value) {
// // Define character limits based on title // Define character limits based on title
// Map<String, int> limits = { Map<String, int> limits = {
// // "Special Request:": 30, // "Special Request:": 30,
// "Comments:": 10, "Comments:": 10,
// // Add more keys and limits if needed // 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),
// 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: TextStyle(fontSize: 12),
// overflow: TextOverflow.ellipsis),
// )
// : Text(
// value,
// style: TextStyle(fontSize: 12),
// ),
// ),
// ],
// );
// }
// Widget _buildDateTimeRow(String title, String date, String time) { int limit = limits[title] ?? 50; // Default limit if title not found
// return Row( bool exceedsLimit = value.length > limit;
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [ String wrapText(String text, int maxLineLength) {
// Text( final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
// title, return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
// style: GoogleFonts.poppins( }
// fontSize: 12,
// fontWeight: FontWeight.w600, return Row(
// ), crossAxisAlignment: CrossAxisAlignment.start,
// ),
// SizedBox(width: 8), children: [
// Expanded( SizedBox(
// child: Text( // color: Colors.yellowAccent.shade100,
// "$date, $time", width: 100,
// style: GoogleFonts.poppins( child: Expanded(
// fontSize: 12, 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
// ? 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: 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 'package:intl/intl.dart';
import '../../services/apiService.dart'; import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
class FlightListWidget extends StatefulWidget { class FlightListWidget extends StatefulWidget {
final bool hasAction; final bool hasAction;
@ -32,6 +33,9 @@ class FlightListWidget extends StatefulWidget {
class _FlightListWidgetState extends State<FlightListWidget> { class _FlightListWidgetState extends State<FlightListWidget> {
ApiService apiService = ApiService(); ApiService apiService = ApiService();
Color? layoutColor;
Color? secondColor;
Color? thridColor;
// late Map<String, String> countryMap; // late Map<String, String> countryMap;
Map<String, String> countryMap = {}; Map<String, String> countryMap = {};
@ -40,6 +44,36 @@ class _FlightListWidgetState extends State<FlightListWidget> {
void initState() { void initState() {
super.initState(); super.initState();
loadCountryList(); // Call your method here 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 { Future<void> loadCountryList() async {
@ -169,7 +203,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// ); // );
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container( child: Container(
margin: const EdgeInsets.only(top: 16.0), margin: const EdgeInsets.only(top: 16.0),
child: Column( child: Column(
@ -192,16 +227,18 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// Right side: either "Add" icon or nothing // Right side: either "Add" icon or nothing
if (widget.flightList.isNotEmpty) if (widget.flightList.isNotEmpty)
MouseRegion( MouseRegion(
cursor: widget.isViewMode cursor:
? SystemMouseCursors.forbidden widget.isViewMode
: SystemMouseCursors.click, ? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: widget.isViewMode onTap:
? null widget.isViewMode
: () { ? null
widget.onAddNew("Flight", true); : () {
print("New data"); widget.onAddNew("Flight", true);
}, print("New data");
},
child: Icon( child: Icon(
Icons.add_circle_sharp, Icons.add_circle_sharp,
size: 30, size: 30,
@ -210,7 +247,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
) )
else if (!isDesktop) else if (!isDesktop)
// Centered "No Data Found" message for mobile and empty list // Centered "No Data Found" message for mobile and empty list
Expanded( Expanded(
child: Center( child: Center(
child: Text( child: Text(
@ -223,8 +260,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
), ),
), ),
) ),
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@ -235,7 +271,6 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
), ),
); );
} }
Widget _buildData(BuildContext context, bool isDesktop) { Widget _buildData(BuildContext context, bool isDesktop) {
@ -347,22 +382,26 @@ class _FlightListWidgetState extends State<FlightListWidget> {
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
// color: isDesktop ? Colors.white : Color(0xFFFFF0F5),
color: isDesktop ? Colors.white : thridColor,
// color: Colors.orange.shade50, // color: Colors.orange.shade50,
color: Colors.white, // color: Colors.white,
boxShadow:
boxShadow: [ isDesktop
BoxShadow( ? [
color: Colors.black12, BoxShadow(
blurRadius: 2, color: Colors.black12,
offset: Offset(0, 2), // down blurRadius: 2,
), offset: Offset(0, 2), // down
// Top shadow ),
BoxShadow( // Top shadow
color: Colors.black12, BoxShadow(
blurRadius: 0.5, color: Colors.black12,
offset: Offset(0, -1), // up blurRadius: 0.5,
), offset: Offset(0, -1), // up
], ),
]
: [],
border: Border( border: Border(
top: BorderSide( top: BorderSide(
color: Colors.white70, // Change color to match your theme color: Colors.white70, // Change color to match your theme
@ -371,49 +410,56 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(12), padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Padding(
children: [ padding: const EdgeInsets.symmetric(horizontal: 2),
Text( child: Row(
tripTypeName ?? "N/A", children: [
style: GoogleFonts.poppins( Text(
fontSize: 14, tripTypeName ?? "N/A",
fontWeight: FontWeight.w800, style: GoogleFonts.poppins(
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74), fontSize: 14,
), fontWeight:
), isDesktop ? FontWeight.w800 : FontWeight.w500,
Spacer(), color: !isDesktop ? Colors.black : Color(0xFF575A74),
GestureDetector(
onTap: () => widget.onOpen(true, item, "Flight"), // Color(0xFF114D8B)
child: Tooltip(
message: 'Edit Flight Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), Spacer(),
SizedBox(width: 10), GestureDetector(
GestureDetector( onTap: () => widget.onOpen(true, item, "Flight"),
onTap: () => widget.onDeleteFlight(item), child: Tooltip(
child: Tooltip( message: 'Edit Flight Details',
message: 'Delete Flight Details', child: Image.asset(
child: Image.asset( 'assets/images/IconsImg/edit.png',
'assets/images/IconsImg/delete.png', width: 20,
width: 20, height: 15,
height: 15, color:
color: Colors.red, isDesktop ? Color(0xFF114D8B) : Colors.black87,
),
), ),
), ),
), SizedBox(width: 10),
], GestureDetector(
onTap: () => widget.onDeleteFlight(item),
child: Tooltip(
message: 'Delete Flight Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
],
),
), ),
Divider(color: Colors.blueGrey.shade50), // Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4), SizedBox(height: 4),
if (isDesktop) if (isDesktop)
Row( Row(
@ -600,10 +646,9 @@ class _FlightListWidgetState extends State<FlightListWidget> {
item["trips"] != null && item["trips"] != null &&
item["trips"].isNotEmpty) item["trips"].isNotEmpty)
...item["trips"].map<Widget>((trip) { ...item["trips"].map<Widget>((trip) {
String fromPlaceCountry = String fromPlaceCountry =
countryMap[trip["from_place"]?.toString()] ?? countryMap[trip["from_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
final parts = fromPlaceCountry.split('\n'); final parts = fromPlaceCountry.split('\n');
final cityAndCode = parts[0]; final cityAndCode = parts[0];
@ -618,7 +663,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
String toPlaceCountry = String toPlaceCountry =
countryMap[trip["to_place"]?.toString()] ?? countryMap[trip["to_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
final toparts = toPlaceCountry.split('\n'); final toparts = toPlaceCountry.split('\n');
final tocityAndCode = toparts[0]; final tocityAndCode = toparts[0];
@ -631,41 +676,44 @@ class _FlightListWidgetState extends State<FlightListWidget> {
final tocity = tocityMatch?.group(1) ?? ''; final tocity = tocityMatch?.group(1) ?? '';
final tocode = tocityMatch?.group(2) ?? ''; final tocode = tocityMatch?.group(2) ?? '';
// return Padding( return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0), padding: const EdgeInsets.symmetric(vertical: 6.0),
// child: Container( child: Container(
// decoration: BoxDecoration( decoration: BoxDecoration(
// border: Border.all(color: Colors.grey.shade300), border: Border.all(color: Colors.grey.shade300),
// borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
// color: Colors.grey.shade50, color: Colors.grey.shade50,
// ), ),
// padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
// child: Column( child: Column(
// crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
// children: [ children: [
// _buildKeyValueRow( _buildKeyValueRow(
// "Class", "Class",
// getRequestForClass(trip["class"].toString()) ?? getRequestForClass(trip["class"].toString()) ??
// "N/A", "N/A",
// ), ),
// _buildKeyValueRow( _buildKeyValueRow(
// "Sector", "From",
// "$fromcity ($fromcode), $fromairport$tocity ($tocode), $toairport", "$fromcity ($fromcode), $fromairport ",
// ), ),
// _buildKeyValueRow(
// _buildKeyValueRow( "To",
// "Date", "$tocity ($tocode), $toairport",
// formatDate(trip["date"] ?? ""), ),
// ),
// _buildKeyValueRow(
// "Time",
// formatTime(trip["time"] ?? ""),
// ),
// ],
// ),
// ),
// );
_buildKeyValueRow(
"Date",
formatDate(trip["date"] ?? ""),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
),
],
),
),
);
// return Padding( // return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0), // padding: const EdgeInsets.symmetric(vertical: 6.0),
@ -701,9 +749,13 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// ), // ),
// ), // ),
// const Padding( // const Padding(
// padding: EdgeInsets.symmetric(horizontal: 6), // padding: EdgeInsets.symmetric(
// horizontal: 6,
// ),
// child: Image( // child: Image(
// image: AssetImage('assets/images/IconsImg/Frame.png'), // image: AssetImage(
// 'assets/images/IconsImg/Frame.png',
// ),
// width: 18, // width: 18,
// height: 18, // height: 18,
// ), // ),
@ -738,68 +790,67 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// ), // ),
// ); // );
return Padding( // return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0), // padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Container( // child: Container(
child: Column( // child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
Wrap( // Wrap(
crossAxisAlignment: WrapCrossAlignment.center, // crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4, // spacing: 4,
runSpacing: 4, // runSpacing: 4,
children: [ // children: [
Text( // Text(
'${getRequestForClass(trip["class"].toString()) ?? "N/A"} (', // '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (',
style: const TextStyle( // style: const TextStyle(
fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
fontSize: 14, // fontSize: 14,
color: Colors.black87, // color: Colors.black87,
), // ),
), // ),
Text( // Text(
fromcode, // fromcode,
style: const TextStyle( // style: const TextStyle(
fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
fontSize: 14, // fontSize: 14,
color: Colors.black87, // color: Colors.black87,
), // ),
), // ),
const Padding( // const Padding(
padding: EdgeInsets.symmetric(horizontal: 4), // padding: EdgeInsets.symmetric(horizontal: 4),
child: Image( // child: Image(
image: AssetImage('assets/images/IconsImg/Frame.png'), // image: AssetImage('assets/images/IconsImg/Frame.png'),
width: 18, // width: 18,
height: 18, // height: 18,
), // ),
), // ),
Text( // Text(
'$tocode)', // '$tocode)',
style: const TextStyle( // style: const TextStyle(
fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
fontSize: 14, // fontSize: 14,
color: Colors.black87, // color: Colors.black87,
), // ),
), // ),
], // ],
), // ),
const SizedBox(height: 6), // const SizedBox(height: 6),
Align( // Align(
alignment: Alignment.centerRight, // alignment: Alignment.centerRight,
child: Text( // child: Text(
'${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}', // '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}',
textAlign: TextAlign.right, // textAlign: TextAlign.right,
style: const TextStyle( // style: const TextStyle(
fontSize: 13, // fontSize: 13,
color: Colors.black87, // color: Colors.black87,
), // ),
), // ),
), // ),
], // ],
), // ),
), // ),
); // );
}).toList(), }).toList(),
], ],
), ),
@ -816,12 +867,12 @@ class _FlightListWidgetState extends State<FlightListWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox( SizedBox(
width: 80, // adjust width as needed width: 70, // adjust width as needed
child: Text( child: Text(
"$key:", "$key",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, 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 'package:intl/intl.dart';
import '../../services/apiService.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 List<Map<String, dynamic>> forexList;
final Function(bool, Map<String, dynamic>, String) onOpen; final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteForex; final Function(Map<String, dynamic>) onDeleteForex;
@ -16,15 +17,60 @@ class ForexListWidget extends StatelessWidget {
final Function(String, bool) onAddNew; final Function(String, bool) onAddNew;
final bool isViewMode; final bool isViewMode;
const ForexListWidget( const ForexListWidget({
{super.key, super.key,
required this.forexList, required this.forexList,
required this.onOpen, required this.onOpen,
required this.onDeleteForex, required this.onDeleteForex,
required this.apiCountryData, required this.apiCountryData,
required this.onAddNew, required this.onAddNew,
required this.apiData, 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -32,7 +78,8 @@ class ForexListWidget extends StatelessWidget {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding:
isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0),
child: Container( child: Container(
margin: const EdgeInsets.only(top: 16.0), margin: const EdgeInsets.only(top: 16.0),
child: Column( child: Column(
@ -135,26 +182,23 @@ class ForexListWidget extends StatelessWidget {
// ], // ],
// ), // ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop) // Scroll behavior based on device
_buildData(context, isDesktop),
], ],
), ),
), ),
); );
} }
Widget _buildData( Widget _buildData(BuildContext context, bool isDesktop) {
BuildContext context,
bool isDesktop,
) {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
List<Map<String, dynamic>> filteredList = 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"); print("filteredList- $filteredList");
List<dynamic> visatypeList = apiData?['visa_type_of_visa'] ?? []; List<dynamic> visatypeList = widget.apiData?['visa_type_of_visa'] ?? [];
List<dynamic> countryList = apiCountryData ?? []; List<dynamic> countryList = widget.apiCountryData ?? [];
String getRequestForVisa(String? specialRequestKey) { String getRequestForVisa(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A"; if (specialRequestKey == null) return "N/A";
@ -209,8 +253,11 @@ class ForexListWidget extends StatelessWidget {
if (hour == 24 && minute == 0) { if (hour == 24 && minute == 0) {
// 24:00 is treated as 00:00 on the next day // 24:00 is treated as 00:00 on the next day
dateTime = DateTime(now.year, now.month, now.day) dateTime = DateTime(
.add(const Duration(days: 1)); now.year,
now.month,
now.day,
).add(const Duration(days: 1));
} else { } else {
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw FormatException("Invalid hour or minute"); throw FormatException("Invalid hour or minute");
@ -231,27 +278,34 @@ class ForexListWidget extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = filteredList[index]; final item = filteredList[index];
final double transport = double.tryParse(item["transport"] ?? "0") ?? 0; 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 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 double calculatedValue = transport + accommodation + telephone;
final String calculatedOtherExpenses = calculatedValue.toStringAsFixed(0); final String calculatedOtherExpenses = calculatedValue.toStringAsFixed(
0,
);
final double finalTotal = calculatedValue + perdiemAmount; final double finalTotal = calculatedValue + perdiemAmount;
return Container( return Container(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50, // color: Colors.orange.shade50,
color: Colors.white, // color: Colors.white,
boxShadow: [ color: isDesktop ? Colors.white : thridColor,
BoxShadow( boxShadow:
color: Colors.black12, isDesktop
blurRadius: 3, ? [
offset: Offset(0, 1), BoxShadow(
), color: Colors.black12,
], blurRadius: 3,
offset: Offset(0, 1),
),
]
: [],
border: Border( border: Border(
top: BorderSide( top: BorderSide(
color: Colors.white70, // Change color to match your theme color: Colors.white70, // Change color to match your theme
@ -260,7 +314,7 @@ class ForexListWidget extends StatelessWidget {
), ),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(12), padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -271,12 +325,12 @@ class ForexListWidget extends StatelessWidget {
getRequestForCountry(item["country_code"]!.toString()), getRequestForCountry(item["country_code"]!.toString()),
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w600,
), ),
), ),
Spacer(), Spacer(),
GestureDetector( GestureDetector(
onTap: () => onOpen(true, item, "Forex"), onTap: () => widget.onOpen(true, item, "Forex"),
child: Tooltip( child: Tooltip(
message: 'Edit Forex Details', message: 'Edit Forex Details',
child: Image.asset( child: Image.asset(
@ -284,7 +338,7 @@ class ForexListWidget extends StatelessWidget {
width: 20, width: 20,
height: 15, height: 15,
// color: Color(0xFF114D8B), // color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74) color: !isDesktop ? Colors.black : Color(0xFF575A74),
), ),
), ),
), ),
@ -303,287 +357,307 @@ class ForexListWidget extends StatelessWidget {
// ), // ),
item['forex_id'] != null item['forex_id'] != null
? IconButton( ? IconButton(
icon: Icon(Icons.download, icon: Icon(
color: Color(0xFF114D8B), size: 18), Icons.download,
onPressed: () { color: Color(0xFF114D8B),
print("PDF- ${item['forex_id']}"); size: 18,
final forexIdString = item['forex_id']; ),
final id = int.tryParse(forexIdString ?? ''); onPressed: () {
print("PDF- ${item['forex_id']}");
final forexIdString = item['forex_id'];
final id = int.tryParse(forexIdString ?? '');
if (id != null) { if (id != null) {
apiService.getForexPdfDownload(id); apiService.getForexPdfDownload(id);
} else { } else {
print("Invalid forex_id: $forexIdString"); print("Invalid forex_id: $forexIdString");
} }
}, },
) )
: SizedBox.shrink(), // or Container() : SizedBox.shrink(), // or Container()
], ],
), ),
Divider( Divider(color: Colors.blueGrey.shade50),
color: Colors.blueGrey.shade50, // SizedBox(height: 4),
),
SizedBox(height: 4),
isDesktop isDesktop
? Row( ? Row(
children: [ children: [
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
"Currency", "Currency",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)), Expanded(
Expanded( flex: 2,
flex: 2, child: Text(
child: Text( " Duration",
" Duration", style: GoogleFonts.poppins(fontSize: 11),
style: GoogleFonts.poppins( ),
fontSize: 11, ),
), Expanded(
)), flex: 2,
Expanded( child: Text(
flex: 2, " Time Period ",
child: Text( style: GoogleFonts.poppins(fontSize: 11),
" Time Period ", ),
style: GoogleFonts.poppins( ),
fontSize: 11, // Expanded(
), // flex: 2,
)), // child: Text(
// Expanded( // " Total ",
// flex: 2, // style: TextStyle(
// child: Text( // fontSize: 11, fontFamily: "Archivo"),
// " Total ", // )),
// style: TextStyle( Expanded(
// fontSize: 11, fontFamily: "Archivo"), flex: 2,
// )), child: Text(
Expanded( " Perdiem ",
flex: 2, style: GoogleFonts.poppins(fontSize: 11),
child: Text( ),
" Perdiem ", ),
style: GoogleFonts.poppins( Expanded(
fontSize: 11, flex: 2,
), child: Text(
)), " Others ",
Expanded( style: GoogleFonts.poppins(fontSize: 11),
flex: 2, ),
child: Text( ),
" Others ", Expanded(
style: GoogleFonts.poppins( flex: 2,
fontSize: 11, child: Text(
), " Total ",
)), style: GoogleFonts.poppins(fontSize: 11),
Expanded( ),
flex: 2, ),
child: Text( Expanded(
" Total ", flex: 2,
style: GoogleFonts.poppins( child: Text(
fontSize: 11, " Cash ",
), style: GoogleFonts.poppins(fontSize: 11),
)), ),
Expanded( ),
flex: 2, Expanded(
child: Text( flex: 2,
" Cash ", child: Text(
style: GoogleFonts.poppins( " Card ",
fontSize: 11, style: GoogleFonts.poppins(fontSize: 11),
), ),
)), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
" Card ", " Comments",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)), ],
Expanded( )
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
],
)
: SizedBox.shrink(), : SizedBox.shrink(),
isDesktop isDesktop
? Row( ? Row(
children: [
Expanded(
flex: 2,
child: Text(
item["currency"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["duration"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$perdiemAmount",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$calculatedOtherExpenses",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$finalTotal",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["deposit_on_cash"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["deposit_on_card"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: _buildComments(
"Comments:", item["comments"] ?? "N/A"),
),
],
): 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: [ children: [
_infoBlock("Country code", item["country_code"] ?? "N/A"), Expanded(
_infoBlock("Currency", item["currency"] ?? "N/A"), flex: 2,
_infoBlock("Total Amount", item["total_amount"]?.toString() ?? "0"), child: Text(
item["currency"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["duration"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$perdiemAmount",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$calculatedOtherExpenses",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"$finalTotal",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["deposit_on_cash"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
item["deposit_on_card"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: _buildComments(
"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 : Container(
const Text( "N/A", style: TextStyle(fontSize: 12), ), color: Colors.white,
], padding: const EdgeInsets.all(4.0),
), child: Column(
// old code crossAxisAlignment: CrossAxisAlignment.start,
// : Column( children: [
// crossAxisAlignment: CrossAxisAlignment.start, _buildRow("Currency", item["currency"]),
// children: [ SizedBox(height: 2),
// _buildRow( _buildRow("Duration", item["duration"]),
// "Currency:", SizedBox(height: 2),
// item["currency"], _buildRow(
// ), "Time Period",
// // SizedBox(height: 6), "${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}",
// _buildRow( // "${item["start_date"]!} - ${item["end_date"]!}",
// "Duration:", ),
// item["duration"], SizedBox(height: 2),
// ), _buildRow("Perdiem", "$perdiemAmount"),
// // SizedBox(height: 6), SizedBox(height: 2),
// _buildRow("StartDate:", item["start_date"]!), _buildRow("Others", "$calculatedOtherExpenses"),
// _buildRow("EndDate:", item["end_date"]!), SizedBox(height: 2),
// _buildRow("Perdiem:", "$perdiemAmount",), _buildRow("Total", "$finalTotal"),
// _buildRow("Others:", "$calculatedOtherExpenses"), SizedBox(height: 2),
// _buildRow("Total:", "$finalTotal"), _buildRow("Cash", item["deposit_on_cash"]!),
// _buildRow("Cash:", item["deposit_on_cash"]!), SizedBox(height: 2),
// _buildRow("Card:", item["deposit_on_card"]!), _buildRow("Card", item["deposit_on_card"]!),
// _buildRow("Comments:", item["comments"] ?? "N/A"), SizedBox(height: 2),
// ], _buildRow("Comments", item["comments"] ?? "N/A"),
// ), ],
),
),
// 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",
// ),
// ],
// ),
// 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,31 +686,35 @@ class ForexListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: exceedsLimit child:
? Tooltip( exceedsLimit
message: wrapText(value, 50), ? Tooltip(
decoration: BoxDecoration( message: wrapText(value, 50),
color: Colors.grey.shade200, // Black background decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6), color: Colors.grey.shade200, // Black background
), borderRadius: BorderRadius.circular(6),
textStyle: ),
TextStyle(color: Colors.black), // Tooltip text color textStyle: TextStyle(
padding: EdgeInsets.all(8), color: Colors.black,
preferBelow: false, ), // Tooltip text color
child: Text(value.substring(0, limit) + "...", padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
overflow: TextOverflow.ellipsis), overflow: TextOverflow.ellipsis,
) ),
: Text( )
value, : Text(
style: GoogleFonts.poppins( value,
fontSize: 12, style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 12,
fontWeight: FontWeight.w600,
),
), ),
),
), ),
], ],
); );
@ -660,10 +738,7 @@ class ForexListWidget extends StatelessWidget {
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
value, value,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
fontSize: 12,
color: Colors.black87,
),
), ),
], ],
), ),
@ -671,60 +746,59 @@ class ForexListWidget extends StatelessWidget {
); );
} }
// Widget _buildRow(String title, String value) { Widget _buildRow(String title, String value) {
// // Define character limits based on title // Define character limits based on title
// Map<String, int> limits = { Map<String, int> limits = {
// // "Special Request:": 30, // "Special Request:": 30,
// "Comments:": 10, "Comments:": 10,
// // Add more keys and limits if needed // 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,
// ),
// ),
// ),
// ],
// );
// }
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( margin: EdgeInsets.only(
top: 40, top: 40,
), // Push it down to make room for the tab bar ), // 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( decoration: BoxDecoration(
color: Colors.white, // Card background color: Colors.white, // Card background
// color: Colors.yellow.shade50, // Card background // color: Colors.yellow.shade50, // Card background

View File

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

File diff suppressed because it is too large Load Diff

View File

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