ui changes
This commit is contained in:
parent
d59aaf90bc
commit
36d3b365be
@ -67,14 +67,28 @@ Future<String?> showRejectDialog(
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text("Please enter remarks to reject the plan."),
|
||||
const Text("Please enter reason for rejection."),
|
||||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
maxLines: 3,
|
||||
onChanged: (value) => remarks = value,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Remarks...",
|
||||
border: OutlineInputBorder(),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, // 👈 Set your desired font size here
|
||||
color: Colors.grey,
|
||||
fontFamily:
|
||||
"Archivo", // optional if you want consistent font
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/config/apiUrl.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@ -275,13 +276,23 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: buildTableLayout(isDesktop),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTableLayout(isDesktop) {
|
||||
String _formatDate(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd MMM yy : hh a').format(dateTime);
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop
|
||||
? EdgeInsets.all(10.0)
|
||||
@ -414,7 +425,9 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
constraints: BoxConstraints(
|
||||
minWidth: minWidth,
|
||||
),
|
||||
child: DataTable(
|
||||
dividerThickness: 0.5,
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
@ -494,7 +507,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
fontSize: 13,
|
||||
fontFamily: "Archivo",
|
||||
))),
|
||||
DataCell(Text(plan.createdOn,
|
||||
DataCell(Text(
|
||||
|
||||
// plan.createdOn,
|
||||
_formatDate(plan.createdOn),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Archivo",
|
||||
|
||||
@ -191,6 +191,10 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
_buildLabel("Email Address"),
|
||||
TextFormField(
|
||||
controller: _emailController,
|
||||
style: TextStyle(
|
||||
fontFamily: "Archivo",
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 11),
|
||||
decoration: _inputDecoration("Enter your email address").copyWith(
|
||||
prefixIcon: Icon(
|
||||
Icons.email_outlined,
|
||||
@ -207,6 +211,10 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
_buildLabel("Password"),
|
||||
TextFormField(
|
||||
controller: _passwordController,
|
||||
style: TextStyle(
|
||||
fontFamily: "Archivo",
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 11),
|
||||
obscureText: _obscureText,
|
||||
decoration: _inputDecoration("Enter your password").copyWith(
|
||||
prefixIcon: Icon(
|
||||
|
||||
@ -78,14 +78,13 @@ class _groupState extends State<Group> {
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
loadAllServices();
|
||||
|
||||
for (var field in dataHeader) {
|
||||
controllers[field] = TextEditingController();
|
||||
}
|
||||
updateData();
|
||||
loadInitialData();
|
||||
});
|
||||
|
||||
for (var field in dataHeader) {
|
||||
controllers[field] = TextEditingController();
|
||||
}
|
||||
|
||||
updateData();
|
||||
}
|
||||
|
||||
void loadInitialData() async {
|
||||
@ -342,13 +341,15 @@ class _groupState extends State<Group> {
|
||||
// margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
child: buildOrganizationLayout(isDesktop),
|
||||
),
|
||||
),
|
||||
@ -386,6 +387,7 @@ class _groupState extends State<Group> {
|
||||
)
|
||||
: null,
|
||||
color: Colors.white,
|
||||
|
||||
// color: Color(0xFFF7F7FB),
|
||||
|
||||
// color: Colors.amber,
|
||||
|
||||
@ -148,7 +148,8 @@ class _GroupListState extends State<GroupList> {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: buildGroupData(isDesktop),
|
||||
);
|
||||
|
||||
@ -725,7 +725,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -657,7 +657,7 @@ class _BusScreenState extends State<BusScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -628,6 +628,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownButtonFormField<String>(
|
||||
isExpanded: true,
|
||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||
focusNode: focusNodes["_tripType1FocusNode"],
|
||||
value: selectedTripType,
|
||||
@ -1292,7 +1293,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -201,7 +201,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
"country_code",
|
||||
"deposit_on_card",
|
||||
"deposit_on_cash",
|
||||
"card_number"
|
||||
// "card_number"
|
||||
];
|
||||
|
||||
// If have_card is "1", then delivery_location is required
|
||||
@ -932,7 +932,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
height: 8,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Currency *",
|
||||
@ -946,19 +946,24 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
isFocused: focusStates["_currencyFocused"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
color: Colors.transparent,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.330
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
// "cur",
|
||||
// "${selectedCurrency}",
|
||||
selectedCurrency ?? "Currency",
|
||||
// selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
child: Center(
|
||||
child: Text(
|
||||
// "cur",
|
||||
// "${selectedCurrency}",
|
||||
selectedCurrency ?? "Currency",
|
||||
// selectedCurrency?.isNotEmpty == true ? selectedCurrency! : "Currency",
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1012,46 +1017,13 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
// if (isDesktop)
|
||||
// Spacer()
|
||||
// else
|
||||
// SizedBox(
|
||||
// height: 8,
|
||||
// ),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Quoted Amount",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_perdiemAmount"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
// "amo",
|
||||
selectedQuotedAmount ?? "0",
|
||||
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// if (isDesktop)Spacer() else SizedBox(height: 8,),
|
||||
];
|
||||
}
|
||||
@ -1268,7 +1240,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldForexWrapper(
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_cash"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
@ -1321,7 +1293,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldForexWrapper(
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_card"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
@ -1355,6 +1327,47 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
],
|
||||
),
|
||||
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Total Amount",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_perdiemAmount"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
// "amo",
|
||||
selectedQuotedAmount ?? "0",
|
||||
// selectedPerdiemAmount?.isNotEmpty == true ? selectedPerdiemAmount! : "Amount",
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
@ -1406,19 +1419,20 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Card Number*",
|
||||
"Card Number",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldForexWrapper(
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_cardNumber"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
enabled: !isChecked,
|
||||
focusNode: focusNodes["_cardNumber"],
|
||||
controller: textControllers["_cardNumber"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
@ -1463,7 +1477,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
false, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.464
|
||||
? MediaQuery.of(context).size.width * 0.330
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: TextField(
|
||||
focusNode: focusNodes["_deliveryLocation"],
|
||||
@ -1511,7 +1525,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
focusStates["_comments"] ?? false, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.464
|
||||
? MediaQuery.of(context).size.width * 0.330
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: TextField(
|
||||
focusNode: focusNodes["_comments"],
|
||||
@ -1547,6 +1561,10 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
isChecked = value!;
|
||||
if (isChecked) {
|
||||
textControllers["_cardNumber"]
|
||||
?.clear(); // Clear the value when isChecked is true
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
@ -1589,7 +1607,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -595,7 +595,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -379,7 +379,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -785,7 +785,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -748,7 +748,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -601,7 +601,7 @@ class _VisaScreenState extends State<VisaScreen> {
|
||||
handleSave();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue, // Primary color for save
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class AccomodationListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> accommodationList;
|
||||
@ -18,149 +19,386 @@ class AccomodationListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Accomodation Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Accomodation Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Accomodation", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Accomodation", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Destination City')),
|
||||
DataColumn(label: Text('Hotel Name')),
|
||||
DataColumn(label: Text('CheckIn Date')),
|
||||
DataColumn(label: Text('CheckOut Date')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
accommodationList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
final Map<String, dynamic> item = entry.value;
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
|
||||
DataCell(Text(item["destination_city"]!)),
|
||||
DataCell(Text(item["hotel_name"]!)),
|
||||
DataCell(Text(item["checkin_date"]!)),
|
||||
DataCell(Text(item["checkout_date"]!)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Accomodation"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteAccommodation(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
))
|
||||
String formatTime(String timeString) {
|
||||
try {
|
||||
final parts = timeString.split(':');
|
||||
final now = DateTime.now();
|
||||
final dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
int.parse(parts[0]),
|
||||
int.parse(parts[1]),
|
||||
);
|
||||
return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM
|
||||
} catch (e) {
|
||||
return "Invalid Time";
|
||||
}
|
||||
}
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Accomodation");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteAccommodation(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )),
|
||||
//
|
||||
]);
|
||||
}).toList();
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
item["hotel_name"]!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Accomodation"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteAccommodation(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" DestinationCity",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Check (in) ",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Check (out) ",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(item["destination_city"],
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: 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"),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 20,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: exceedsLimit
|
||||
? Tooltip(
|
||||
message: wrapText(value, 50),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200, // Black background
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
textStyle:
|
||||
TextStyle(color: Colors.black), // Tooltip text color
|
||||
padding: EdgeInsets.all(8),
|
||||
preferBelow: false,
|
||||
child: Text(value.substring(0, limit) + "...",
|
||||
style: TextStyle(fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateTimeRow(String title, String date, String time) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"$date, $time",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@ -25,161 +26,359 @@ class BusListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Bus Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Bus Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Bus", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Bus", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
// color: Colors.blueGrey,
|
||||
width: double.infinity,
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
// child: Expanded(
|
||||
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('From')),
|
||||
DataColumn(label: Text('To')),
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Time')),
|
||||
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
|
||||
// )
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
busList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
final Map<String, dynamic> item = entry.value;
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
|
||||
DataCell(Text(item["from"]!)),
|
||||
DataCell(Text(item["to"]!)),
|
||||
DataCell(Text(item["date"]!)),
|
||||
DataCell(Text(item["time"]!)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Bus"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteBus(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
String formatTime(String timeString) {
|
||||
try {
|
||||
final parts = timeString.split(':');
|
||||
final now = DateTime.now();
|
||||
final dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
int.parse(parts[0]),
|
||||
int.parse(parts[1]),
|
||||
);
|
||||
return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM
|
||||
} catch (e) {
|
||||
return "Invalid Time";
|
||||
}
|
||||
}
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Bus");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteBus(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Bus"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteBus(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
" Planned Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
" Date",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text("${item["from"]} - ${item["to"]} ",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
"${formatDate(item["date"]!)} ${formatTime(item["time"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: 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"]!),
|
||||
),
|
||||
_buildRow("Comments:", item["comments"] ?? "N/A"),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 30,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: exceedsLimit
|
||||
? Tooltip(
|
||||
message: wrapText(value, 50),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200, // Black background
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
textStyle:
|
||||
TextStyle(color: Colors.black), // Tooltip text color
|
||||
padding: EdgeInsets.all(8),
|
||||
preferBelow: false,
|
||||
child: Text(value.substring(0, limit) + "...",
|
||||
style: TextStyle(fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateTimeRow(String title, String date, String time) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"$date, $time",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class FlightListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> flightList;
|
||||
final Function(bool, Map<String, dynamic>, String) onOpen;
|
||||
final Function(Map<String, dynamic>) onDeleteFlight;
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
final Function(String, bool) onAddNew;
|
||||
final bool isViewMode;
|
||||
@ -14,161 +16,324 @@ class FlightListWidget extends StatelessWidget {
|
||||
required this.onOpen,
|
||||
required this.onDeleteFlight,
|
||||
required this.onAddNew,
|
||||
required this.apiData,
|
||||
required this.isViewMode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Flight Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Flight Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Flight", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Flight", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
flightList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
List<dynamic> visatypeList = apiData?['flight_class'] ?? [];
|
||||
|
||||
String getRequestForClass(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
return visatypeList
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
String formatTime(String timeString) {
|
||||
try {
|
||||
final parts = timeString.split(':');
|
||||
final now = DateTime.now();
|
||||
final dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
int.parse(parts[0]),
|
||||
int.parse(parts[1]),
|
||||
);
|
||||
return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM
|
||||
} catch (e) {
|
||||
return "Invalid Time";
|
||||
}
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
// width: 1000,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Trip Type')),
|
||||
DataColumn(label: Text('From')),
|
||||
DataColumn(label: Text('To')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
item["trip_type"]?.toString() ?? "N/A",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Flight"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteFlight(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Class",
|
||||
style: TextStyle(fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Planned Trips",
|
||||
style: TextStyle(fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Date",
|
||||
style: TextStyle(fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Time",
|
||||
style: TextStyle(fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
// Trip Rows
|
||||
|
||||
if (isDesktop)
|
||||
if (item["trips"] != null && item["trips"].isNotEmpty)
|
||||
...item["trips"].map<Widget>((trip) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
getRequestForClass(trip["class"].toString()) ??
|
||||
"N/A",
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
formatDate(trip["date"] ?? ""),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(formatTime(trip["time"] ?? ""),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
if (!isDesktop &&
|
||||
item["trips"] != null &&
|
||||
item["trips"].isNotEmpty)
|
||||
...item["trips"].map<Widget>((trip) {
|
||||
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 - To",
|
||||
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}"),
|
||||
_buildKeyValueRow(
|
||||
"Date", formatDate(trip["date"] ?? "")),
|
||||
_buildKeyValueRow(
|
||||
"Time", formatTime(trip["time"] ?? "")),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildKeyValueRow(String key, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 80, // adjust width as needed
|
||||
child: Text(
|
||||
"$key:",
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
flightList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
Map<String, dynamic> item = entry.value;
|
||||
print("Trip Type: ${item["trip_type"]}");
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")),
|
||||
DataCell(Text(item["trip_type"]?.toString() ?? "N/A")),
|
||||
DataCell(Text(item["trips"].isNotEmpty
|
||||
? item["trips"][0]["from_place"]?.toString() ?? "N/A"
|
||||
: "N/A")),
|
||||
DataCell(Text(item["trips"].isNotEmpty
|
||||
? item["trips"][0]["to_place"]?.toString() ?? "N/A"
|
||||
: "N/A")),
|
||||
|
||||
DataCell(
|
||||
Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Flight"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteFlight(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
//
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Flight");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteFlight(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
//
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class ForexListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> forexList;
|
||||
final Function(bool, Map<String, dynamic>, String) onOpen;
|
||||
final Function(Map<String, dynamic>) onDeleteForex;
|
||||
final List<dynamic>? apiCountryData;
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
final Function(String, bool) onAddNew;
|
||||
final bool isViewMode;
|
||||
@ -18,107 +20,100 @@ class ForexListWidget extends StatelessWidget {
|
||||
required this.onDeleteForex,
|
||||
required this.apiCountryData,
|
||||
required this.onAddNew,
|
||||
required this.apiData,
|
||||
required this.isViewMode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Forex List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Forex List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Forex", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Forex", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
// color: Colors.blueGrey,
|
||||
width: double.infinity,
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Forex Start Date')),
|
||||
DataColumn(label: Text('Forex End Date')),
|
||||
DataColumn(label: Text('Country')),
|
||||
DataColumn(label: Text('Perdiem Amount')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
//
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
List<dynamic> countryList = apiCountryData ?? [];
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
forexList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
List<dynamic> visatypeList = apiData?['visa_type_of_visa'] ?? [];
|
||||
List<dynamic> countryList = apiCountryData ?? [];
|
||||
|
||||
String getRequestForVisa(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
return visatypeList
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String getRequestForCountry(String? countryCode) {
|
||||
if (countryCode == null) return "N/A";
|
||||
|
||||
@ -130,64 +125,296 @@ class ForexListWidget extends StatelessWidget {
|
||||
.toString();
|
||||
}
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
Map<String, dynamic> item = entry.value;
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
|
||||
DataCell(Text(item["start_date"] ?? "N/A")),
|
||||
DataCell(Text(item["end_date"] ?? "N/A")),
|
||||
DataCell(Text(getRequestForCountry(item["country_code"]!.toString()))),
|
||||
// DataCell(Text(item["country_code"] ?? "N/A")),
|
||||
DataCell(Text(item["perdiem_amount"] ?? "N/A")),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Forex"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteForex(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Forex");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteForex(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
getRequestForCountry(item["country_code"]!.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Forex"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteForex(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Currency",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Duration",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Time Period ",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
// Expanded(
|
||||
// flex: 2,
|
||||
// child: Text(
|
||||
// " Total ",
|
||||
// style: TextStyle(
|
||||
// fontSize: 11, fontFamily: "Archivo"),
|
||||
// )),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item["currency"],
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
item["duration"],
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" ${formatDate(item["start_date"]!)} ${formatDate(item["end_date"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
// Expanded(
|
||||
// flex: 2,
|
||||
// child: Text(
|
||||
// " ",
|
||||
// style: TextStyle(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// fontFamily: "Archivo"),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildRow(
|
||||
"Currency:",
|
||||
item["currency"],
|
||||
),
|
||||
// SizedBox(height: 6),
|
||||
_buildRow(
|
||||
"Duration:",
|
||||
item["duration"],
|
||||
),
|
||||
// SizedBox(height: 6),
|
||||
_buildRow("StartDate:", item["start_date"]!),
|
||||
_buildRow("EndDate:", item["end_date"]!),
|
||||
// SizedBox(height: 6),
|
||||
_buildRow("Comments:", item["comments"] ?? "N/A"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 30,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:js_interop';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class InsuranceListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> insuranceList;
|
||||
@ -22,12 +23,15 @@ class InsuranceListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -79,35 +83,290 @@ class InsuranceListWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Insurance Type')),
|
||||
DataColumn(label: Text('Start Date')),
|
||||
DataColumn(label: Text('End Date')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
insuranceList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
List<dynamic> insurancetypeList =
|
||||
apiData?['insurance_type_of_insurance'] ?? [];
|
||||
|
||||
String getRequestForInsuranceType(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
return insurancetypeList
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
String getRequestValue(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
return (apiData?['miscellaneous_special_request'] ?? [])
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Insurance"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteInsurance(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" InsuranceType",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Time Period ",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
getRequestForInsuranceType(
|
||||
item["type_of_insurance"]!.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${formatDate(item["start_date"]!)} ${formatDate(item["end_date"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: 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"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 20,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRow(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
"Special Request:": 30,
|
||||
"Comments:": 70,
|
||||
// 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: TextStyle(fontWeight: FontWeight.w600, 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, fontSize: 12), // 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
insuranceList.where((item) => item["is_active"] == "1").toList();
|
||||
|
||||
@ -19,18 +19,21 @@ class MiscellaneousListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Miscellaneous Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
"Miscellaneous List",
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
@ -52,23 +55,15 @@ class MiscellaneousListWidget extends StatelessWidget {
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Miscellaneous", true);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min, // Ensures content fits nicely
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Add New",
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
SizedBox(width: 8), // spacing between icon and text
|
||||
Icon(
|
||||
Icons.add_circle_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
Text("Add New", style: TextStyle(fontSize: 13)),
|
||||
SizedBox(width: 8),
|
||||
Icon(Icons.add_circle_outline_rounded,
|
||||
size: 15, color: Colors.white),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -76,118 +71,305 @@ class MiscellaneousListWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Special Request')),
|
||||
DataColumn(label: Text('Comments')),
|
||||
// DataColumn(label: Text('Created On')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Scroll behavior based on device
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
print("miscellaneousList - $miscellaneousList");
|
||||
List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
|
||||
|
||||
print("purposeList - $purposeList");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
miscellaneousList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
int index = entry.key + 1; // To start index from 1
|
||||
Map<String, dynamic> item = entry.value;
|
||||
print(item);
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
|
||||
// DataCell(Text(specialRequestValue)),
|
||||
DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
|
||||
DataCell(Text(item["comments"] ?? "N/A")),
|
||||
// DataCell(Text(item["created_on"] ?? "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
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Miscellaneous");
|
||||
// // Edit action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteMiscellaneous(item);
|
||||
// // Delete action
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
String getRequestValue(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
return (apiData?['miscellaneous_special_request'] ?? [])
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.yellow.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Special Request",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
getRequestValue(
|
||||
item["special_request"]?.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Text(item["comments"],
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
_buildRow(
|
||||
"Special Request:",
|
||||
getRequestValue(
|
||||
item["special_request"]?.toString())),
|
||||
SizedBox(width: 10),
|
||||
_buildRow("Comments:", item["comments"] ?? "N/A"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 40,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRow(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
"Special Request:": 30,
|
||||
"Comments:": 70,
|
||||
// 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: TextStyle(fontWeight: FontWeight.w600, 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, 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();
|
||||
// }
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class TaxiListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> taxiList;
|
||||
final Function(bool, Map<String, dynamic>, String) onOpen;
|
||||
final Function(Map<String, dynamic>) onDeleteTaxi;
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
final Function(String, bool) onAddNew;
|
||||
final bool isViewMode;
|
||||
@ -11,6 +13,7 @@ class TaxiListWidget extends StatelessWidget {
|
||||
const TaxiListWidget(
|
||||
{super.key,
|
||||
required this.taxiList,
|
||||
required this.apiData,
|
||||
required this.onOpen,
|
||||
required this.onDeleteTaxi,
|
||||
required this.onAddNew,
|
||||
@ -18,153 +21,411 @@ class TaxiListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Taxi Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Taxi Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Taxi", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Taxi", 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_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Destination')),
|
||||
DataColumn(label: Text('Location Of Pickup')),
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Taxi Required For')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
taxiList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
final Map<String, dynamic> item = entry.value;
|
||||
List<dynamic> taxiClassList = apiData?['taxt_car_type'] ?? [];
|
||||
List<dynamic> taxirequiredFor = apiData?['taxi_car_required_for'] ?? [];
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")), // Index column
|
||||
DataCell(Text(item["destination_city"]!)),
|
||||
DataCell(Text(item["location_of_pickup"]!)),
|
||||
DataCell(Text(item["date"]!)),
|
||||
DataCell(Text(item["car_required_for"]!)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Taxi"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteTaxi(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
String getRequestForTaxiClass(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Taxi");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteTaxi(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
//
|
||||
return taxiClassList
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String getRequestFortaxirequiredFor(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
return taxirequiredFor
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
String formatTime(String timeString) {
|
||||
try {
|
||||
final parts = timeString.split(':');
|
||||
final now = DateTime.now();
|
||||
final dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
int.parse(parts[0]),
|
||||
int.parse(parts[1]),
|
||||
);
|
||||
return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM
|
||||
} catch (e) {
|
||||
return "Invalid Time";
|
||||
}
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"${getRequestForTaxiClass(item["car_type"]!.toString())} For ${item["no_of_passengers"]!} Passernger",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Taxi"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => (item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Class",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Planned Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Date",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text("${item["destination_city"]}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text("${item["location_of_pickup"]}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${formatDate(item["date"]!)} ${formatTime(item["time"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
" Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: 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"),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: exceedsLimit
|
||||
? Tooltip(
|
||||
message: wrapText(value, 50),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200, // Black background
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
textStyle:
|
||||
TextStyle(color: Colors.black), // Tooltip text color
|
||||
padding: EdgeInsets.all(8),
|
||||
preferBelow: false,
|
||||
child: Text(value.substring(0, limit) + "...",
|
||||
style: TextStyle(fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateTimeRow(String title, String date, String time) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"$date, $time",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class TrainListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> trainList;
|
||||
@ -6,6 +7,7 @@ class TrainListWidget extends StatelessWidget {
|
||||
final Function(Map<String, dynamic>) onDeleteTrain;
|
||||
final Function(String, bool) onAddNew;
|
||||
final bool isViewMode;
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
const TrainListWidget({
|
||||
super.key,
|
||||
@ -14,16 +16,20 @@ class TrainListWidget extends StatelessWidget {
|
||||
required this.onDeleteTrain,
|
||||
required this.onAddNew,
|
||||
required this.isViewMode,
|
||||
required this.apiData,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -75,100 +81,340 @@ class TrainListWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Train Number')),
|
||||
// DataColumn(label: Text('Class')),
|
||||
DataColumn(label: Text('From')),
|
||||
// DataColumn(label: Text('To')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
trainList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
// print("filteredList- $filteredList");
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
final Map<String, dynamic> item = entry.value;
|
||||
List<dynamic> trainClassList = apiData?['train_class'] ?? [];
|
||||
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")),
|
||||
String getRequestForTrainClass(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
|
||||
DataCell(Text(item["train_no"]!)),
|
||||
// DataCell(Text(item["class"]!)),
|
||||
DataCell(Text(item["from_station"]!)),
|
||||
// DataCell(Text(item["to_station"]!)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Train"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
return trainClassList
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element["dropdown_key"].toString() == specialRequestKey,
|
||||
orElse: () => {"dropdown_value": "N/A"},
|
||||
)["dropdown_value"]
|
||||
.toString();
|
||||
}
|
||||
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
String formatTime(String timeString) {
|
||||
try {
|
||||
final parts = timeString.split(':');
|
||||
final now = DateTime.now();
|
||||
final dateTime = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
int.parse(parts[0]),
|
||||
int.parse(parts[1]),
|
||||
);
|
||||
return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM
|
||||
} catch (e) {
|
||||
return "Invalid Time";
|
||||
}
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteTrain(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
item["train_no"]?.toString() ?? "N/A",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Train"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteTrain(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Class",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Planned Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Date",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${getRequestForTrainClass(item["class"]!.toString())} ",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${item["from_station"]!} ${(item["to_station"])}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"))),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${formatDate(item["date"]!)} ${formatTime(item["time"]!)}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo")),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_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"),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.keyboard_arrow_down_outlined,
|
||||
size: 28, color: Color(0xFF475569)),
|
||||
onPressed: () {
|
||||
// Expand logic
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Train");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteTrain(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
//
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 30,
|
||||
// Add more keys and limits if needed
|
||||
};
|
||||
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: exceedsLimit
|
||||
? Tooltip(
|
||||
message: wrapText(value, 50),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200, // Black background
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
textStyle:
|
||||
TextStyle(color: Colors.black), // Tooltip text color
|
||||
padding: EdgeInsets.all(8),
|
||||
preferBelow: false,
|
||||
child: Text(value.substring(0, limit) + "...",
|
||||
style: TextStyle(fontSize: 12),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDateTimeRow(String title, String date, String time) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"$date, $time",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class VisaListWidget extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> visaList;
|
||||
@ -22,18 +23,21 @@ class VisaListWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Header with title and button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Visa Booking List",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
@ -59,19 +63,12 @@ class VisaListWidget extends StatelessWidget {
|
||||
onAddNew("Visa", true);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min, // Ensures content fits nicely
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Add New",
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
SizedBox(width: 8), // spacing between icon and text
|
||||
Icon(
|
||||
Icons.add_circle_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
Text("Add New", style: TextStyle(fontSize: 13)),
|
||||
SizedBox(width: 8),
|
||||
Icon(Icons.add_circle_outline_rounded,
|
||||
size: 15, color: Colors.white),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -79,36 +76,102 @@ class VisaListWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: DataTable(
|
||||
border: TableBorder(
|
||||
bottom: BorderSide(color: Colors.black12),
|
||||
horizontalInside: BorderSide(
|
||||
color: Colors.black12), // Only horizontal lines
|
||||
),
|
||||
columns: const [
|
||||
// DataColumn(label: Text('#')),
|
||||
DataColumn(label: Text('Type of Visa')),
|
||||
DataColumn(label: Text('Country')),
|
||||
DataColumn(label: Text('Start Date')),
|
||||
DataColumn(label: Text('Actions')),
|
||||
],
|
||||
rows: _buildDataRows(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Scroll behavior based on device
|
||||
|
||||
_buildData(context, isDesktop)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
// Widget build(BuildContext context) {
|
||||
// return Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Container(
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
// children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Visa Booking List",
|
||||
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// MouseRegion(
|
||||
// cursor: isViewMode
|
||||
// ? SystemMouseCursors.forbidden
|
||||
// : SystemMouseCursors.click,
|
||||
// child: ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// backgroundColor: Color(0xFF114D8B),
|
||||
// foregroundColor: Colors.white,
|
||||
// disabledBackgroundColor: Color(0xFF114D8B),
|
||||
// disabledForegroundColor: Colors.white,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
// ),
|
||||
// padding:
|
||||
// EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
// ),
|
||||
// onPressed: 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_outline_rounded,
|
||||
// size: 15,
|
||||
// color: Colors.white,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 16),
|
||||
// Center(
|
||||
// child: SingleChildScrollView(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// child: SizedBox(
|
||||
// width: MediaQuery.of(context).size.width,
|
||||
// child: DataTable(
|
||||
// border: TableBorder(
|
||||
// bottom: BorderSide(color: Colors.black12),
|
||||
// horizontalInside: BorderSide(
|
||||
// color: Colors.black12), // Only horizontal lines
|
||||
// ),
|
||||
// columns: const [
|
||||
// // DataColumn(label: Text('#')),
|
||||
// DataColumn(label: Text('Type of Visa')),
|
||||
// DataColumn(label: Text('Country')),
|
||||
// DataColumn(label: Text('Start Date')),
|
||||
// DataColumn(label: Text('Actions')),
|
||||
// ],
|
||||
// rows: _buildDataRows(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
List<DataRow> _buildDataRows() {
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
List<Map<String, dynamic>> filteredList =
|
||||
visaList.where((item) => item["is_active"] == "1").toList();
|
||||
print("filteredList- $filteredList");
|
||||
@ -139,66 +202,362 @@ class VisaListWidget extends StatelessWidget {
|
||||
.toString();
|
||||
}
|
||||
|
||||
return filteredList.asMap().entries.map((entry) {
|
||||
int index = entry.key + 1; // To start index from 1
|
||||
Map<String, dynamic> item = entry.value;
|
||||
print(item);
|
||||
return DataRow(cells: [
|
||||
// DataCell(Text(item["indx"]?.toString() ?? "N/A")),
|
||||
// DataCell(Text(item["type_of_visa"]!)),
|
||||
DataCell(Text(getRequestForVisa(item["type_of_visa"]!.toString()))),
|
||||
DataCell(Text(getRequestForCountry(item["country_code"]!.toString()))),
|
||||
// DataCell(Text(item["country_code"]!)),
|
||||
DataCell(Text(item["start_date"]!)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Visa"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteMiscellaneous(item),
|
||||
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
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
String formatDate(String dateString) {
|
||||
try {
|
||||
DateTime date = DateTime.parse(dateString);
|
||||
return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25
|
||||
} catch (e) {
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Row(
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// onPressed: () {
|
||||
// // View action
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.edit, color: Colors.green),
|
||||
// onPressed: () {
|
||||
// onOpen(true, item, "Visa");
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () {
|
||||
// onDeleteMiscellaneous(item);
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = filteredList[index];
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
// color: Colors.orange.shade50,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black12,
|
||||
blurRadius: 3,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
],
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.white70, // Change color to match your theme
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
]);
|
||||
}).toList();
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Visa"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteMiscellaneous(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: Colors.blueGrey.shade50,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Visa Type",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Country",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Date",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
" Comments",
|
||||
style: TextStyle(
|
||||
fontSize: 11, fontFamily: "Archivo"),
|
||||
)),
|
||||
],
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
isDesktop
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
getRequestForVisa(
|
||||
item["type_of_visa"]!.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
getRequestForCountry(
|
||||
item["country_code"]!.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
formatDate(item["start_date"]!),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildComments(
|
||||
"Comments:", item["comments"] ?? "N/A"),
|
||||
),
|
||||
],
|
||||
)
|
||||
: 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"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComments(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 20,
|
||||
// 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: [
|
||||
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,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
)
|
||||
: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRow(String title, String value) {
|
||||
// Define character limits based on title
|
||||
Map<String, int> limits = {
|
||||
// "Special Request:": 30,
|
||||
"Comments:": 40,
|
||||
// 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: TextStyle(fontWeight: FontWeight.w600, 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// List<DataRow> _buildDataRows() {
|
||||
// List<Map<String, dynamic>> filteredList =
|
||||
// visaList.where((item) => item["is_active"] == "1").toList();
|
||||
// print("filteredList- $filteredList");
|
||||
//
|
||||
// List<dynamic> visatypeList = apiData?['visa_type_of_visa'] ?? [];
|
||||
// List<dynamic> countryList = apiCountryData ?? [];
|
||||
//
|
||||
// String getRequestForVisa(String? specialRequestKey) {
|
||||
// if (specialRequestKey == null) return "N/A";
|
||||
//
|
||||
// return visatypeList
|
||||
// .firstWhere(
|
||||
// (element) =>
|
||||
// element["dropdown_key"].toString() == specialRequestKey,
|
||||
// orElse: () => {"dropdown_value": "N/A"},
|
||||
// )["dropdown_value"]
|
||||
// .toString();
|
||||
// }
|
||||
//
|
||||
// String getRequestForCountry(String? countryCode) {
|
||||
// if (countryCode == null) return "N/A";
|
||||
//
|
||||
// return countryList
|
||||
// .firstWhere(
|
||||
// (element) => element["country_code"].toString() == countryCode,
|
||||
// orElse: () => {"country_name": "N/A"},
|
||||
// )["country_name"]
|
||||
// .toString();
|
||||
// }
|
||||
//
|
||||
// return filteredList.asMap().entries.map((entry) {
|
||||
// int index = entry.key + 1; // To start index from 1
|
||||
// Map<String, dynamic> item = entry.value;
|
||||
// print(item);
|
||||
// return DataRow(cells: [
|
||||
// // DataCell(Text(item["indx"]?.toString() ?? "N/A")),
|
||||
// // DataCell(Text(item["type_of_visa"]!)),
|
||||
// DataCell(Text(getRequestForVisa(item["type_of_visa"]!.toString()))),
|
||||
// DataCell(Text(getRequestForCountry(item["country_code"]!.toString()))),
|
||||
// // DataCell(Text(item["country_code"]!)),
|
||||
// DataCell(Text(item["start_date"]!)),
|
||||
// DataCell(Row(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () => onOpen(true, item, "Visa"),
|
||||
// child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
// width: 20, height: 15),
|
||||
// ),
|
||||
// SizedBox(width: 10),
|
||||
// GestureDetector(
|
||||
// onTap: () => onDeleteMiscellaneous(item),
|
||||
// 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
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
//
|
||||
// //
|
||||
// // Row(
|
||||
// // children: [
|
||||
// // IconButton(
|
||||
// // icon: Icon(Icons.remove_red_eye, color: Colors.blue),
|
||||
// // onPressed: () {
|
||||
// // // View action
|
||||
// // },
|
||||
// // ),
|
||||
// // IconButton(
|
||||
// // icon: Icon(Icons.edit, color: Colors.green),
|
||||
// // onPressed: () {
|
||||
// // onOpen(true, item, "Visa");
|
||||
// // },
|
||||
// // ),
|
||||
// // IconButton(
|
||||
// // icon: Icon(Icons.delete, color: Colors.red),
|
||||
// // onPressed: () {
|
||||
// // onDeleteMiscellaneous(item);
|
||||
// // },
|
||||
// // ),
|
||||
// // ],
|
||||
// // )
|
||||
//
|
||||
// ),
|
||||
// ]);
|
||||
// }).toList();
|
||||
// }
|
||||
}
|
||||
|
||||
@ -354,6 +354,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
// color: Colors.redAccent,
|
||||
color: bodyColor,
|
||||
child: buildOrgLayout(isDesktop),
|
||||
),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -431,6 +431,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
isViewMode: widget.isViewMode,
|
||||
apiData: widget.apiData,
|
||||
onDeleteTrain: (data) => handleItinerarydelete("Train", data),
|
||||
);
|
||||
break;
|
||||
@ -440,6 +441,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
isViewMode: widget.isViewMode,
|
||||
apiData: widget.apiData,
|
||||
onDeleteTaxi: (data) => handleItinerarydelete("Taxi", data),
|
||||
);
|
||||
break;
|
||||
@ -480,6 +482,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
isViewMode: widget.isViewMode,
|
||||
apiData: widget.apiData,
|
||||
onDeleteForex: (data) => handleItinerarydelete("Forex", data),
|
||||
);
|
||||
break;
|
||||
@ -510,6 +513,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
isViewMode: widget.isViewMode,
|
||||
apiData: widget.apiData,
|
||||
onDeleteFlight: (data) => handleItinerarydelete("Flight", data));
|
||||
break;
|
||||
}
|
||||
@ -612,7 +616,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
borderRadius: BorderRadius.circular(1),
|
||||
// color: Color(0xFFF4F4FB),
|
||||
),
|
||||
padding: EdgeInsets.all(10),
|
||||
// padding: EdgeInsets.all(10),
|
||||
child: isMobile
|
||||
? Expanded(
|
||||
child: SingleChildScrollView(
|
||||
@ -645,6 +649,24 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
List<Widget> _buildOptions() {
|
||||
if (ServicesChoosed == null) return [];
|
||||
|
||||
if (ServicesChoosed != null &&
|
||||
ServicesChoosed!.isNotEmpty &&
|
||||
selectedListOption == "") {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
selectedListOption = ServicesChoosed!.first['name'];
|
||||
isSelected = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// if (ServicesChoosed != null &&
|
||||
// ServicesChoosed!.isNotEmpty &&
|
||||
// selectedListOption == "") {
|
||||
// selectedListOption = ServicesChoosed!.first['name'];
|
||||
// isSelected = false;
|
||||
// }
|
||||
|
||||
return ServicesChoosed!.map((service) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
@ -657,6 +679,76 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
Widget _buildOption(
|
||||
Map<String, dynamic> service,
|
||||
bool hasData,
|
||||
) {
|
||||
String name = service['name'];
|
||||
String iconUrl = service['icon']; // Can be empty string
|
||||
IconData fallbackIcon = _getLocalIconForService(name);
|
||||
|
||||
bool isOptionSelected = selectedListOption == name;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedListOption = name;
|
||||
isSelected = false;
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: isOptionSelected ? Color(0xFF114D8B) : Colors.transparent,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
iconUrl.isNotEmpty
|
||||
? Image.network(
|
||||
iconUrl,
|
||||
width: 18,
|
||||
height: 18,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Icon(
|
||||
fallbackIcon,
|
||||
size: 18,
|
||||
color: isOptionSelected
|
||||
? Color(0xFF114D8B)
|
||||
: Color(0xFF475569),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Icon(
|
||||
fallbackIcon,
|
||||
size: 18,
|
||||
color: isOptionSelected
|
||||
? Color(0xFF114D8B)
|
||||
: Color(0xFF475569),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: isOptionSelected ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||
fontFamily: "Archivo",
|
||||
fontWeight:
|
||||
isOptionSelected ? FontWeight.bold : FontWeight.w500,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
if (hasData) Icon(Icons.circle, size: 8, color: Colors.green),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOption1(
|
||||
Map<String, dynamic> service,
|
||||
bool hasData,
|
||||
) {
|
||||
String name = service['name'];
|
||||
String iconUrl = service['icon']; // Can be empty string
|
||||
@ -701,9 +793,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
: Color(0xFF475569),
|
||||
),
|
||||
|
||||
SizedBox(width: 5),
|
||||
|
||||
SizedBox(width: 5),
|
||||
SizedBox(width: 2),
|
||||
Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
@ -719,20 +809,19 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
// fontWeight: selectedListOption == title ? FontWeight.bold : FontWeight.normal,)),
|
||||
),
|
||||
|
||||
SizedBox(width: 5),
|
||||
SizedBox(width: 2),
|
||||
// if (selectedListOption == title && widget.isViewMode == false)
|
||||
if (hasData)
|
||||
Container(
|
||||
height: 13,
|
||||
width: 13,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.green, width: 1.5),
|
||||
),
|
||||
child:
|
||||
Icon(Icons.notifications_rounded, size: 8, color: Colors.green
|
||||
// color: Colors.grey,
|
||||
)),
|
||||
height: 10,
|
||||
width: 10,
|
||||
// decoration: BoxDecoration(
|
||||
// shape: BoxShape.circle,
|
||||
// border: Border.all(color: Colors.green, width: 1.5),
|
||||
// ),
|
||||
child: Icon(Icons.circle, size: 8, color: Colors.green
|
||||
// color: Colors.grey,
|
||||
)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@ -744,7 +833,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
case 'train':
|
||||
return Icons.train_outlined;
|
||||
case 'bus':
|
||||
return Icons.bus_alert_outlined;
|
||||
return Icons.directions_bus_filled_outlined;
|
||||
case 'taxi':
|
||||
return Icons.local_taxi_outlined;
|
||||
case 'accomodation':
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/config/apiUrl.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@ -198,13 +199,23 @@ class _ListPlansState extends State<ListPlans> {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: buildTableLayout(isDesktop),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTableLayout(isDesktop) {
|
||||
String _formatDate(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd MMM yy : hh a').format(dateTime);
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop
|
||||
? EdgeInsets.all(10.0)
|
||||
@ -499,7 +510,8 @@ class _ListPlansState extends State<ListPlans> {
|
||||
fontSize: 13,
|
||||
fontFamily: "Archivo",
|
||||
))),
|
||||
DataCell(Text(plan.createdOn,
|
||||
DataCell(Text(_formatDate(plan.createdOn),
|
||||
// plan.createdOn,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Archivo",
|
||||
|
||||
@ -106,20 +106,21 @@ class _PolicyState extends State<Policy> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
// WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
loadinitializeData();
|
||||
loadInitialData();
|
||||
|
||||
if (widget.policy != null) {
|
||||
final details =
|
||||
List<Map<String, dynamic>>.from(widget.policy!['policy_details']);
|
||||
policyCriteriaKey.currentState?.loadPolicyDetails(details);
|
||||
}
|
||||
updateSelectedServices();
|
||||
updateData();
|
||||
|
||||
loadInitialData();
|
||||
});
|
||||
updateSelectedServices();
|
||||
updateData();
|
||||
}
|
||||
|
||||
void loadInitialData() async {
|
||||
@ -440,14 +441,15 @@ class _PolicyState extends State<Policy> {
|
||||
return Container(
|
||||
// margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
// color: bodyColor,
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
child: buildPolicyLayout(isDesktop),
|
||||
),
|
||||
),
|
||||
|
||||
@ -156,7 +156,8 @@ class _PolicyListState extends State<PolicyList> {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
// color: bodyColor,
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: buildGroupListLayout(isDesktop),
|
||||
);
|
||||
|
||||
@ -689,7 +689,8 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
||||
// margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: Column(
|
||||
children: [
|
||||
|
||||
@ -265,7 +265,8 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
color: bodyColor,
|
||||
// color: bodyColor,
|
||||
color: Color(0xFFE1F5FE),
|
||||
border: Border.all(color: Color(0xFFF7F7FB), width: 3.5)),
|
||||
child: buildUserTable(isDesktop),
|
||||
);
|
||||
|
||||
@ -582,7 +582,7 @@ packages:
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
|
||||
@ -45,6 +45,7 @@ dependencies:
|
||||
bcrypt: ^1.1.3
|
||||
http_parser: ^4.1.2
|
||||
image_picker: ^1.1.2
|
||||
web: ^1.1.0
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user