Merge branch 'main' of bitbucket.org:venbainformationtechnology/ts-tat

This commit is contained in:
venba-Inspriron-3558 2025-08-04 18:11:44 +05:30
commit 2dee35c37c
32 changed files with 11526 additions and 9797 deletions

File diff suppressed because it is too large Load Diff

View File

@ -373,7 +373,15 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
// color: Colors.amber,
),
child: Padding(
padding: const EdgeInsets.all(1.0),
padding:
isDesktop
? const EdgeInsets.only(
top: 15,
bottom: 15,
left: 20,
right: 20,
)
: const EdgeInsets.only(top: 15, bottom: 15, left: 5, right: 5),
child: Container(
// padding: const EdgeInsets.all(10.0),
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
@ -387,22 +395,28 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
'Trips',
style: GoogleFonts.poppins(
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Colors.black,
Padding(
padding:
isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.only(left: 14.0),
child: Row(
children: [
Text(
'Trips',
style: GoogleFonts.poppins(
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Colors.black,
),
// style: TextStyle(
// fontFamily: "Inter",
// fontSize: isDesktop ? 16 : 14,
// fontWeight: FontWeight.w600,
// color: Color(0xFF212121))
),
// style: TextStyle(
// fontFamily: "Inter",
// fontSize: isDesktop ? 16 : 14,
// fontWeight: FontWeight.w600,
// color: Color(0xFF212121))
),
],
],
),
),
Spacer(),
@ -447,7 +461,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
),
// SizedBox(width: 16),
Spacer(),
// Spacer(),
// ElevatedButton(
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
@ -473,6 +487,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
if (!isDesktop) const SizedBox(height: 10),
if (!isDesktop)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.85,
@ -694,14 +709,18 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
),
DataCell(
Text(
plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
SizedBox(
width: 130,
child: Text(
plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
maxLines: 2,
// overflow: TextOverflow.ellipsis,
),
softWrap: true,
overflow: TextOverflow.ellipsis,
),
),
@ -870,6 +889,34 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
);
},
),
if (plan.statusValue ==
"Approved" &&
plan.forexId !=
null &&
plan.forexId !=
'')
IconButton(
icon: Icon(
Icons
.monetization_on_outlined,
color: Color(
0xFF475569,
),
size: 18,
),
tooltip:
'Download Forex PDF',
onPressed: () {
Navigator.pop(
context,
);
apiService
.getForexPdfDownload(
plan.forexId,
);
},
),
IconButton(
icon: const Icon(
Icons.comment,
@ -1003,6 +1050,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
PlanPopupMenu(
plan: plan,
deletePlan: deletePlan,
apiService: apiService,
layoutColor: layoutColor,
),

File diff suppressed because it is too large Load Diff

View File

@ -52,14 +52,14 @@ class StatusDashboardState extends State<StatusDashboard> {
"Partially Approved",
"Approved",
"Rejected",
"Cancelled"
"Cancelled",
];
// Extract counts for "Both" section
List<int> getStatusValues(Map<String, dynamic> serviceData) {
final both = serviceData['Both'] ?? {};
return statusLabels.map((label) => (both[label] ?? 0) as int).toList();
}
// Extract counts for "Both" section
List<int> getStatusValues(Map<String, dynamic> serviceData) {
final both = serviceData['Both'] ?? {};
return statusLabels.map((label) => (both[label] ?? 0) as int).toList();
}
@override
void initState() {
@ -150,8 +150,7 @@ class StatusDashboardState extends State<StatusDashboard> {
checkbackbutton();
});
setState(() {
isLoading = true;
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"
? statusBasedTodayCount
: statusBasedWeeklyCount ;
typeData =
selectedView == "Today" ? typeBasedTodayCount : typeBasedWeeklyCount;
statusData =
selectedView == "Today"
? statusBasedTodayCount
: statusBasedWeeklyCount;
flightData = selectedView == "Today"
? getStatusValues(todayBasedCount['flight'] ?? {})
: getStatusValues(weekBasedCount['flight'] ?? {});
accommodationData = selectedView == "Today"
? getStatusValues(todayBasedCount['acomodation'] ?? {})
: getStatusValues(weekBasedCount['acomodation'] ?? {});
forexData = selectedView == "Today"
? getStatusValues(todayBasedCount['forex'] ?? {})
: getStatusValues(weekBasedCount['forex'] ?? {});
flightData =
selectedView == "Today"
? getStatusValues(todayBasedCount['flight'] ?? {})
: getStatusValues(weekBasedCount['flight'] ?? {});
accommodationData =
selectedView == "Today"
? getStatusValues(todayBasedCount['acomodation'] ?? {})
: getStatusValues(weekBasedCount['acomodation'] ?? {});
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) {
@ -450,7 +452,7 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Column(
children: [
Tooltip(
message: label ,
message: label,
child: Image.asset(
label == 'Domestic'
? 'assets/images/IconsImg/Domestic_new.png'
@ -478,10 +480,10 @@ class StatusDashboardState extends State<StatusDashboard> {
child: Text(
label,
style: GoogleFonts.poppins(
fontSize: 10,
fontSize: 12,
color: color,
// color: const Color(0xFFEAF3FB),
fontWeight: FontWeight.w700,
fontWeight: FontWeight.w500,
),
),
),
@ -542,61 +544,65 @@ class StatusDashboardState extends State<StatusDashboard> {
color: const Color(0xFFEAF3FB),
borderRadius: BorderRadius.circular(8),
),
child: isDesktop
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: 18,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 6),
Text(
label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
child:
isDesktop
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: 18,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 6),
Text(
label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
),
const SizedBox(width: 10),
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
const SizedBox(width: 10),
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
Widget buildCategoryCard(String title, IconData icon, List<String> statusLabels,List<int> values) {
Widget buildCategoryCard(
String title,
IconData icon,
List<String> statusLabels,
List<int> values,
) {
final statusIcons = [
Icons.calendar_today,
Icons.assignment,
@ -607,9 +613,9 @@ class StatusDashboardState extends State<StatusDashboard> {
final statusColors = [
Color(0xFFFBFFCA),
Color(0xFFFFF1CD),// Colors.yellow.shade100, // Color(0xFFCAE77B),
Color(0xFFDAFFE8),// Colors.green.shade100, // Color(0xFF72D480),
Color(0xFFFFD6D3),// Colors.red.shade100, // Color(0xFFF88C8C),
Color(0xFFFFF1CD), // Colors.yellow.shade100, // Color(0xFFCAE77B),
Color(0xFFDAFFE8), // Colors.green.shade100, // Color(0xFF72D480),
Color(0xFFFFD6D3), // Colors.red.shade100, // Color(0xFFF88C8C),
Color(0xFFFFA8A8), // Colors.red.shade200, // Color(0xFFE94B4B),
];
@ -650,17 +656,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),
@ -678,7 +683,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(
@ -688,16 +695,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(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.bold,
),),
Text(
values[index].toString(),
style: GoogleFonts.poppins(
fontSize: 10,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
);
@ -802,251 +813,383 @@ class StatusDashboardState extends State<StatusDashboard> {
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
? const EdgeInsets.symmetric(vertical: 5)
: EdgeInsets.zero,
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(
builder: (context, constraints) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// First Row: Toggle Buttons Row
Row(
mainAxisAlignment: MainAxisAlignment.end,
isLoading
? Center(child: CircularProgressIndicator())
: LayoutBuilder(
builder: (context, constraints) {
return Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
height: 36,
decoration: BoxDecoration(
color: const Color(0xFFEAEAEA),
borderRadius: BorderRadius.circular(20),
),
child: Row(
children: [
toggleChip("Today"),
toggleChip("This Week"),
],
),
),
],
),
const SizedBox(height: 20),
// 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),
),
],
const SizedBox(height: 10),
// First Row: Toggle Buttons Row
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Container(
height: 36,
decoration: BoxDecoration(
color: const Color(0xFFEAEAEA),
borderRadius:
BorderRadius.circular(20),
),
child: Row(
children: [
toggleChip("Today"),
toggleChip("This Week"),
],
),
),
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: [
...typeData.map((item) {
return Expanded(
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),
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),
),
],
),
);
}).toList(),
],
),
),
),
const SizedBox(width: 20),
Expanded(
flex: 3,
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: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Status",
style: GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
padding: const EdgeInsets.all(
15,
),
child: Row(
children: [
...typeData.map((item) {
return Expanded(
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,
),
),
],
),
);
}).toList(),
],
),
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(),
],
const SizedBox(width: 20),
Expanded(
flex: 3,
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: 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: [
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(
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),
)
: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey,
blurRadius: 5,
offset: Offset(0, 2),
),
],
),
);
}).toList(),
],
),
),
const SizedBox(height: 20),
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: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Status",
style: GoogleFonts.poppins(
fontSize: 19,
color: Colors.black87,
fontWeight: FontWeight.bold,
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,
),
),
],
),
);
}).toList(),
],
),
),
),
const SizedBox(height: 23),
Wrap(
spacing: 10,
runSpacing: 10,
children: [
...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(),
],
),
],
),
),
],
),
const SizedBox(height: 20),
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: 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
isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: buildCategoryCard("Flight", 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)),
// Third Row: Flight, Accommodation, Forex
isDesktop
? Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: buildCategoryCard(
"Flight",
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

@ -1530,7 +1530,8 @@ class _ForexScreenState extends State<ForexScreen> {
else
SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment:
isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.start,
children: [
Text(
"Currency *",
@ -1552,19 +1553,24 @@ class _ForexScreenState extends State<ForexScreen> {
height: 40,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(
// "cur",
// "${selectedCurrency}",
selectedCurrency ?? "Currency",
// selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
),
child:
isDesktop
? Center(child: currencyText())
: Container(child: currencyText()),
// child: Center
// (
// child: Text(
// // "cur",
// // "${selectedCurrency}",
// selectedCurrency ?? "Currency",
// // selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
// style: const TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// ),
),
),
),
@ -1632,6 +1638,14 @@ class _ForexScreenState extends State<ForexScreen> {
];
}
Widget currencyText() => Text(
selectedCurrency ?? "Currency",
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
);
List<Widget> _buildSecondRow(bool isDesktop) {
return [
if (isDesktop) Spacer(),
@ -2344,7 +2358,8 @@ class _ForexScreenState extends State<ForexScreen> {
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: isDesktop ? MainAxisAlignment.center : MainAxisAlignment.start,
mainAxisAlignment:
isDesktop ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [
Container(
alignment: Alignment.bottomLeft,

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,17 +90,19 @@ class AccomodationListWidget extends StatelessWidget {
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Accomodation", true);
},
onTap:
widget.isViewMode
? null
: () {
print("New data");
widget.onAddNew("Accomodation", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
@ -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: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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,36 +308,38 @@ class AccomodationListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
// mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
item["hotel_name"]!,
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),)
fontSize: 14,
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
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,170 +352,175 @@ class AccomodationListWidget extends StatelessWidget {
),
],
),
Divider(
color: Colors.blueGrey.shade50,
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
" DestinationCity",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Check (in) ",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Check (out) ",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
],
)
children: [
Expanded(
flex: 2,
child: Text(
" DestinationCity",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Check (in) ",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Check (out) ",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
)
: SizedBox.shrink(),
SizedBox(height: 8),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
item["destination_city"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
children: [
Expanded(
flex: 2,
child: Text(
item["destination_city"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
"${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: _buildComments(
"Comments:", item["comments"] ?? "N/A"),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: _buildComments(
"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"],
),
const SizedBox(height: 10),
const Text(
"Comment",
style: TextStyle(fontWeight: FontWeight.w500),
SizedBox(height: 5),
_buildRow(
"Check (in)",
"${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
),
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"]!,
// ),
// SizedBox(width: 10),
// _buildRow(
// "Date(out):", formatDate(item["checkout_date"]!)),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// )
SizedBox(height: 5),
_buildRow(
"Check (out)",
"${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
),
SizedBox(height: 5),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
),
),
// 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"]!)}",
// // ),
// // ],
// // ),
// // ),
// ],
// ),
// 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 +549,35 @@ class AccomodationListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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) + "...",
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,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
),
],
);
@ -531,87 +599,90 @@ 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),
// 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 _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
};
// 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,
// ),
// ),
// ),
// ],
// );
// }
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: 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

@ -8,8 +8,9 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../config/apiUrl.dart';
import '../../data/models/plan.dart';
import '../../utils/auth_utils.dart';
class BusListWidget extends StatelessWidget {
class BusListWidget extends StatefulWidget {
final List<Map<String, dynamic>> busList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteBus;
@ -17,20 +18,66 @@ class BusListWidget extends StatelessWidget {
final Function(String, bool) onAddNew;
final bool isViewMode;
const BusListWidget(
{super.key,
required this.busList,
required this.onOpen,
required this.onDeleteBus,
required this.onAddNew,
required this.isViewMode});
const BusListWidget({
super.key,
required this.busList,
required this.onOpen,
required this.onDeleteBus,
required this.onAddNew,
required this.isViewMode,
});
@override
State<BusListWidget> createState() => _BusListWidgetState();
}
class _BusListWidgetState extends State<BusListWidget> {
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(
@ -40,7 +87,7 @@ class BusListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && busList.isNotEmpty)
if ((!isDesktop) && widget.busList.isNotEmpty)
Text(
" ",
style: const TextStyle(
@ -50,16 +97,18 @@ class BusListWidget extends StatelessWidget {
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Bus", true);
},
onTap:
widget.isViewMode
? null
: () {
print("New data");
widget.onAddNew("Bus", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
@ -73,7 +122,7 @@ class BusListWidget extends StatelessWidget {
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
),
// Container(
// decoration: BoxDecoration(
// shape: BoxShape.circle,
@ -130,9 +179,9 @@ class BusListWidget extends StatelessWidget {
],
),
const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop)
// Scroll behavior based on device
_buildData(context, isDesktop),
],
),
),
@ -141,7 +190,7 @@ class BusListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
busList.where((item) => item["is_active"] == "1").toList();
widget.busList.where((item) => item["is_active"] == "1").toList();
print("filteredList- $filteredList");
// String formatDate(String dateString) {
@ -191,8 +240,11 @@ class BusListWidget 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");
@ -218,14 +270,17 @@ class BusListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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
@ -234,7 +289,7 @@ class BusListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -246,25 +301,27 @@ class BusListWidget extends StatelessWidget {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color:
!isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Bus"),
onTap: () => widget.onOpen(true, item, "Bus"),
child: Tooltip(
message: 'Delete Edit Details',
message: 'Edit Bus Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteBus(item),
onTap: () => widget.onDeleteBus(item),
child: Tooltip(
message: 'Delete Bus Details',
child: Image.asset(
@ -277,137 +334,149 @@ class BusListWidget extends StatelessWidget {
),
],
),
Divider(
color: Colors.blueGrey.shade50,
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 3,
child: Text(
" Planned Trips",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 3,
child: Text(
" Date",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 3,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
],
)
: SizedBox.shrink(),
SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 3,
child: Text(
"${item["from"]} - ${item["to"]} ",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 3,
child: Text(
"${formatDate(item["date"]!)} ${formatTime(item["time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 3,
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: [
_infoBlock("From", item["from"] ?? "N/A"),
_infoBlock("To", item["to"]! ?? "N/A"),
_infoBlock("Date",
(item["date"] != null && item["time"] != null)
? "${formatDate(item["date"]!)} ${formatTime(item["time"]!)}"
: "N/A",
Expanded(
flex: 3,
child: Text(
"Planned Trips",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 3,
child: Text(
" Date",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 3,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
)
: SizedBox.shrink(),
SizedBox(height: 8),
isDesktop
? Row(
children: [
Expanded(
flex: 3,
child: Text(
"${item["from"]} - ${item["to"]} ",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 3,
child: Text(
"${formatDate(item["date"]!)} ${formatTime(item["time"]!)}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 3,
child: _buildComments(
"Comments:",
item["comments"] ?? "N/A",
),
),
],
)
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow(
"PlannedTrips",
'${item["from"]!} - ${item["to"]!}',
),
SizedBox(height: 5),
// _buildRow("To", item["to"]!),
// SizedBox(width: 10),
_buildDateTimeRow(
"Date",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
SizedBox(height: 5),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
),
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), ),
],
),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("From:", item["from"]),
// SizedBox(width: 10),
// _buildRow("To:", item["to"]!),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// 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("From", item["from"] ?? "N/A"),
// _infoBlock("To", item["to"]! ?? "N/A"),
// _infoBlock(
// "Date",
// (item["date"] != null && item["time"] != null)
// ? "${formatDate(item["date"]!)} ${formatTime(item["time"]!)}"
// : "N/A",
// ),
// ],
// ),
// const SizedBox(height: 16),
//
// // Comment label
// Text(
// "Comment",
// style: GoogleFonts.poppins(
// fontSize: 14,
// fontWeight: FontWeight.w600,
// ),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// )
// ),
// 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)),
// ],
// ),
],
),
),
@ -434,16 +503,14 @@ class BusListWidget extends StatelessWidget {
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
],
),
),
);
}
Widget _buildComments(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {
@ -464,31 +531,35 @@ class BusListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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) + "...",
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,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
),
],
);
@ -513,36 +584,38 @@ class BusListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
SizedBox(
width: 100,
child: 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) + "...",
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: GoogleFonts.poppins(
fontSize: 12,
),
),
overflow: TextOverflow.ellipsis,
),
)
: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
),
],
);
@ -552,21 +625,19 @@ class BusListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
SizedBox(
width: 100,
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 8),
Expanded(
child: Text(
"$date, $time",
style: GoogleFonts.poppins(
fontSize: 12,
),
),
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,16 +227,18 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// Right side: either "Add" icon or nothing
if (widget.flightList.isNotEmpty)
MouseRegion(
cursor: widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: widget.isViewMode
? null
: () {
widget.onAddNew("Flight", true);
print("New data");
},
onTap:
widget.isViewMode
? null
: () {
widget.onAddNew("Flight", true);
print("New data");
},
child: Icon(
Icons.add_circle_sharp,
size: 30,
@ -210,21 +247,20 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
)
else if (!isDesktop)
// Centered "No Data Found" message for mobile and empty list
// Centered "No Data Found" message for mobile and empty list
Expanded(
child: Center(
child: Text(
"No Data Found",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.grey,
),
),
),
)
),
],
),
const SizedBox(height: 16),
@ -235,7 +271,6 @@ class _FlightListWidgetState extends State<FlightListWidget> {
),
),
);
}
Widget _buildData(BuildContext context, bool isDesktop) {
@ -347,22 +382,26 @@ 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: [
BoxShadow(
color: Colors.black12,
blurRadius: 2,
offset: Offset(0, 2), // down
),
// Top shadow
BoxShadow(
color: Colors.black12,
blurRadius: 0.5,
offset: Offset(0, -1), // up
),
],
// color: Colors.white,
boxShadow:
isDesktop
? [
BoxShadow(
color: Colors.black12,
blurRadius: 2,
offset: Offset(0, 2), // down
),
// Top shadow
BoxShadow(
color: Colors.black12,
blurRadius: 0.5,
offset: Offset(0, -1), // up
),
]
: [],
border: Border(
top: BorderSide(
color: Colors.white70, // Change color to match your theme
@ -371,49 +410,56 @@ 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(
children: [
Text(
tripTypeName ?? "N/A",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
),
),
Spacer(),
GestureDetector(
onTap: () => widget.onOpen(true, item, "Flight"),
child: Tooltip(
message: 'Edit Flight Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Row(
children: [
Text(
tripTypeName ?? "N/A",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
// Color(0xFF114D8B)
),
),
),
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,
Spacer(),
GestureDetector(
onTap: () => widget.onOpen(true, item, "Flight"),
child: Tooltip(
message: 'Edit Flight Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color:
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),
if (isDesktop)
Row(
@ -600,10 +646,9 @@ 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";
"Unknown Country";
final parts = fromPlaceCountry.split('\n');
final cityAndCode = parts[0];
@ -618,7 +663,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
String toPlaceCountry =
countryMap[trip["to_place"]?.toString()] ??
"Unknown Country";
"Unknown Country";
final toparts = toPlaceCountry.split('\n');
final tocityAndCode = toparts[0];
@ -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,
),
),
),

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,9 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
class InsuranceListWidget extends StatelessWidget {
import '../../utils/auth_utils.dart';
class InsuranceListWidget extends StatefulWidget {
final List<Map<String, dynamic>> insuranceList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteInsurance;
@ -13,21 +15,67 @@ class InsuranceListWidget extends StatelessWidget {
final Function(String, bool) onAddNew;
final bool isViewMode;
const InsuranceListWidget(
{super.key,
required this.insuranceList,
required this.onOpen,
required this.apiData,
required this.onDeleteInsurance,
required this.onAddNew,
required this.isViewMode});
const InsuranceListWidget({
super.key,
required this.insuranceList,
required this.onOpen,
required this.apiData,
required this.onDeleteInsurance,
required this.onAddNew,
required this.isViewMode,
});
@override
State<InsuranceListWidget> createState() => _InsuranceListWidgetState();
}
class _InsuranceListWidgetState extends State<InsuranceListWidget> {
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(
@ -107,10 +155,10 @@ class InsuranceListWidget extends StatelessWidget {
// ),
// ],
// ),
const SizedBox(height: 16),
// Scroll behavior based on device
// const SizedBox(height: 16),
_buildData(context, isDesktop)
// Scroll behavior based on device
_buildData(context, isDesktop),
],
),
),
@ -119,11 +167,11 @@ class InsuranceListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
insuranceList.where((item) => item["is_active"] == "1").toList();
widget.insuranceList.where((item) => item["is_active"] == "1").toList();
print("filteredList- $filteredList");
List<dynamic> insurancetypeList =
apiData?['insurance_type_of_insurance'] ?? [];
widget.apiData?['insurance_type_of_insurance'] ?? [];
String getRequestForInsuranceType(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
@ -146,7 +194,7 @@ class InsuranceListWidget extends StatelessWidget {
String getRequestValue(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
return (apiData?['miscellaneous_special_request'] ?? [])
return (widget.apiData?['miscellaneous_special_request'] ?? [])
.firstWhere(
(element) =>
element["dropdown_key"].toString() == specialRequestKey,
@ -177,14 +225,18 @@ class InsuranceListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
// 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
@ -193,176 +245,207 @@ class InsuranceListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
getRequestForInsuranceType(item["type_of_insurance"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
Expanded(
flex: 1,
child: Text(
getRequestForInsuranceType(
item["type_of_insurance"]!.toString(),
),
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Insurance"),
onTap: () => widget.onOpen(true, item, "Insurance"),
child: Tooltip(
message: 'Edit Insurance Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black,
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => widget.onDeleteInsurance(item),
child: Tooltip(
message: 'Delete Insurance Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onDeleteInsurance(item),
// child: Tooltip(
// message: 'Delete Insurance Details',
// child: Image.asset(
// 'assets/images/IconsImg/delete.png',
// width: 20,
// height: 15,
// color: Colors.red,
// ),
// ),
// ),
],
),
SizedBox(height: 4),
Divider(
color: Colors.blueGrey.shade50,
),
SizedBox(height: 4),
// Divider(color: Colors.blueGrey.shade50),
// SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
" InsuranceType",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Time Period ",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
],
)
: SizedBox.shrink(),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
getRequestForInsuranceType(
item["type_of_insurance"]!.toString()),
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: _buildComments(
"Comments:", item["comments"] ?? "N/A"),
),
],
)
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_infoBlock("Insurance Type", getRequestForInsuranceType(item["type_of_insurance"]!.toString()) ?? "N/A"),
_infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
_infoBlock("End Date", formatDate(item["end_date"]) ?? "N/A"),
Expanded(
flex: 2,
child: Text(
" InsuranceType",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Time Period ",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
),
const SizedBox(height: 16),
)
: SizedBox.shrink(),
SizedBox(height: 8),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
getRequestForInsuranceType(
item["type_of_insurance"]!.toString(),
),
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: _buildComments(
"Comments:",
item["comments"] ?? "N/A",
),
),
],
)
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
children: [
_buildRow(
"InsuranceType",
getRequestForInsuranceType(
item["type_of_insurance"]!.toString(),
),
),
SizedBox(width: 10),
_buildRow(
"TimePeriod",
'${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"])} ',
),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
SizedBox(width: 10),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
),
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), ),
],
),
// Column(
// children: [
// _buildRow(
// "InsuranceType:",
// getRequestForInsuranceType(
// item["type_of_insurance"]!.toString())),
// SizedBox(width: 10),
// _buildRow(
// "StartDate:", formatDate(item["start_date"]!)),
// SizedBox(width: 10),
// _buildRow("EndDate:", formatDate(item["end_date"])),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // Top Row (Country, Currency, Total)
// // Row(
// // mainAxisAlignment: MainAxisAlignment.spaceBetween,
// Wrap(
// spacing: 20, // horizontal space between items
// runSpacing: 10, // vertical space between rows
// children: [
// _infoBlock(
// "Insurance Type",
// getRequestForInsuranceType(
// item["type_of_insurance"]!.toString(),
// ) ??
// "N/A",
// ),
// _infoBlock(
// "Start Date",
// formatDate(item["start_date"]!) ?? "N/A",
// ),
// _infoBlock(
// "End Date",
// formatDate(item["end_date"]) ?? "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)),
// ],
// ),
],
),
),
@ -391,31 +474,35 @@ class InsuranceListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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) + "...",
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,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
),
],
);
@ -439,16 +526,14 @@ class InsuranceListWidget extends StatelessWidget {
const 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 = {
@ -468,40 +553,39 @@ class InsuranceListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
SizedBox(
width: 100,
child: 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, fontSize: 12), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
),
),
textStyle: TextStyle(
color: Colors.black,
fontSize: 12,
), // 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)),
),
],
);
@ -509,11 +593,11 @@ class InsuranceListWidget extends StatelessWidget {
List<DataRow> _buildDataRows() {
List<Map<String, dynamic>> filteredList =
insuranceList.where((item) => item["is_active"] == "1").toList();
widget.insuranceList.where((item) => item["is_active"] == "1").toList();
print("filteredList- $filteredList");
List<dynamic> insurancetypeList =
apiData?['insurance_type_of_insurance'] ?? [];
widget.apiData?['insurance_type_of_insurance'] ?? [];
String getRequestForInsuranceType(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
@ -529,47 +613,55 @@ class InsuranceListWidget extends StatelessWidget {
return filteredList.asMap().entries.map((entry) {
Map<String, dynamic> item = entry.value;
return DataRow(cells: [
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
// DataCell(Text(item["type_of_insurance"]!)),
DataCell(Text(
getRequestForInsuranceType(item["type_of_insurance"]!.toString()))),
DataCell(Text(item["start_date"]!)),
DataCell(Text(item["end_date"]!)),
DataCell(Row(
children: [
GestureDetector(
onTap: () => onOpen(true, item, "Insurance"),
child: Tooltip(
message: 'Edit Insurance Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
return DataRow(
cells: [
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
// DataCell(Text(item["type_of_insurance"]!)),
DataCell(
Text(
getRequestForInsuranceType(item["type_of_insurance"]!.toString()),
),
),
DataCell(Text(item["start_date"]!)),
DataCell(Text(item["end_date"]!)),
DataCell(
Row(
children: [
GestureDetector(
onTap: () => widget.onOpen(true, item, "Insurance"),
child: Tooltip(
message: 'Edit Insurance Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
),
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteInsurance(item),
child: Tooltip(
message: 'Delete Insurance Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
SizedBox(width: 10),
GestureDetector(
onTap: () => widget.onDeleteInsurance(item),
child: Tooltip(
message: 'Delete Insurance Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
),
IconButton(
icon: Icon(
Icons.keyboard_arrow_down_outlined,
size: 28,
color: Color(0xFF475569),
),
onPressed: () {
// Expand logic
},
),
],
),
IconButton(
icon: Icon(Icons.keyboard_arrow_down_outlined,
size: 28, color: Color(0xFF475569)),
onPressed: () {
// Expand logic
},
),
],
)
// Row(
// children: [
@ -593,9 +685,9 @@ class InsuranceListWidget extends StatelessWidget {
// ),
// ],
// )
),
]);
),
],
);
}).toList();
}
}

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class MiscellaneousListWidget extends StatelessWidget {
import '../../utils/auth_utils.dart';
class MiscellaneousListWidget extends StatefulWidget {
final List<Map<String, dynamic>> miscellaneousList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteMiscellaneous;
@ -19,12 +21,58 @@ class MiscellaneousListWidget extends StatelessWidget {
required this.isViewMode,
});
@override
State<MiscellaneousListWidget> createState() =>
_MiscellaneousListWidgetState();
}
class _MiscellaneousListWidgetState extends State<MiscellaneousListWidget> {
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 +82,7 @@ class MiscellaneousListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && miscellaneousList.isNotEmpty)
if ((!isDesktop) && widget.miscellaneousList.isNotEmpty)
Text(
" ",
style: const TextStyle(
@ -44,20 +92,20 @@ class MiscellaneousListWidget extends StatelessWidget {
),
MouseRegion(
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap:
isViewMode
? null
: () {
print("New data");
onAddNew("Miscellaneous", true);
},
widget.isViewMode
? null
: () {
print("New data");
widget.onAddNew("Miscellaneous", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
@ -133,7 +181,9 @@ class MiscellaneousListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
miscellaneousList.where((item) => item["is_active"] == "1").toList();
widget.miscellaneousList
.where((item) => item["is_active"] == "1")
.toList();
return ListView.builder(
shrinkWrap: true,
@ -144,12 +194,12 @@ class MiscellaneousListWidget extends StatelessWidget {
String getRequestValue(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
return (apiData?['miscellaneous_special_request'] ?? [])
return (widget.apiData?['miscellaneous_special_request'] ?? [])
.firstWhere(
(element) =>
element["dropdown_key"].toString() == specialRequestKey,
orElse: () => {"dropdown_value": "N/A"},
)["dropdown_value"]
element["dropdown_key"].toString() == specialRequestKey,
orElse: () => {"dropdown_value": "N/A"},
)["dropdown_value"]
.toString();
}
@ -158,14 +208,17 @@ class MiscellaneousListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.yellow.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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
@ -174,7 +227,7 @@ class MiscellaneousListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -185,26 +238,28 @@ class MiscellaneousListWidget extends StatelessWidget {
getRequestValue(item["special_request"]?.toString()),
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Miscellaneous"),
onTap: () => widget.onOpen(true, item, "Miscellaneous"),
child: Tooltip(
message: 'Edit Miscellaneous Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black,
),
),
),
SizedBox(width: 10),
GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
onTap: () => onDeleteMiscellaneous(item),
onTap: () => widget.onDeleteMiscellaneous(item),
child: Tooltip(
message: 'Delete Miscellaneous Details',
child: Image.asset(
@ -217,95 +272,70 @@ class MiscellaneousListWidget extends StatelessWidget {
),
],
),
Divider(color: Colors.blueGrey.shade50),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
"Special Request",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 3,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
)
// : SizedBox.shrink(),
// isDesktop
// ? Row(
// children: [
// Expanded(
// flex: 2,
// child: Text(
// getRequestValue(
// item["special_request"]?.toString(),
// ),
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// Expanded(
// flex: 3,
// child: Text(
// item["comments"],
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ],
// )
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 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),
children: [
Expanded(
flex: 2,
child: Text(
"Special Request",
style: GoogleFonts.poppins(fontSize: 11),
),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
Expanded(
flex: 3,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// Column(
// children: [
// _buildRow(
// "Special Request:",
// getRequestValue(item["special_request"]?.toString()),
// ),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
)
: SizedBox.shrink(),
SizedBox(height: 8),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
getRequestValue(
item["special_request"]?.toString(),
),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
Expanded(
flex: 3,
child: Text(
item["comments"],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
)
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
children: [
// _buildRow(
// "Special Request",
// getRequestValue(item["special_request"]?.toString()),
// ),
SizedBox(width: 10),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
),
],
),
),
@ -335,34 +365,34 @@ class MiscellaneousListWidget extends StatelessWidget {
children: [
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,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
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,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
);
@ -387,102 +417,108 @@ class MiscellaneousListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600),
SizedBox(
width: 100,
child: 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,
fontSize: 12,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
overflow: TextOverflow.ellipsis,
),
)
: Text(value),
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
fontSize: 12,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
overflow: TextOverflow.ellipsis,
),
)
: Text(value),
),
],
);
}
//
// Widget _buildData(BuildContext context) {
// return Container(
// width: MediaQuery.of(context).size.width,
// child: DataTable(
// border: TableBorder(
// bottom: BorderSide(color: Colors.black12),
// horizontalInside: BorderSide(color: Colors.black12),
// ),
// columns: const [
// DataColumn(label: Text('Special Request')),
// DataColumn(label: Text('Comments')),
// DataColumn(label: Text('Actions')),
// ],
// rows: _buildDataRows(),
// ),
// );
// }
//
// List<DataRow> _buildDataRows() {
// List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
//
// String getRequestValue(String? specialRequestKey) {
// if (specialRequestKey == null) return "N/A";
// return purposeList
// .firstWhere(
// (element) =>
// element["dropdown_key"].toString() == specialRequestKey,
// orElse: () => {"dropdown_value": "N/A"},
// )["dropdown_value"]
// .toString();
// }
//
// List<Map<String, dynamic>> filteredList =
// miscellaneousList.where((item) => item["is_active"] == "1").toList();
//
// return filteredList.asMap().entries.map((entry) {
// Map<String, dynamic> item = entry.value;
//
// return DataRow(cells: [
// DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
// DataCell(Text(item["comments"] ?? "N/A")),
// DataCell(Row(
// children: [
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/edit.png',
// width: 20, height: 15),
// ),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/delete.png',
// width: 20, height: 15),
// ),
// IconButton(
// icon: Icon(Icons.keyboard_arrow_down_outlined,
// size: 28, color: Color(0xFF475569)),
// onPressed: () {
// // Expand logic (optional)
// },
// ),
// ],
// )),
// ]);
// }).toList();
// }
}
//
// Widget _buildData(BuildContext context) {
// return Container(
// width: MediaQuery.of(context).size.width,
// child: DataTable(
// border: TableBorder(
// bottom: BorderSide(color: Colors.black12),
// horizontalInside: BorderSide(color: Colors.black12),
// ),
// columns: const [
// DataColumn(label: Text('Special Request')),
// DataColumn(label: Text('Comments')),
// DataColumn(label: Text('Actions')),
// ],
// rows: _buildDataRows(),
// ),
// );
// }
//
// List<DataRow> _buildDataRows() {
// List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
//
// String getRequestValue(String? specialRequestKey) {
// if (specialRequestKey == null) return "N/A";
// return purposeList
// .firstWhere(
// (element) =>
// element["dropdown_key"].toString() == specialRequestKey,
// orElse: () => {"dropdown_value": "N/A"},
// )["dropdown_value"]
// .toString();
// }
//
// List<Map<String, dynamic>> filteredList =
// miscellaneousList.where((item) => item["is_active"] == "1").toList();
//
// return filteredList.asMap().entries.map((entry) {
// Map<String, dynamic> item = entry.value;
//
// return DataRow(cells: [
// DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
// DataCell(Text(item["comments"] ?? "N/A")),
// DataCell(Row(
// children: [
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/edit.png',
// width: 20, height: 15),
// ),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/delete.png',
// width: 20, height: 15),
// ),
// IconButton(
// icon: Icon(Icons.keyboard_arrow_down_outlined,
// size: 28, color: Color(0xFF475569)),
// onPressed: () {
// // Expand logic (optional)
// },
// ),
// ],
// )),
// ]);
// }).toList();
// }
}

View File

@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
class TaxiListWidget extends StatelessWidget {
import '../../utils/auth_utils.dart';
class TaxiListWidget extends StatefulWidget {
final List<Map<String, dynamic>> taxiList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteTaxi;
@ -21,12 +23,57 @@ class TaxiListWidget extends StatelessWidget {
required this.isViewMode,
});
@override
State<TaxiListWidget> createState() => _TaxiListWidgetState();
}
class _TaxiListWidgetState extends State<TaxiListWidget> {
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(
@ -36,7 +83,7 @@ class TaxiListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && taxiList.isNotEmpty)
if ((!isDesktop) && widget.taxiList.isNotEmpty)
Text(
" ",
style: const TextStyle(
@ -46,17 +93,17 @@ class TaxiListWidget extends StatelessWidget {
),
MouseRegion(
cursor:
isViewMode
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap:
isViewMode
widget.isViewMode
? null
: () {
print("New data");
onAddNew("Taxi", true);
widget.onAddNew("Taxi", true);
},
child: Row(
mainAxisSize:
@ -121,11 +168,12 @@ class TaxiListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
taxiList.where((item) => item["is_active"] == "1").toList();
widget.taxiList.where((item) => item["is_active"] == "1").toList();
print("filteredList- $filteredList");
List<dynamic> taxiClassList = apiData?['taxt_car_type'] ?? [];
List<dynamic> taxirequiredFor = apiData?['taxi_car_required_for'] ?? [];
List<dynamic> taxiClassList = widget.apiData?['taxt_car_type'] ?? [];
List<dynamic> taxirequiredFor =
widget.apiData?['taxi_car_required_for'] ?? [];
String getRequestForTaxiClass(String? specialRequestKey) {
if (specialRequestKey == null) return "N/A";
@ -228,14 +276,17 @@ class TaxiListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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
@ -244,37 +295,41 @@ class TaxiListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"${getRequestForTaxiClass(item["car_type"]!.toString())} For ${item["no_of_passengers"]!} Passenger",
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
Expanded(
flex: 1,
child: Text(
"${getRequestForTaxiClass(item["car_type"]!.toString())} For ${item["no_of_passengers"]!} Passenger",
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Taxi"),
onTap: () => widget.onOpen(true, item, "Taxi"),
child: Tooltip(
message: 'Edit Taxi Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black,
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteTaxi(item),
onTap: () => widget.onDeleteTaxi(item),
child: Tooltip(
message: 'Delete Taxi Details',
child: Image.asset(
@ -287,7 +342,7 @@ class TaxiListWidget extends StatelessWidget {
),
],
),
Divider(color: Colors.blueGrey.shade50),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
@ -323,7 +378,8 @@ class TaxiListWidget extends StatelessWidget {
],
)
: SizedBox.shrink(),
SizedBox(height: 4),
SizedBox(height: 8),
isDesktop
? Row(
children: [
@ -369,72 +425,75 @@ class TaxiListWidget extends StatelessWidget {
),
],
)
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// First row: City & Location
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("City", item["destination_city"] ?? "N/A"),
_infoColumn("Location", item["location_of_pickup"] ?? "N/A",alignEnd: true),
],
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow("City", item["destination_city"]),
SizedBox(width: 10),
_buildRow("Location", item["location_of_pickup"]!),
SizedBox(width: 10),
_buildDateTimeRow(
"Date",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
const SizedBox(height: 16),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
// Second row: Date & Time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("Date", "${formatDate(item["date"]!)}" ?? "N/A"),
_infoColumn("Time", "${formatTime(item["time"]!)}" ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
// Comment box
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), ),
] )
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("City:", item["destination_city"]),
// SizedBox(width: 10),
// _buildRow("Pickup:", item["location_of_pickup"]!),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// ),
// _buildRow("TaxiFor:", item["car_required_for"]!),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // First row: City & Location
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoColumn("City", item["destination_city"] ?? "N/A"),
// _infoColumn("Location", item["location_of_pickup"] ?? "N/A",alignEnd: true),
// ],
// ),
// const SizedBox(height: 16),
//
// // Second row: Date & Time
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoColumn("Date", "${formatDate(item["date"]!)}" ?? "N/A"),
// _infoColumn("Time", "${formatTime(item["time"]!)}" ?? "N/A",alignEnd: true),
// ],
// ),
// const SizedBox(height: 16),
//
// // Comment label
// Text(
// "Comment",
// style: GoogleFonts.poppins(
// fontSize: 14,
// fontWeight: FontWeight.w600,
// ),
// ),
// const SizedBox(height: 8),
//
// // Comment box
// 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), ),
//
// ] ),
),
],
),
),
@ -516,9 +575,12 @@ class TaxiListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
SizedBox(
width: 100,
child: Text(
title,
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
),
),
SizedBox(width: 8),
Expanded(
@ -551,9 +613,15 @@ class TaxiListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600),
SizedBox(
width: 100,
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 8),
Expanded(
@ -562,30 +630,27 @@ class TaxiListWidget extends StatelessWidget {
],
);
}
Widget _infoColumn(String label, String value, {bool alignEnd = false}) {
return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
);
}
Widget _infoColumn(String label, String value, {bool alignEnd = false}) {
return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
],
);
}
}

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 TrainListWidget extends StatefulWidget {
final bool hasAction;
@ -36,12 +37,46 @@ class _TrainListWidgetState extends State<TrainListWidget> {
// late Map<String, String> countryMap;
Map<String, String> countryMap = {};
Color? layoutColor;
Color? secondColor;
Color? thridColor;
@override
void initState() {
super.initState();
loadInitialData();
loadCountryList(); // Call your method here
}
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;
});
}
void checkClass() {
if (widget.hasAction) {
if (widget.tripType?.isNotEmpty == true) {
@ -99,7 +134,8 @@ class _TrainListWidgetState extends State<TrainListWidget> {
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(
@ -315,14 +351,17 @@ class _TrainListWidgetState extends State<TrainListWidget> {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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
@ -331,7 +370,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -343,7 +382,8 @@ class _TrainListWidgetState extends State<TrainListWidget> {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
color:
!isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
),
),
Spacer(),
@ -355,7 +395,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black,
),
),
),
@ -374,7 +414,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
),
],
),
Divider(color: Colors.blueGrey.shade50),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
@ -382,7 +422,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
Expanded(
flex: 2,
child: Text(
" Class",
"Class",
style: GoogleFonts.poppins(fontSize: 11),
),
),
@ -410,7 +450,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
],
)
: SizedBox.shrink(),
SizedBox(height: 4),
SizedBox(height: 8),
isDesktop
? Row(
children: [
@ -539,72 +579,102 @@ class _TrainListWidgetState extends State<TrainListWidget> {
),
],
)
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// First row: City & Location
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_infoColumn("Class", getRequestForTrainClass(item["class"]!.toString()) ?? "N/A"),
_infoColumn("From", item["from_station"]! ?? "N/A"),
_infoColumn("To", item["to_station"]! ?? "N/A",alignEnd: true),
_buildRow(
"Class",
getRequestForTrainClass(item["class"]!.toString()),
),
_buildRow("From", item["from_station"]!),
_buildRow("To", item["to_station"]!),
_buildDateTimeRow(
"Date",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
const SizedBox(height: 16),
),
// Second row: Date & Time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("Date", "${formatDate(item["date"]!)}" ?? "N/A"),
_infoColumn("Time", "${formatTime(item["time"]!)}" ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
// Comment box
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), ),
] )
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "Class:",
// getRequestForTrainClass(item["class"]!.toString()),
// // First row: City & Location
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoColumn(
// "Class",
// getRequestForTrainClass(
// item["class"]!.toString(),
// ) ??
// "N/A",
// ),
// _infoColumn("From", item["from_station"]! ?? "N/A"),
// _infoColumn(
// "To",
// item["to_station"]! ?? "N/A",
// alignEnd: true,
// ),
// ],
// ),
// _buildRow("From:", item["from_station"]!),
// _buildRow("To:", item["to_station"]!),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// const SizedBox(height: 16),
//
// // Second row: Date & Time
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// _infoColumn(
// "Date",
// "${formatDate(item["date"]!)}" ?? "N/A",
// ),
// _infoColumn(
// "Time",
// "${formatTime(item["time"]!)}" ?? "N/A",
// alignEnd: true,
// ),
// ],
// ),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// const SizedBox(height: 16),
//
// // Comment label
// Text(
// "Comment",
// style: GoogleFonts.poppins(
// fontSize: 14,
// fontWeight: FontWeight.w600,
// ),
// ),
// const SizedBox(height: 8),
//
// // Comment box
// 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)),
// ],
// ),
],
@ -690,9 +760,15 @@ class _TrainListWidgetState extends State<TrainListWidget> {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600),
SizedBox(
width: 100,
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 8),
Expanded(
@ -725,7 +801,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
label,
@ -738,21 +814,22 @@ class _TrainListWidgetState extends State<TrainListWidget> {
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
],
);
}
Widget _buildDateTimeRow(String title, String date, String time) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
SizedBox(
width: 100,
child: Text(
title,
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
),
),
SizedBox(width: 8),
Expanded(child: Text("$date, $time", style: TextStyle(fontSize: 12))),

View File

@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
class VisaListWidget extends StatelessWidget {
import '../../utils/auth_utils.dart';
class VisaListWidget extends StatefulWidget {
final List<Map<String, dynamic>> visaList;
final Function(bool, Map<String, dynamic>, String) onOpen;
final Function(Map<String, dynamic>) onDeleteMiscellaneous;
@ -12,91 +14,138 @@ class VisaListWidget extends StatelessWidget {
final Function(String, bool) onAddNew;
final bool isViewMode;
const VisaListWidget(
{super.key,
required this.visaList,
required this.onOpen,
required this.onDeleteMiscellaneous,
required this.apiData,
required this.apiCountryData,
required this.onAddNew,
required this.isViewMode});
const VisaListWidget({
super.key,
required this.visaList,
required this.onOpen,
required this.onDeleteMiscellaneous,
required this.apiData,
required this.apiCountryData,
required this.onAddNew,
required this.isViewMode,
});
State<VisaListWidget> createState() => _VisaListWidgetState();
}
class _VisaListWidgetState extends State<VisaListWidget> {
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(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header with title and button
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && visaList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// if ((!isDesktop) && widget.visaList.isNotEmpty)
// Text(
// " ",
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
// MouseRegion(
// cursor:
// widget.isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
//
// child: GestureDetector(
// onTap:
// widget.isViewMode
// ? null
// : () {
// print("New data");
// widget.onAddNew("Visa", true);
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// // Text(
// // "Add New",
// // style: TextStyle(fontSize: 13),
// // ),
// // SizedBox(width: 8), // spacing between icon and text
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// ],
// ),
// ),
// // onPressed: isViewMode
// // ? null
// // : () {
// // print("New data");
// //
// // },
// // child: Row(
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// // ],
// // ),
// ),
// ],
// ),
// const SizedBox(height: 16),
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Visa", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
],
),
),
// onPressed: isViewMode
// ? null
// : () {
// print("New data");
//
// },
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// ),
),
],
),
const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop)
_buildData(context, isDesktop),
],
),
),
@ -191,11 +240,11 @@ class VisaListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
visaList.where((item) => item["is_active"] == "1").toList();
widget.visaList.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";
@ -249,8 +298,11 @@ class VisaListWidget 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");
@ -276,14 +328,17 @@ class VisaListWidget extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
// color: Colors.orange.shade50,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3,
offset: Offset(0, 1),
),
],
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
@ -292,7 +347,7 @@ class VisaListWidget extends StatelessWidget {
),
),
child: Padding(
padding: EdgeInsets.all(12),
padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -303,26 +358,27 @@ class VisaListWidget extends StatelessWidget {
getRequestForVisa(item["type_of_visa"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
fontWeight:
isDesktop ? FontWeight.w800 : FontWeight.w600,
color: !isDesktop ? Colors.black : Color(0xFF575A74),
),
),
Spacer(),
GestureDetector(
onTap: () => onOpen(true, item, "Visa"),
onTap: () => widget.onOpen(true, item, "Visa"),
child: Tooltip(
message: 'Edit Visa Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
color: isDesktop ? Color(0xFF114D8B) : Colors.black,
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteMiscellaneous(item),
onTap: () => widget.onDeleteMiscellaneous(item),
child: Tooltip(
message: 'Delete Visa Details',
child: Image.asset(
@ -335,155 +391,180 @@ class VisaListWidget extends StatelessWidget {
),
],
),
Divider(
color: Colors.blueGrey.shade50,
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
" Country",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Visa Type",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Date",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(
fontSize: 11,
),
)),
],
)
children: [
Expanded(
flex: 2,
child: Text(
" Country",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Visa Type",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Date",
style: GoogleFonts.poppins(fontSize: 11),
),
),
Expanded(
flex: 2,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
)
: SizedBox.shrink(),
SizedBox(height: 8),
isDesktop
? Row(
children: [
Expanded(
flex: 2,
child: Text(
getRequestForCountry(
item["country_code"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
getRequestForVisa(
item["type_of_visa"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
formatDate(item["start_date"]!),
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)
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_infoBlock("Visa Type", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
_infoBlock("Country", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
_infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
Expanded(
flex: 2,
child: Text(
getRequestForCountry(
item["country_code"]!.toString(),
),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
getRequestForVisa(item["type_of_visa"]!.toString()),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: Text(
formatDate(item["start_date"]!),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 10),
Expanded(
flex: 2,
child: _buildComments(
"Comments:",
item["comments"] ?? "N/A",
),
),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
)
: Container(
color: Colors.white,
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow(
"VisaType",
getRequestForVisa(item["type_of_visa"]!.toString()),
),
SizedBox(height: 6),
_buildRow(
"Country",
getRequestForCountry(
item["country_code"]!.toString(),
),
),
SizedBox(height: 6),
_buildRow("StartDate", item["start_date"]!),
SizedBox(height: 6),
_buildRow("Comments", item["comments"] ?? "N/A"),
],
),
),
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), ),
],
),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "VisaType:",
// getRequestForVisa(
// item["type_of_visa"]!.toString())),
// SizedBox(height: 6),
// _buildRow(
// "Country:",
// getRequestForCountry(
// item["country_code"]!.toString())),
// SizedBox(height: 6),
// _buildRow("StartDate:", item["start_date"]!),
// SizedBox(height: 6),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // Top Row (Country, Currency, Total)
// // Row(
// // mainAxisAlignment: MainAxisAlignment.spaceBetween,
// Wrap(
// spacing: 20, // horizontal space between items
// runSpacing: 10, // vertical space between rows
// children: [
// _infoBlock(
// "Visa Type",
// getRequestForCountry(
// item["country_code"]!.toString(),
// ) ??
// "N/A",
// ),
// _infoBlock(
// "Country",
// getRequestForCountry(
// item["country_code"]!.toString(),
// ) ??
// "N/A",
// ),
// _infoBlock(
// "Start Date",
// formatDate(item["start_date"]!) ?? "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)),
// ],
// ),
],
),
),
@ -512,31 +593,37 @@ class VisaListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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) + "...",
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,
fontWeight: FontWeight.w600,
fontFamily: "Archivo"),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
fontFamily: "Archivo",
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
fontFamily: "Archivo"),
),
fontFamily: "Archivo",
),
),
),
],
);
@ -560,16 +647,14 @@ class VisaListWidget extends StatelessWidget {
const 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 = {
@ -589,34 +674,38 @@ class VisaListWidget extends StatelessWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
SizedBox(
width: 100,
child: 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) + "...",
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),
),
overflow: TextOverflow.ellipsis,
),
)
: Text(value, style: TextStyle(fontSize: 12)),
),
],
);

View File

@ -578,8 +578,6 @@ class TemplateForexState extends State<TemplateForex> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Container(
@ -587,15 +585,13 @@ class TemplateForexState extends State<TemplateForex> {
isDesktop: isDesktop,
breadcrumbItems: [
BreadcrumbItem(
title: 'Org Settings',
tooltip: 'Go To Organization Settings',
onTap: (context) {
context.go("/OrganizationSettings");
}
),
BreadcrumbItem(
title: 'Forex',
title: 'Org Settings',
tooltip: 'Go To Organization Settings',
onTap: (context) {
context.go("/OrganizationSettings");
},
),
BreadcrumbItem(title: 'Forex'),
],
),
),
@ -788,7 +784,7 @@ class TemplateForexState extends State<TemplateForex> {
),
Container(
padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.5,
height: MediaQuery.of(context).size.height * 0.45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Color(0xFFD6D5E6), width: 0.5),
@ -862,17 +858,18 @@ class TemplateForexState extends State<TemplateForex> {
SizedBox(width: 10),
SizedBox(
child: ElevatedButton(
onPressed: isDisable
? null
: () async {
setState(() {
isDisable = true;
});
onPressed:
isDisable
? null
: () async {
setState(() {
isDisable = true;
});
await handleSubmit();
// You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal
},
await handleSubmit();
// You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal
},
style: ElevatedButton.styleFrom(
backgroundColor: layoutColor,
// backgroundColor: widget.layoutColor,

View File

@ -1131,7 +1131,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: () {
context.go('/listPlan');
context.go('/OrganizationSettings');
},
child: Text("Cancel", style: GoogleFonts.poppins(fontSize: 12)),
),

View File

@ -58,6 +58,21 @@ class _ColorThemePickerWidgetState extends State<ColorThemePickerWidget> {
];
final List<Color> layoutTertiaryColors = [
Color(0xFFE5EFFF), // Very Light Blue
Color(0xFFE6FDFF), // Very Light Teal
Color(0xFFE8FDEF), // Mint Green
Color(0xFFFFE7E6), // Light Coral/Red
Color(0xFFFDE9E7), // Peach
Color(0xFFFFF5E5), // Lightest Orange
Color(0xFFECEEF8), // Very Light Rose
Color(0xFFE5FFFC), // Pastel Pink
Color(0xFFFEE6F3), // Light Lavender
Color(0xFFF9EBF3), // Soft Purple Grey
Color(0xFFF8EAFA), // Near-white Neutral
Color(0xFFF4EDF7), // Near-white Neutral
];
final List<Color> layoutTertiaryColors1 = [
Color(0xFFE3F2FD), // Very Light Blue
Color(0xFFE0F7FA), // Very Light Teal
Color(0xFFC8E6C9), // Mint Green
@ -67,7 +82,7 @@ class _ColorThemePickerWidgetState extends State<ColorThemePickerWidget> {
Color(0xFFFFEBEE), // Very Light Rose
Color(0xFFFCE4EC), // Pastel Pink
Color(0xFFF3E5F5), // Light Lavender
Color(0xFFEDE7F6), // Soft Purple Grey
Color(0xFFF9EBF3), // Soft Purple Grey
Color(0xFFF8F9FA), // Near-white Neutral
];

View File

@ -446,10 +446,12 @@ class CreateNewPlansState extends State<CreateNewPlan> {
String? _selectedIsBillable;
String? selectedFuncDept;
String? selectedPurpose;
bool hasUpdateVal = false;
Map<String, String?> validationErrors = {};
List<Map<String, dynamic>> miscellaneousList = [];
// List<Map<String, dynamic>> miscellaneousList = [{"special_request": 1, "comments": "posta", "indx": 1}];
List<Map<String, dynamic>> miscellaneousList = [];
List<Map<String, dynamic>> visaList = [];
List<Map<String, dynamic>> insuranceList = [];
List<Map<String, dynamic>> accommodationList = [];
@ -562,6 +564,10 @@ class CreateNewPlansState extends State<CreateNewPlan> {
loadInitialData();
});
// if (widget.selectedPlanData != null) {
// hasUpdateVal = true;
// }
if (widget.approverStatus == "Approval pending") {
print("Status approver - Approval Pending");
}
@ -656,6 +662,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
planTravlrId = travellerId;
_selectedOption = "Option 3";
otherUserName = travellerName;
hasUpdateVal = true;
} else if (userId.isNotEmpty && userId != "0") {
print("TestplanUsrId : $userId");
print("TestplanUsrIdSelf : $selfId");
@ -663,6 +671,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
print("TestplanUsrId2 : $planUsrId");
_selectedOption = (selfId != userId) ? "Option 2" : "Option 1";
otherUserName = userName;
hasUpdateVal = true;
}
});
}
@ -1316,6 +1325,56 @@ class CreateNewPlansState extends State<CreateNewPlan> {
}
}
Future<bool> serviceHasData() async {
return miscellaneousList.isNotEmpty ||
visaList.isNotEmpty ||
insuranceList.isNotEmpty ||
accommodationList.isNotEmpty ||
trainList.isNotEmpty ||
flightList.isNotEmpty ||
busList.isNotEmpty ||
taxiList.isNotEmpty ||
forexList.isNotEmpty;
}
void clearAllServiceLists() async {
setState(() {
miscellaneousList = [];
visaList = [];
insuranceList = [];
accommodationList = [];
trainList = [];
flightList = [];
busList = [];
taxiList = [];
forexList = [];
planData['miscellaneous'] = [];
planData['visa'] = [];
planData['insurance'] = [];
planData['accommodation'] = [];
planData['train'] = [];
planData['flight'] = [];
planData['bus'] = [];
planData['taxi'] = [];
planData['forex'] = [];
});
// Debugging output
print("After clearing:");
print("After clearing: $planData");
print("miscellaneousList: ${miscellaneousList.length}");
print("visaList: ${visaList.length}");
print("insuranceList: ${insuranceList.length}");
print("accommodationList: ${accommodationList.length}");
print("trainList: ${trainList.length}");
print("flightList: ${flightList.length}");
print("busList: ${busList.length}");
print("taxiList: ${taxiList.length}");
print("forexList: ${forexList.length}");
}
Future<void> checkExceptionalClass() async {
// pretend we fetch something
await Future.delayed(Duration(seconds: 1)); // Example async operation
@ -1850,6 +1909,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
onItineraryUpdate: handleItineraryUpdate,
onExeptionalClass: handleExcentionalClass,
loginUser: selfId,
selectedPlanData: planData,
isViewMode: widget.isViewMode,
),
@ -1945,12 +2005,49 @@ class CreateNewPlansState extends State<CreateNewPlan> {
focusStates["trip_typeFocused"] = hasFocus;
});
},
child: GestureDetector(
onTap: () {
print("TRIP CLICKESS1");
// Request focus when user taps
focusNodes["trip_typeFocusNode"]?.requestFocus();
print("TRIP CLICKESS15");
},
child: DropdownSearch<Map<String, dynamic>>(
onBeforePopupOpening: (selectedItem) async {
bool hasData = await serviceHasData();
if (hasData) {
bool? shouldProceed = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Changing trip type will remove added services",
),
content: Text("Do you wish to proceed?"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false); // Cancel
},
child: Text("Cancel"),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true); // Continue
},
child: Text("Continue"),
),
],
);
},
);
return shouldProceed ?? false;
}
return true;
},
enabled: !hasUpdateVal,
popupProps: PopupProps.menu(
showSearchBox: false, // Optionally enable search
fit: FlexFit.loose,
@ -2045,6 +2142,16 @@ class CreateNewPlansState extends State<CreateNewPlan> {
widget.isViewMode
? null
: (Map<String, dynamic>? newItem) {
final newTripType =
newItem?['dropdown_key'].toString();
print("newTripType - $newTripType");
print("_selectedTripType- $_selectedTripType");
if (newTripType != _selectedTripType) {
print("Type changed");
clearAllServiceLists();
dynamicItineraryKey.currentState
?.clearAllServiceLists();
}
if (newItem != null) {
setState(() {
_selectedTripType =
@ -2058,6 +2165,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
fetchTrainFlightClass(
int.parse(_selectedTripType!),
);
dynamicItineraryKey.currentState
?.updateSelectedServices();
});
@ -3073,6 +3181,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
{"title": "Others (Non Employee)", "value": "Option 3"},
];
print("isViewModeYY: ${widget.isViewMode}, hasUpdateVal: $hasUpdateVal");
return [
CustomTextFieldWrapper(
// isFocused: focusStates["trip_plannedFocused"] ?? false,
@ -3099,12 +3208,14 @@ class CreateNewPlansState extends State<CreateNewPlan> {
// Request focus when user taps
focusNodes["trip_plannedFocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem:
options.firstWhere(
(opt) => opt['value'] == _selectedOption,
)['title'],
enabled: !widget.isViewMode,
enabled: !hasUpdateVal,
// enabled: || !hasUpdateVal,
items: options.map((opt) => opt['title']!).toList(),
popupProps: PopupProps.menu(
showSearchBox: false,

View File

@ -104,6 +104,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
@override
void initState() {
print("DynamicItinerary");
super.initState();
handleSelectedPlan();
updateSelectedServices();
@ -128,7 +129,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
// selectedIndex = null;
// selectedItem = null;
// });
print("updateTripType - $_tripType");
updateTripType(widget.tripType);
}
}
@ -187,6 +188,9 @@ class DynamicItineraryState extends State<DynamicItinerary> {
_tripType = newTripType;
});
updateSelectedServices(); // Refresh services based on new tripType
print("updateTripType2 - $newTripType");
handleSelectedPlan();
}
}
@ -268,6 +272,13 @@ class DynamicItineraryState extends State<DynamicItinerary> {
}
}
void clearAllServiceLists() async {
print("clearAllServiceLists");
setState(() {
itineraryData.updateAll((key, value) => []);
});
}
// Future<void> updateSelectedServices() async {
// await loadAllServices();
// await loadOrgSelectedAlServices();
@ -389,6 +400,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
}
void handleSelectedPlan() {
print("handleSelectedPlan");
// Check if selectedPlanData has itinerary data
if (hasAnyItineraryData()) {
print("selectedPlanData HAS DATA");
@ -856,7 +868,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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -18,10 +18,10 @@ import '../../../services/apiService.dart';
import '../../../utils/pagination.dart';
import '../../../widgets/custom_breadcrumb_navigation.dart';
import '../../../widgets/popup_travelAgentList_action.dart';
/// import '../../../widgets/custom_popup.dart';
/// import '../../../../widgets/popup_TravelAgentList_action.dart';
class TravelAgentListScreen extends StatefulWidget {
@override
_TravelAgentListScreenState createState() => _TravelAgentListScreenState();
@ -144,7 +144,8 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
Future<List<dynamic>> fetchUsers() async {
// return [];
orgId = await getOrgId();
final String apiUrlData = '$apiUrl/api/agentList?org_id=$orgId&for=table_view';
final String apiUrlData =
'$apiUrl/api/agentList?org_id=$orgId&for=table_view';
final String? token = await getToken();
print("Fetch Users");
@ -459,15 +460,13 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
isDesktop: isDesktop,
breadcrumbItems: [
BreadcrumbItem(
title: 'Org Settings',
tooltip: 'Go To Organization Settings',
onTap: (context) {
context.go("/OrganizationSettings");
}
),
BreadcrumbItem(
title: 'Travel Agent',
title: 'Org Settings',
tooltip: 'Go To Organization Settings',
onTap: (context) {
context.go("/OrganizationSettings");
},
),
BreadcrumbItem(title: 'Travel Agent'),
],
),
),
@ -483,8 +482,8 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
),
if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.03),
// SizedBox(width: MediaQuery.of(context).size.width * 0.23),
// SizedBox(width: MediaQuery.of(context).size.width * 0.15),
// SizedBox(width: MediaQuery.of(context).size.width * 0.23),
// SizedBox(width: MediaQuery.of(context).size.width * 0.15),
if (isDesktop)
Container(
width: MediaQuery.of(context).size.width * 0.2,
@ -844,11 +843,12 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
DataCell(
Row(
mainAxisAlignment:
MainAxisAlignment.start,
MainAxisAlignment.start,
children: [
GestureDetector(
child: Tooltip(
message: 'Edit Travel Agent Details',
message:
'Edit Travel Agent Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
@ -858,12 +858,18 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
onTap: () async {
// Navigator.pop(context); // Close the menu
// final userId = user['user_id'];
final userId = int.parse(user['user_id'].toString());
final usersData = await apiService.getSingleUser(userId);
context.go("/CreateTravelAgent", extra: {
"selectedUser": usersData,
"isViewMode": false,
});
final userId = int.parse(
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
context.go(
"/CreateTravelAgent",
extra: {
"selectedUser": usersData,
"isViewMode": false,
},
);
},
),
],
@ -911,32 +917,48 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
child: Tooltip(
message: 'Edit Travel Agent Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
child: Tooltip(
message:
'Edit Travel Agent Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
onTap: () async {
Navigator.pop(context); // Close the menu
final userId = int.parse(user['user_id'].toString());
final usersData = await apiService.getSingleUser(userId);
context.go("/CreateTravelAgent", extra: {
),
onTap: () async {
// Navigator.pop(context); // Close the menu
// final userId = user['user_id'];
final userId = int.parse(
user['user_id'].toString(),
);
final usersData = await apiService
.getSingleUser(userId);
context.go(
"/CreateTravelAgent",
extra: {
"selectedUser": usersData,
"isViewMode": false,
});
},
),
],
),
},
);
},
// onTap: () async {
// Navigator.pop(context); // Close the menu
// final userId = int.parse(user['user_id'].toString());
// final usersData = await apiService.getSingleUser(userId);
// context.go("/CreateTravelAgent", extra: {
// "selectedUser": usersData,
// "isViewMode": false,
// });
// },
),
],
),
// UserActionsMenu(
// user: user,
// getUserDetails:
@ -1043,7 +1065,7 @@ class _TravelAgentListScreenState extends State<TravelAgentListScreen> {
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
CrossAxisAlignment.start,
children: [
Text(
"${user['company_name'] ?? ''}",

View File

@ -806,7 +806,10 @@ class PersonalDetailsState extends State<PersonalDetails> {
CustomTextFieldUserWrapper(
isFocused: focusStates["FnameFocused"] ?? false,
isDesktop: widget.isDesktop,
width: MediaQuery.of(context).size.width * 0.12,
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
child: SizedBox(
height: 40,
child: TextField(
@ -858,7 +861,10 @@ class PersonalDetailsState extends State<PersonalDetails> {
CustomTextFieldUserWrapper(
isFocused: focusStates["LnameFocused"] ?? false,
isDesktop: widget.isDesktop,
width: MediaQuery.of(context).size.width * 0.12,
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
child: SizedBox(
height: 40,
child: TextField(
@ -1210,7 +1216,10 @@ class PersonalDetailsState extends State<PersonalDetails> {
CustomTextFieldUserWrapper(
isFocused: focusStates["mobileNumberFocused"] ?? false,
isDesktop: widget.isDesktop,
width: MediaQuery.of(context).size.width * 0.12,
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
child: SizedBox(
height: 40,
child: TextField(
@ -1274,7 +1283,10 @@ class PersonalDetailsState extends State<PersonalDetails> {
// isFocused: false,
isFocused: focusStates["alternateMobileFocused"] ?? false,
isDesktop: widget.isDesktop,
width: MediaQuery.of(context).size.width * 0.12,
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.12
: null,
child: SizedBox(
height: 40,
child: TextField(
@ -1353,161 +1365,175 @@ class PersonalDetailsState extends State<PersonalDetails> {
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: focusNodes["countryFocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["countryFocused"] = hasFocus;
});
},
child: GestureDetector(
onTap: () {
// Request focus when user taps
focusNodes["countryFocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
// (context, item, isSelected) => Container(
// padding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 6,
// ),
// child: Text(
// item,
// style: GoogleFonts.poppins(fontSize: 11.5),
// ),
// ),
(context, item, isSelected) {
print("contryItem - $item");
final match = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(item);
final countryName = match?.group(1) ?? '';
final countryCode = match?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 6.0,
),
child: Padding(
// padding: const EdgeInsets.all(3.0),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
countryName,
style: GoogleFonts.poppins(fontSize: 11.5),
),
Text(
countryCode,
style: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
),
],
),
),
);
height: 40,
width: double.infinity,
child: Focus(
focusNode: focusNodes["countryFocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["countryFocused"] = hasFocus;
});
},
child: GestureDetector(
onTap: () {
// Request focus when user taps
focusNodes["countryFocusNode"]?.requestFocus();
},
constraints: BoxConstraints(maxHeight: 180),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Country...",
contentPadding: EdgeInsets.symmetric(
horizontal: 3,
vertical: 3,
),
),
),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["countryFocused"] ?? false)
? (layoutColor ?? Colors.blue)
: Colors.white,
// width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["countryFocused"] ?? false)
? (layoutColor ?? Colors.blue)
: Colors.white,
// width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color : (layoutColor ?? Colors.grey), width: 1),
),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0,),
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
// Center-align selected item
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Country",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
enabled: !widget.isViewMode,
popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder:
// (context, item, isSelected) => Container(
// padding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 6,
// ),
// child: Text(
// item,
// style: GoogleFonts.poppins(fontSize: 11.5),
// ),
// ),
(context, item, isSelected) {
print("contryItem - $item");
final match = RegExp(
r'^(.*)\s\((.*)\)$',
).firstMatch(item);
final countryName = match?.group(1) ?? '';
final countryCode = match?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 6.0,
),
child: Padding(
// padding: const EdgeInsets.all(3.0),
padding: EdgeInsets.symmetric(
horizontal: 2,
vertical: 3,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
countryName,
style: GoogleFonts.poppins(fontSize: 11.5),
),
Text(
countryCode,
style: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
),
],
),
),
);
},
constraints: BoxConstraints(maxHeight: 180),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Country...",
contentPadding: EdgeInsets.symmetric(
horizontal: 3,
vertical: 3,
),
),
),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["countryFocused"] ?? false)
? (layoutColor ?? Colors.blue)
: Colors.white,
// width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["countryFocused"] ?? false)
? (layoutColor ?? Colors.blue)
: Colors.white,
// width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: (layoutColor ?? Colors.grey),
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 8.0,
),
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
// Center-align selected item
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Country",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
// onChanged: widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// // Find the country_code based on selected country_name
// selectedCountry = countryMap.entries
// .firstWhere((entry) => entry.value == newValue)
// .key;
//
// // if (selectedCountry!.isNotEmpty) {
// // errorMessages.remove("country_code");
// // }
// });
// widget.onCountryChanged?.call(newValue);
// },
onChanged:
widget.isViewMode
? null
: (String? newValue) {
if (newValue == null) return;
// onChanged: widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// // Find the country_code based on selected country_name
// selectedCountry = countryMap.entries
// .firstWhere((entry) => entry.value == newValue)
// .key;
//
// // if (selectedCountry!.isNotEmpty) {
// // errorMessages.remove("country_code");
// // }
// });
// widget.onCountryChanged?.call(newValue);
// },
onChanged:
widget.isViewMode
? null
: (String? newValue) {
if (newValue == null) return;
final countryCode =
countryMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
final countryCode =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
setState(() {
selectedCountry = countryCode;
});
setState(() {
selectedCountry = countryCode;
});
widget.onCountryChanged?.call(
countryCode,
); // send code not name
},
),),),
widget.onCountryChanged?.call(
countryCode,
); // send code not name
},
),
),
),
),
),
],

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}");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
// import 'package:flutter/rendering.dart';
import 'dart:html' as html;
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
import 'package:frontend/services/apiService.dart';
@ -34,8 +34,8 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
SemanticsBinding.instance
.ensureSemantics(); // Safe here -only for testing uncomment, Otherwise Email Template wont allow to type
// SemanticsBinding.instance
// .ensureSemantics(); // Safe here -only for testing uncomment, Otherwise Email Template wont allow to type
if (kIsWeb) {
final uri = Uri.parse(html.window.location.href);
print("URI - $uri");
@ -76,7 +76,7 @@ class _MyAppState extends State<MyApp> {
});
html.window.console.log("Auth code detected: $authCode");
}else {
} else {
html.window.console.log("No auth code found or wrong path.");
}
}
@ -110,32 +110,34 @@ class _MyAppState extends State<MyApp> {
setState(() {
_isloading = false;
});
if(_isloading){ const CircularProgressIndicator(); }
if (_isloading) {
const CircularProgressIndicator();
}
final userData = prefs.getString('user_data');
print("MS Userdata - $userData");
final orgDataString = prefs.getString('org_data');
print("MS orgdata - $orgDataString");
if (orgDataString != null && userData != null){
Fluttertoast.showToast(
msg: "You're in!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
);
if (orgDataString != null && userData != null) {
Fluttertoast.showToast(
msg: "You're in!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
);
print("Microsoft User Logged In Refer the Role - $userRole");
// Navigate based on role
if (userRole == "Travel Agent") {
router.go('/listTravelAgentPlan');
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
router.go('/StatusDashboard');
} else {
router.go('/listPlan');
}
print("Microsoft User Logged In Refer the Role - $userRole");
// Navigate based on role
if (userRole == "Travel Agent") {
router.go('/listTravelAgentPlan');
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
router.go('/StatusDashboard');
} else {
router.go('/listPlan');
}
}
} else {
throw Exception('Token missing in response.');
@ -172,7 +174,10 @@ class _MyAppState extends State<MyApp> {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('auth_token', token);
await prefs.setString('user_data', jsonEncode(userData)); // Store full user data
await prefs.setString(
'user_data',
jsonEncode(userData),
); // Store full user data
if (userData != null) {
final pref = await SharedPreferences.getInstance();
@ -188,7 +193,6 @@ class _MyAppState extends State<MyApp> {
print("MicroSoft Started");
await apiService.getOrganizationData();
print("MicroSoft end");
} catch (e) {
print('Error decoding token MS: $e');
router.go('/');
@ -197,12 +201,9 @@ class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
if (_isAuthRedirect) {
return const MaterialApp(
home: Scaffold(
body: Center(child: CircularProgressIndicator()),
),
home: Scaffold(body: Center(child: CircularProgressIndicator())),
);
}

View File

@ -14,7 +14,6 @@ const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be';
* Check File : App.dart -> line 37 need to comment it "SemanticsBinding" **/
// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
/** Note : Adfactor UAT BE URL
* incase "aujas" or "tstat" href means changed to "adfactor"
* File : web/index.html - change below

View File

@ -20,6 +20,7 @@ class Plan {
final String createdOn;
final String? approverId;
final String? delegaterId;
final String? forexId;
Plan({
required this.planId,
@ -41,6 +42,7 @@ class Plan {
required this.createdOn,
this.approverId,
this.delegaterId,
this.forexId,
});
factory Plan.fromJson(Map<String, dynamic> json) {
@ -55,8 +57,9 @@ class Plan {
? ''
: json['approver_status']?.toString() ?? "",
status: json['status'] == "0" ? "Inactive" : "Active",
costCenter: json['cost_center_value']?.toString() ?? "" ,
functionalDepartment: json['functional_department_value']?.toString() ?? "",
costCenter: json['cost_center_value']?.toString() ?? "",
functionalDepartment:
json['functional_department_value']?.toString() ?? "",
purposeOfTravel: json['purpose_of_travel_value']?.toString() ?? "",
soNumber: json['so_number']?.toString() ?? "",
description: json['description']?.toString() ?? "",
@ -73,9 +76,15 @@ class Plan {
statusValue: json["status_value"]?.toString() ?? "",
createdOn: json["created_on"]?.toString() ?? "",
approverId:
json["approver_id"] == null ? '' : json['approver_id']?.toString() ?? "",
json["approver_id"] == null
? ''
: json['approver_id']?.toString() ?? "",
delegaterId:
json["delegater_id"] == null ? '' : json['delegater_id']?.toString() ?? "",
json["delegater_id"] == null
? ''
: json['delegater_id']?.toString() ?? "",
forexId:
json["forex_id"] == null ? '' : json['forex_id']?.toString() ?? "",
);
}
}

View File

@ -71,7 +71,7 @@ class PlanPopupMenu extends StatelessWidget {
IconButton(
icon: Icon(
Icons.download,
color: Color(0xFF114D8B),
color: Color(0xFF475569),
size: 18,
),
onPressed: () {
@ -79,6 +79,22 @@ class PlanPopupMenu extends StatelessWidget {
apiService.getPdfDownload(plan.planId);
},
),
if (plan.statusValue == "Approved" &&
plan.forexId != null &&
plan.forexId != '')
IconButton(
icon: Icon(
Icons.monetization_on_outlined,
color: Color(0xFF475569),
size: 18,
),
tooltip: 'Download Forex PDF',
onPressed: () {
Navigator.pop(context);
apiService.getPdfDownload(plan.forexId);
},
),
IconButton(
icon: const Icon(
Icons.comment,