master
Sneha 13 hours ago
parent c47bddf151
commit fb8777b7f8

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -876,7 +876,7 @@ class _HomeScreenState extends State<HomeScreen> {
for(var order in data){
String status =
(order['status'] ?? "")
(order['my_supplier_entry']['status'] ?? "")
.toString()
.toLowerCase();
@ -1116,25 +1116,39 @@ class _HomeScreenState extends State<HomeScreen> {
/// percentage calculation
double percent = 0;
if(yesterday != 0){
if(yesterday > 0){
percent =
((today - yesterday) / yesterday) * 100;
}
else if(today > 0){
percent = 100;
}
String text;
Color color;
if(percent > 0){
if(today > yesterday){
text =
"${percent.abs().toStringAsFixed(0)}% from yesterday";
if(yesterday == 0){
text = "↑ New revenue";
}
else{
text =
"${percent.abs().toStringAsFixed(0)}% from yesterday";
}
color = Colors.green;
}
else if(percent < 0){
else if(today < yesterday){
text =
"${percent.abs().toStringAsFixed(0)}% from yesterday";

@ -211,6 +211,13 @@ class AppSettings{
static int resourcesInitialTab = 0;
static List<String> existingCreditCustomerIds = [];
static String moneyConvertion(String value) {
var comma = NumberFormat('#,##,###.00', 'en_IN');
return comma.format(
double.parse(value),
);
}
static String formDouble(dynamic s) {
var comma = NumberFormat('#,##,###.##', 'en_IN');

@ -1,7 +1,13 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/orders/edit_order_requests.dart';
import '../resources/tankers_model.dart';
import 'best_options.dart';
class AcceptOrderRequests extends StatefulWidget {
var order;
var status;
@ -12,22 +18,188 @@ class AcceptOrderRequests extends StatefulWidget {
class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
int advancePayable = 0;
int advance =0;
double amountToPayAfterDelivery = 0.0;
double totalFare = 0.0;
final TextEditingController tankerPriceController = TextEditingController();
double platformFee = 0.0;
double totalTaxes = 0.0;
double subtotal = 0.0;
double cgst = 0.0;
double sgst = 0.0;
double total = 0.0;
@override
void initState() {
// TODO: implement initState
super.initState();
advance = 150;
advancePayable = advance;
totalFare = advance + double.parse(widget.order.quoted_amount);
amountToPayAfterDelivery = totalFare - advancePayable;
tankerPriceController.addListener(() => setState(() {}));
fetchTankers();
platformFee = 11;
tankerPriceController.text = '${widget.order.quoted_amount}';
}
List<TankersModel> tankersList = [];
bool isLoadingTankers = false;
Future<void> fetchTankers() async {
setState(() {
isLoadingTankers = true;
});
try {
final response =
await AppSettings.getTankers();
final data =
(jsonDecode(response)['data'] as List)
.map((e)=>
TankersModel.fromJson(e))
.toList();
tankersList = data;
setState(() {
isLoadingTankers = false;
});
}
catch(e){
print(e);
setState(() {
isLoadingTankers = false;
});
}
}
double getDeliveryFee(){
if(tankersList.isEmpty)
return 0;
String orderCapacity =
widget.order.capacity
.replaceAll(",", "")
.replaceAll("Litres","")
.replaceAll("L","")
.replaceAll(" ","")
.trim();
var matched =
tankersList.firstWhere(
(t){
String tankerCap =
t.capacity
.replaceAll(",", "")
.replaceAll("Litres","")
.replaceAll("L","")
.replaceAll(" ","")
.trim();
return tankerCap
== orderCapacity;
},
orElse: ()=>TankersModel(),
);
return double.tryParse(
matched.delivery_fee.toString()
) ?? 0;
}
double calculateTransport(){
double distance =
double.tryParse(
widget.order.distanceInKm
.toString()
) ?? 0;
double deliveryFee =
getDeliveryFee();
double qty =
double.tryParse(
widget.order.quantity
.toString()
) ?? 1;
return (distance *
deliveryFee *
qty);
}
@override
Widget build(BuildContext context) {
int tankerPrice = int.tryParse(tankerPriceController.text) ?? 0;
int updatedQuantity=int.tryParse(widget.order.quantity) ?? 0;
String updatedCapacity=widget.order.capacity;
int bookingCharges =
calculateTransport().round();
//int totalPrice = (tankerPrice * updatedQuantity) + bookingCharges;
int advancePayable = bookingCharges; //
//int amountToPayAfterDelivery=totalPrice-bookingCharges;
double distance =
double.tryParse(
widget.order.distanceInKm.toString()
) ?? 0;
double perKm =
getDeliveryFee();
double transport =
calculateTransport();
double actualPrice =
double.tryParse(
tankerPriceController.text
) ?? 0;
double quantity =
double.tryParse(
widget.order.quantity.toString()
) ?? 1;
double subtotal =
actualPrice * quantity;
double cgst =
subtotal * 0.09;
double sgst =
subtotal * 0.09;
double totalTaxes =
cgst + sgst;
double totalPrice =
subtotal +
transport +
totalTaxes +
platformFee;
double amountToPayAfterDelivery =
totalPrice - transport;
return Scaffold(
backgroundColor: Colors.white,
extendBodyBehindAppBar: true,
@ -182,16 +354,72 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
SizedBox(
height: MediaQuery.of(context).size.height * .011,
),
_detailTwoRow(
_twoFields(tankerPriceController, "Tanker Price",
'images/price.png', false, null, null, null, null),
/*_detailTwoRow(
"Tanker Price",
"${AppSettings.formDouble(widget.order.quoted_amount) ?? ''}",
"images/financialsBottomIcon.png",
"",
"",
""),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
""),*/
_detailTwoRow(
"Transport Charges",
"" +
AppSettings.formDouble(
transport.toString()),
"images/advance.png",
"",
"",
"",
),
Padding(
padding: EdgeInsets.only(left:4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'images/warning.png',
fit: BoxFit.cover,
width:
22, // Match the diameter of the CircleAvatar
height: 22,
),
SizedBox(width: MediaQuery.of(context).size.width * .020),
Expanded(
child: Text(
"Transport charges are calculated based on distance ${distance.toStringAsFixed(2)} km and rate ₹${perKm.toStringAsFixed(0)} per km. Total transport charges are ₹${transport.toStringAsFixed(0)}.",
softWrap:true,
style: fontTextStyle(
11,
Color(0XFF646566),
FontWeight.w400),
),
),
],
)
),
_detailTwoRow(
"Water Type",
"${widget.order.type_of_water}",
@ -218,9 +446,9 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
"Quantity",
"${widget.order.quantity}",
"images/quantity.png",
"Booking Charges",
advance.toString(),
"images/advance.png",
"",
"",
"",
),
],
),
@ -230,7 +458,7 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
),
/// 🔹 Additional Details
Padding(
/* Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -252,10 +480,10 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
12, const Color(0XFF646566), FontWeight.w400),
),
],
)),
)),*/
/// 🔹 Payment Summary
Padding(
/*Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -297,7 +525,35 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
'${AppSettings.formDouble(amountToPayAfterDelivery.toString()) ?? ''}'),
],
),
),
),*/
const SizedBox(height: 20),
Padding( padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("UPDATED PAYMENT SUMMARY",
style: fontTextStyle(12,Color(0XFF2D2E30),FontWeight.w600),),
const SizedBox(height: 12),
_summaryRow("Quantity", " $updatedQuantity"),
_summaryRow("Capacity", "$updatedCapacity"),
_summaryRow("Tanker Price", "$tankerPrice"),
_summaryRow("Transport Charges", "$bookingCharges"),
_summaryRow('Platform Fee', '${AppSettings.moneyConvertion(platformFee.toString())}'),
_summaryRow('Taxes', '${AppSettings.moneyConvertion(totalTaxes.toString())}'),
_summaryRow(
"Total Price",
"${AppSettings.formDouble(totalPrice.toString())}"
),
const Divider(),
_summaryRow(
"Transport Charges",
"${AppSettings.formDouble(transport.toString())}"
),
_summaryRow("Amount to Pay (After Delivery)", "$amountToPayAfterDelivery"),
],
)),
const SizedBox(height: 80), // space for bottom buttons
],
@ -313,7 +569,7 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
),
child: Row(
children: [
Expanded(
/* Expanded(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: Color(0XFF000000),
@ -348,7 +604,7 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
),
),
),
SizedBox(width: 8),
SizedBox(width: 8),*/
Expanded(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
@ -365,8 +621,8 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
if (isOnline) {
var payload = new Map<String, dynamic>();
payload["supplierId"] = AppSettings.supplierId;
payload["amount"] = int.parse(widget.order.quoted_amount);
payload["delivery_charges"] = advance;
payload["amount"] = int.parse(tankerPriceController.text);
payload["delivery_charges"] = calculateTransport().round();
payload["action"] = 'reject';
bool status = await AppSettings.acceptOrderRequests(
@ -422,8 +678,8 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
if (isOnline) {
var payload = new Map<String, dynamic>();
payload["supplierId"] = AppSettings.supplierId;
payload["amount"] = int.parse(widget.order.quoted_amount);
payload["delivery_charges"] = advance;
payload["amount"] = int.parse(tankerPriceController.text);
payload["delivery_charges"] = calculateTransport().round();
payload["action"] = 'accept';
bool status = await AppSettings.acceptOrderRequests(
@ -448,6 +704,21 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
AppSettings.longFailedToast("Please Check internet");
}
},
/*onPressed:(){
Navigator.push(
context,
MaterialPageRoute(
builder:(_)=>TankerOptionsDemo()
)
);
},*/
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -487,6 +758,121 @@ class _AcceptOrderRequestsState extends State<AcceptOrderRequests> {
);
}
Widget _twoFields(
TextEditingController? controller1,
String? label1,
String? path1,
bool? readOnly1,
TextEditingController? controller2,
String? label2,
String? path2,
bool? readOnly2) {
return Row(
children: [
Expanded(
child: _textField(controller1, label1, path1, readOnly1!),
),
const SizedBox(width: 10),
if (controller2 != null)
Expanded(
child: _textField(controller2, label2, path2, readOnly2!),
),
],
);
}
Widget _textField(TextEditingController? controller, String? label,
String? path, bool readOnly) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
child: TextField(
controller: controller,
cursorColor: primaryColor,
readOnly: readOnly,
decoration: InputDecoration(
counterText: '',
filled: false,
fillColor: Colors.white,
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
child: SizedBox(
width: 18,
height: 18,
child: Image.asset(
path!,
fit: BoxFit.contain,
color: Color(0XFFC3C4C4),
),
),
),
prefixIconConstraints: BoxConstraints(
minWidth: 24,
minHeight: 24,
),
suffixIcon: readOnly
? null
: Padding(
padding: const EdgeInsets.only(right: 8),
child: Image.asset(
'images/edit.png',
height: 18,
width: 18,
color: const Color(0XFFC3C4C4),
),
),
suffixIconConstraints: BoxConstraints(
minWidth: 24,
minHeight: 24,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: BorderSide(
color: Color(0XFFC3C4C4),
width: 1,
)),
focusedBorder: !readOnly
? OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: BorderSide(
color: Color(0XFF8270DB),
width: 1,
),
)
: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: BorderSide(
color: Color(0XFFC3C4C4),
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: BorderSide(color: Color(0XFFC3C4C4)),
),
labelText: label,
labelStyle: fontTextStyle(12, Color(0XFF646566), FontWeight.w400),
/* TextStyle(color: greyColor, fontWeight: FontWeight.bold //<-- SEE HERE
),*/
),
style: fontTextStyle(12, Color(0XFF343637), FontWeight.w500),
),
);
}
Widget _summaryRow(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: fontTextStyle(12,Color(0XFF646566),FontWeight.w400),),
Text(value,
style: fontTextStyle(12,Color(0XFF2D2E30),FontWeight.w500),),
],
),
);
}
Widget _detailTwoRow(
String title1,
String value1,

File diff suppressed because it is too large Load Diff

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_loctaions_model.dart';
import '../resources/drivers_model.dart';
@ -92,6 +93,165 @@ class _AssignDriverScreenState extends State<AssignDriverScreen> {
}
}
DateTime parseOrderDateTime(){
DateTime d =
DateFormat("dd-MMM-yyyy")
.parse(widget.order.date);
DateTime t =
DateFormat("hh:mm a")
.parse(widget.order.time);
return DateTime(
d.year,
d.month,
d.day,
t.hour,
t.minute
);
}
bool isTankerBlocked(TankersModel tanker){
if(tanker.blocked_dates == null ||
tanker.blocked_dates.isEmpty){
return false;
}
DateTime orderDT =
parseOrderDateTime();
for(var slot in tanker.blocked_dates){
if(slot['date'] != widget.order.date){
continue;
}
String timeRange =
slot['time'];
List parts =
timeRange.split("to");
if(parts.length != 2){
continue;
}
DateTime start =
DateFormat("hh:mm a")
.parse(parts[0].trim());
DateTime end =
DateFormat("hh:mm a")
.parse(parts[1].trim());
DateTime startDT =
DateTime(
orderDT.year,
orderDT.month,
orderDT.day,
start.hour,
start.minute
);
DateTime endDT =
DateTime(
orderDT.year,
orderDT.month,
orderDT.day,
end.hour,
end.minute
);
/// inside range
if(
orderDT.isAfter(startDT) &&
orderDT.isBefore(endDT)
){
return true;
}
/// exact start
if(orderDT == startDT){
return true;
}
/// exact end
if(orderDT == endDT){
return true;
}
}
return false;
}
String? getDriverBlockedTime(DriversModel driver){
if(driver.blocked_dates == null ||
driver.blocked_dates.isEmpty){
return null;
}
DateTime orderDT = parseOrderDateTime();
for(var slot in driver.blocked_dates){
if(slot['date'] != widget.order.date){
continue;
}
String timeRange = slot['time'];
List parts = timeRange.split("to");
if(parts.length != 2){
continue;
}
DateTime start =
DateFormat("hh:mm a")
.parse(parts[0].trim());
DateTime end =
DateFormat("hh:mm a")
.parse(parts[1].trim());
DateTime startDT = DateTime(
orderDT.year,
orderDT.month,
orderDT.day,
start.hour,
start.minute
);
DateTime endDT = DateTime(
orderDT.year,
orderDT.month,
orderDT.day,
end.hour,
end.minute
);
if(orderDT.isAfter(startDT) &&
orderDT.isBefore(endDT)){
return timeRange;
}
if(orderDT == startDT ||
orderDT == endDT){
return timeRange;
}
}
return null;
}
void _showAssignTankerBottomSheet() {
int? selectedTankerIndex;
int? selectedDriverIndex;
@ -238,55 +398,100 @@ class _AssignDriverScreenState extends State<AssignDriverScreen> {
physics:
const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: tankersList
.where((t) =>
_capToLiters(t.capacity) ==
_capToLiters(
widget.order.capacity))
.length,
itemCount: tankersList
.where((t) =>
_capToLiters(t.capacity) ==
_capToLiters(widget.order.capacity) &&
t.type_of_water.toLowerCase().trim() ==
widget.order.type_of_water.toLowerCase().trim())
.length,
separatorBuilder: (_, __) =>
const SizedBox(height: 12),
itemBuilder: (context, idx) {
final filteredTankers = tankersList
.where((t) =>
_capToLiters(t.capacity) ==
_capToLiters(
widget.order.capacity))
.toList();
final filteredTankers = tankersList.where((t) =>
_capToLiters(t.capacity) ==
_capToLiters(widget.order.capacity) &&
t.type_of_water.toLowerCase().trim() ==
widget.order.type_of_water.toLowerCase().trim()
).toList();
final d = filteredTankers[idx];
bool blocked =
isTankerBlocked(d);
final isSelected =
selectedTankerIndex == idx;
return GestureDetector(
onTap: () {
onTap: blocked ? null : () {
setModalState(() {
selectedTankerIndex = idx;
selectedDriverIndex =
null; // reset driver selection if tanker changes
selectedDriverIndex=null;
});
},
child: Opacity(
opacity: blocked ? 0.4 : 1,
child: Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(12),
BorderRadius.circular(12),
side: BorderSide(
color: isSelected
color: blocked
? Colors.grey
: (isSelected
? primaryColor
: const Color(0XFFC3C4C4),
: const Color(0XFFC3C4C4)),
width: 1,
),
),
child: TankersCard(
title: d.tanker_name,
subtitle: d.type_of_water,
capacity: d.capacity,
code: d.license_plate,
owner: d.supplier_name,
status: List<String>.from(
d.availability),
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
TankersCard(
title: d.tanker_name,
subtitle: d.type_of_water,
capacity: d.capacity,
code: d.license_plate,
owner: d.supplier_name,
status: List<String>.from(
d.availability),
),
if(blocked)
Padding(
padding: EdgeInsets.only(
left:10,
top:4
),
child: Text(
"Booked at ${widget.order.time}",
style: fontTextStyle(
10,
Colors.red,
FontWeight.w500
),
),
),
]),
),
)
);
},
)),
@ -298,163 +503,294 @@ class _AssignDriverScreenState extends State<AssignDriverScreen> {
style: fontTextStyle(
10, const Color(0XFF2D2E30), FontWeight.w600),
),
const SizedBox(height: 4),
// 🚨 Driver list disabled until tanker is selected
selectedTankerIndex == null
? Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(top: 8),
decoration: BoxDecoration(
color: const Color(0XFFFFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFFC3C4C4)),
),
child: Center(
child: Text(
'Select a tanker to choose driver',
style: fontTextStyle(
14,
const Color(0xFF2D2E30),
FontWeight.w400),
),
),
)
width: double.infinity,
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(top: 8),
decoration: BoxDecoration(
color: const Color(0XFFFFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFFC3C4C4)),
),
child: Center(
child: Text(
'Select a tanker to choose driver',
style: fontTextStyle(
14,
const Color(0xFF2D2E30),
FontWeight.w400),
),
),
)
: isLoading
? const Center(
child: CircularProgressIndicator())
: (driversList.isEmpty
? Center(
child: Padding(
? const Center(
child: CircularProgressIndicator())
: (driversList.isEmpty
? Center(
child: Padding(
padding:
const EdgeInsets.symmetric(
vertical: 12),
child: Text(
'No Data Available',
style: fontTextStyle(
12,
const Color(0xFF939495),
FontWeight.w500),
),
),
)
: ListView.separated(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: driversList.length,
separatorBuilder: (_, __) =>
const SizedBox(height: 12),
itemBuilder: (context, idx) {
final d = driversList[idx];
final isSelected =
selectedDriverIndex == idx;
String? blockedTime =
getDriverBlockedTime(d);
bool blocked =
blockedTime != null;
String driverStatus =
d.status.toLowerCase().trim();
final isAvailable =
driverStatus == "available" &&
!blocked;
final statusColor = blocked
? Colors.red
: (isAvailable
? const Color(0XFF0A9E04)
: (driverStatus == "on delivery"
? const Color(0XFFD0AE3C)
: (driverStatus == "offline"
? const Color(0XFF939495)
: Colors.grey)));
return GestureDetector(
onTap: isAvailable ? () {
setModalState(() {
selectedDriverIndex = idx;
});
} : null,
child: Opacity(
opacity:
isAvailable ? 1 : 0.4,
child: Card(
color:
const Color(0XFFFFFFFF),
elevation: 1,
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
12),
side: BorderSide(
color: isSelected
? primaryColor
: const Color(
0XFFC3C4C4),
width: 1,
),
),
child: Padding(
padding:
const EdgeInsets.all(
12.0),
child: Row(
children: [
Image.asset(
'images/avatar.png',
fit: BoxFit.cover,
width: 20,
height: 20,
),
const SizedBox(
width: 8),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
d.driver_name,
style:
fontTextStyle(
14,
const Color(
0XFF2D2E30),
FontWeight
.w500),
),
if(blockedTime != null)
Text(
"Booked $blockedTime",
style: fontTextStyle(
10,
Colors.red,
FontWeight.w500),
),
],
),
),
const SizedBox(
width: 8),
Container(
padding:
const EdgeInsets.symmetric(
vertical: 12),
const EdgeInsets
.symmetric(
horizontal: 6,
vertical: 2),
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
4),
border: Border.all(
color:
statusColor),
),
child: Text(
'No Data Available',
style: fontTextStyle(
12,
const Color(0xFF939495),
FontWeight.w500),
blocked
? "booked"
: d.status,
style:
fontTextStyle(
10,
statusColor,
FontWeight
.w400),
),
),
)
: ListView.separated(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: driversList.length,
separatorBuilder: (_, __) =>
const SizedBox(height: 12),
itemBuilder: (context, idx) {
final d = driversList[idx];
final isSelected =
selectedDriverIndex == idx;
final isAvailable =
d.status == "available";
final statusColor = isAvailable
? const Color(0XFF0A9E04)
: (d.status == "on delivery"
? const Color(0XFFD0AE3C)
: (d.status == "offline"
? const Color(
0XFF939495)
: Colors.grey));
return GestureDetector(
onTap: () {
/* if (isAvailable) {
setModalState(() {
selectedDriverIndex = idx;
});
} else {
AppSettings.longFailedToast(
'Only available drivers can be selected',
);
}*/
setModalState(() {
selectedDriverIndex = idx;
});
},
child: Card(
color:
const Color(0XFFFFFFFF),
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
12),
side: BorderSide(
color: isSelected
? primaryColor
: const Color(
0XFFC3C4C4),
width: 1,
),
),
child: Padding(
padding:
const EdgeInsets.all(
12.0),
child: Row(
children: [
Image.asset(
'images/avatar.png',
fit: BoxFit.cover,
width: 20,
height: 20,
),
const SizedBox(
width: 8),
Expanded(
child: Text(
d.driver_name,
style: fontTextStyle(
14,
const Color(
0XFF2D2E30),
FontWeight
.w500),
),
),
const SizedBox(
width: 8),
Container(
padding:
const EdgeInsets
.symmetric(
horizontal: 6,
vertical: 2),
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
4),
border: Border.all(
color:
statusColor),
),
child: Text(
d.status,
style:
fontTextStyle(
10,
statusColor,
FontWeight
.w400),
),
),
],
),
),
),
);
},
)),
],
),
),
),
),
);
},
)),
const SizedBox(height: 8),

@ -0,0 +1,639 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:http/http.dart' as http;
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_loctaions_model.dart';
import '../resources/drivers_model.dart';
import '../resources/tankers_model.dart';
class AssignDriverScreenNewDesign extends StatefulWidget {
final dynamic order;
final dynamic status;
const AssignDriverScreenNewDesign({
super.key,
this.order,
this.status,
});
@override
State<AssignDriverScreenNewDesign> createState() =>
_AssignDriverScreenNewDesignState();
}
class _AssignDriverScreenNewDesignState
extends State<AssignDriverScreenNewDesign> {
GoogleMapController? _mapController;
List<DriversModel> driversList = [];
List<TankersModel> tankersList = [];
List<SourceLocationsModel> sourceLocationsList = [];
DriversModel? selectedDriver;
TankersModel? selectedTanker;
SourceLocationsModel? selectedSource;
bool loading = true;
bool routeLoading = false;
Set<Marker> _markers = {};
Set<Polyline> _polylines = {};
String eta = '';
String distanceText = '';
String routeError = '';
static const String googleApiKey = 'AIzaSyDJpK9RVhlBejtJu9xSGfneuTN6HOfJgSM';
@override
void initState() {
super.initState();
loadData();
}
Future<void> loadData() async {
try {
final d = await AppSettings.getDrivers();
driversList = (jsonDecode(d)['data'] as List)
.map((e) => DriversModel.fromJson(e))
.toList();
final t = await AppSettings.getTankers();
tankersList = (jsonDecode(t)['data'] as List)
.map((e) => TankersModel.fromJson(e))
.toList();
final s = await AppSettings.getSourceLoctaions();
sourceLocationsList = (jsonDecode(s)['data'] as List)
.map((e) => SourceLocationsModel.fromJson(e))
.toList();
} catch (e) {
debugPrint('Load error: $e');
}
if (!mounted) return;
setState(() {
loading = false;
_rebuildMarkers();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_fitMap();
});
}
double? _toDouble(dynamic value) {
if (value == null) return null;
if (value is double) return value;
if (value is int) return value.toDouble();
return double.tryParse(value.toString().trim());
}
LatLng? _deliveryPosition() {
try {
final lat = _toDouble(
widget.order?.lat ??
widget.order?.delivery_lat ??
widget.order?.location_lat,
);
final lng = _toDouble(
widget.order?.lng ??
widget.order?.delivery_lng ??
widget.order?.location_lng,
);
if (lat == null || lng == null) return null;
return LatLng(lat, lng);
} catch (e) {
debugPrint('Delivery parse error: $e');
return null;
}
}
LatLng? _sourcePosition(SourceLocationsModel source) {
try {
final lat = _toDouble(source.latitude);
final lng = _toDouble(source.longitude);
if (lat == null || lng == null) return null;
return LatLng(lat, lng);
} catch (e) {
debugPrint('Source parse error: $e');
return null;
}
}
void _rebuildMarkers() {
final Set<Marker> markers = {};
final delivery = _deliveryPosition();
if (delivery != null) {
markers.add(
Marker(
markerId: const MarkerId('delivery'),
position: delivery,
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueRed,
),
infoWindow: InfoWindow(
title: widget.order?.building_name?.toString() ?? 'Delivery',
snippet: 'Customer location',
),
),
);
}
for (final source in sourceLocationsList) {
final pos = _sourcePosition(source);
if (pos == null) continue;
final bool isSelected = selectedSource?.dbId == source.dbId;
markers.add(
Marker(
markerId: MarkerId('source_${source.dbId}'),
position: pos,
icon: BitmapDescriptor.defaultMarkerWithHue(
isSelected
? BitmapDescriptor.hueViolet
: BitmapDescriptor.hueAzure,
),
infoWindow: InfoWindow(
title: source.source_name?.toString() ?? 'Source',
snippet: isSelected ? 'Selected source' : 'Tap to select source',
),
onTap: () async {
setState(() {
selectedSource = source;
routeError = '';
eta = '';
distanceText = '';
_rebuildMarkers();
});
await _loadRouteAndEta();
WidgetsBinding.instance.addPostFrameCallback((_) {
_fitMap();
});
},
),
);
}
_markers = markers;
}
Future<void> _loadRouteAndEta() async {
final source = selectedSource;
final sourcePos = source == null ? null : _sourcePosition(source);
final deliveryPos = _deliveryPosition();
if (sourcePos == null || deliveryPos == null) {
setState(() {
routeError = 'Source or delivery coordinates missing';
_polylines = {};
});
return;
}
setState(() {
routeLoading = true;
routeError = '';
});
try {
await Future.wait([
_loadDirectionsPolyline(sourcePos, deliveryPos),
_loadEtaWithDirections(sourcePos, deliveryPos),
]);
} catch (e) {
debugPrint('Route load error: $e');
if (mounted) {
setState(() {
routeError = 'Unable to load route';
});
}
}
if (!mounted) return;
setState(() {
routeLoading = false;
});
}
Future<void> _loadEtaWithDirections(
LatLng origin,
LatLng destination,
) async {
try {
final uri = Uri.parse(
'https://maps.googleapis.com/maps/api/directions/json'
'?origin=${origin.latitude},${origin.longitude}'
'&destination=${destination.latitude},${destination.longitude}'
'&mode=driving'
'&departure_time=now'
'&traffic_model=best_guess'
'&key=$googleApiKey',
);
final response = await http.get(uri);
final data = jsonDecode(response.body);
debugPrint('Directions ETA response: $data');
if (data['status'] != 'OK') {
setState(() {
routeError = 'ETA unavailable: ${data['status']}';
});
return;
}
final routes = data['routes'] as List?;
if (routes == null || routes.isEmpty) {
setState(() {
routeError = 'ETA unavailable';
});
return;
}
final legs = routes.first['legs'] as List?;
if (legs == null || legs.isEmpty) {
setState(() {
routeError = 'ETA unavailable';
});
return;
}
final leg = legs.first;
final distance = leg['distance'];
final duration = leg['duration'];
final durationInTraffic = leg['duration_in_traffic'];
setState(() {
distanceText = (distance?['text'] ?? '').toString();
eta = (durationInTraffic?['text'] ?? duration?['text'] ?? '').toString();
});
} catch (e) {
debugPrint('ETA error: $e');
setState(() {
routeError = 'ETA request failed';
});
}
}
Future<void> _loadDirectionsPolyline(
LatLng origin,
LatLng destination,
) async {
try {
final uri = Uri.parse(
'https://maps.googleapis.com/maps/api/directions/json'
'?origin=${origin.latitude},${origin.longitude}'
'&destination=${destination.latitude},${destination.longitude}'
'&mode=driving'
'&departure_time=now'
'&traffic_model=best_guess'
'&key=$googleApiKey',
);
final response = await http.get(uri);
final data = jsonDecode(response.body);
debugPrint('Directions route response: $data');
if (data['status'] != 'OK') {
setState(() {
routeError = 'Route unavailable: ${data['status']}';
_polylines = {};
});
return;
}
final routes = data['routes'] as List?;
if (routes == null || routes.isEmpty) {
setState(() {
routeError = 'No route found';
_polylines = {};
});
return;
}
final encoded = routes.first['overview_polyline']?['points']?.toString();
if (encoded == null || encoded.isEmpty) {
setState(() {
routeError = 'Route polyline missing';
_polylines = {};
});
return;
}
final polylinePoints = PolylinePoints();
final decoded = polylinePoints.decodePolyline(encoded);
final points = decoded
.map((p) => LatLng(p.latitude, p.longitude))
.toList();
if (points.isEmpty) {
setState(() {
routeError = 'Failed to decode route';
_polylines = {};
});
return;
}
setState(() {
_polylines = {
Polyline(
polylineId: const PolylineId('source_delivery_route'),
points: points,
color: Colors.blue,
width: 6,
),
};
});
} catch (e) {
debugPrint('Polyline error: $e');
setState(() {
routeError = 'Route request failed';
_polylines = {};
});
}
}
Future<void> _fitMap() async {
if (_mapController == null) return;
final List<LatLng> points = [];
final delivery = _deliveryPosition();
if (delivery != null) points.add(delivery);
for (final source in sourceLocationsList) {
final pos = _sourcePosition(source);
if (pos != null) points.add(pos);
}
if (points.isEmpty) return;
if (points.length == 1) {
await _mapController!.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: points.first, zoom: 14),
),
);
return;
}
double minLat = points.first.latitude;
double maxLat = points.first.latitude;
double minLng = points.first.longitude;
double maxLng = points.first.longitude;
for (final point in points) {
if (point.latitude < minLat) minLat = point.latitude;
if (point.latitude > maxLat) maxLat = point.latitude;
if (point.longitude < minLng) minLng = point.longitude;
if (point.longitude > maxLng) maxLng = point.longitude;
}
try {
await _mapController!.animateCamera(
CameraUpdate.newLatLngBounds(
LatLngBounds(
southwest: LatLng(minLat, minLng),
northeast: LatLng(maxLat, maxLng),
),
80,
),
);
} catch (_) {
await Future.delayed(const Duration(milliseconds: 300));
try {
await _mapController!.animateCamera(
CameraUpdate.newLatLngBounds(
LatLngBounds(
southwest: LatLng(minLat, minLng),
northeast: LatLng(maxLat, maxLng),
),
80,
),
);
} catch (_) {}
}
}
Future<void> assign() async {
if (selectedDriver == null) {
_msg('Select driver');
return;
}
if (selectedTanker == null) {
_msg('Select tanker');
return;
}
if (selectedSource == null) {
_msg('Select source from map');
return;
}
final payload = <String, dynamic>{};
payload["tankerName"] = selectedTanker!.tanker_name;
payload["delivery_agent"] = selectedDriver!.driver_name;
payload["delivery_agent_mobile"] = selectedDriver!.phone_number;
payload["water_source_location"] = selectedSource!.source_name;
AppSettings.preLoaderDialog(context);
bool status = false;
try {
status = await AppSettings.assignTanker(payload, widget.order.dbId);
} catch (e) {
debugPrint('Assign error: $e');
}
if (mounted) {
Navigator.pop(context);
}
if (!mounted) return;
if (status) {
_msg('Assigned successfully');
Navigator.pop(context, true);
} else {
_msg('Assignment failed');
}
}
void _msg(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
Widget _buildInfoRow(IconData icon, String text) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: [
Icon(icon, size: 18),
const SizedBox(width: 8),
Expanded(child: Text(text)),
],
),
);
}
Widget _buildBottomCard() {
return Container(
margin: const EdgeInsets.all(15),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
boxShadow: const [
BoxShadow(
blurRadius: 10,
color: Colors.black26,
offset: Offset(0, 3),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButton<DriversModel>(
isExpanded: true,
hint: const Text('Select Driver'),
value: selectedDriver,
items: driversList.map((driver) {
return DropdownMenuItem(
value: driver,
child: Text(driver.driver_name?.toString() ?? 'Driver'),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedDriver = value;
});
},
),
const SizedBox(height: 8),
DropdownButton<TankersModel>(
isExpanded: true,
hint: const Text('Select Tanker'),
value: selectedTanker,
items: tankersList.map((tanker) {
return DropdownMenuItem(
value: tanker,
child: Text(
'${tanker.tanker_name} (${tanker.capacity})',
),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedTanker = value;
});
},
),
const SizedBox(height: 8),
_buildInfoRow(
Icons.water_drop_outlined,
selectedSource?.source_name?.toString() ?? 'Select source from map',
),
if (routeLoading) ...[
const SizedBox(height: 8),
const LinearProgressIndicator(),
],
if (distanceText.isNotEmpty || eta.isNotEmpty) ...[
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0XFFF5F4FF),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
if (distanceText.isNotEmpty)
_buildInfoRow(Icons.route, 'Distance: $distanceText'),
if (eta.isNotEmpty)
_buildInfoRow(Icons.timer_outlined, 'ETA: $eta'),
],
),
),
],
if (routeError.isNotEmpty) ...[
const SizedBox(height: 8),
Text(
routeError,
style: const TextStyle(
color: Colors.red,
fontSize: 12,
),
),
],
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: assign,
child: const Text('ASSIGN'),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
if (loading) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Enterprise Dispatch Map'),
),
body: Stack(
children: [
GoogleMap(
initialCameraPosition: CameraPosition(
target: _deliveryPosition() ?? const LatLng(17.3850, 78.4867),
zoom: 12,
),
markers: _markers,
polylines: _polylines,
trafficEnabled: true,
zoomControlsEnabled: true,
myLocationButtonEnabled: true,
mapToolbarEnabled: false,
onMapCreated: (controller) {
_mapController = controller;
Future.delayed(const Duration(milliseconds: 400), () {
_fitMap();
});
},
),
Align(
alignment: Alignment.bottomCenter,
child: _buildBottomCard(),
),
],
),
);
}
}

@ -0,0 +1,428 @@
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class TankerOptionsDemo extends StatefulWidget {
@override
State<TankerOptionsDemo> createState() => _TankerOptionsDemoState();
}
class _TankerOptionsDemoState extends State<TankerOptionsDemo> {
GoogleMapController? mapController;
LatLng customerLocation =
LatLng(17.3850,78.4867);
String selectedTanker="TNK1";
List tankers=[
{
"id":"TNK1",
"lat":17.387,
"lng":78.489,
"distance":2.5,
"eta":15,
"status":"AVAILABLE"
},
{
"id":"TNK2",
"lat":17.381,
"lng":78.480,
"distance":5,
"eta":30,
"status":"ON_DELIVERY",
"availableIn":20
},
{
"id":"TNK3",
"lat":17.370,
"lng":78.470,
"distance":9,
"eta":50,
"status":"FAR"
}
];
Set<Marker> markers={};
@override
void initState(){
super.initState();
createMarkers();
}
void createMarkers(){
markers.add(
Marker(
markerId: MarkerId("customer"),
position: customerLocation,
infoWindow:
InfoWindow(title:"Delivery Location"),
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueBlue)
)
);
for(var t in tankers){
BitmapDescriptor color;
if(t["status"]=="AVAILABLE"){
color=
BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueGreen);
}
else if(t["status"]=="ON_DELIVERY"){
color=
BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueOrange);
}
else{
color=
BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueRed);
}
markers.add(
Marker(
markerId: MarkerId(t["id"]),
position: LatLng(
t["lat"],
t["lng"]
),
infoWindow:
InfoWindow(
title:t["id"],
snippet:
"ETA ${t["eta"]} min"
),
icon:color
)
);
}
setState(() {});
}
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title:
Text("Select Tanker"),
backgroundColor:
Colors.white,
),
body:
Column(
children:[
Container(
height:300,
child:
GoogleMap(
initialCameraPosition:
CameraPosition(
target:
customerLocation,
zoom:13
),
markers:markers,
),
),
Expanded(
child:
ListView(
children:
tankers.map((t){
return tankerCard(t);
}).toList(),
)
)
],
),
bottomNavigationBar:
Container(
padding:EdgeInsets.all(12),
child:
ElevatedButton(
style:
ElevatedButton.styleFrom(
backgroundColor:
Colors.green
),
onPressed:(){
Navigator.pop(context);
},
child:
Text("Confirm Selection")
),
),
);
}
Widget tankerCard(var tanker){
Color color;
if(tanker["status"]=="AVAILABLE"){
color=Colors.green;
}
else if(tanker["status"]=="ON_DELIVERY"){
color=Colors.orange;
}
else{
color=Colors.red;
}
return GestureDetector(
onTap:(){
selectedTanker=tanker["id"];
setState(() {});
},
child:
Container(
margin:
EdgeInsets.all(10),
padding:
EdgeInsets.all(12),
decoration:
BoxDecoration(
borderRadius:
BorderRadius.circular(10),
border:
Border.all(
color:
selectedTanker==tanker["id"]
?
Colors.green
:
Colors.grey
),
),
child:
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:[
Row(
children:[
Text(
tanker["id"],
style:
TextStyle(
fontSize:18,
fontWeight:
FontWeight.bold
),
),
Spacer(),
Container(
padding:
EdgeInsets.all(6),
decoration:
BoxDecoration(
color:
color,
borderRadius:
BorderRadius.circular(5)
),
child:
Text(
tanker["status"],
style:
TextStyle(
color:Colors.white)
),
)
],
),
SizedBox(height:8),
Text(
"Distance : ${tanker["distance"]} km"),
Text(
"ETA : ${tanker["eta"]} min"),
if(tanker["status"]=="ON_DELIVERY")
Text(
"Available in ${tanker["availableIn"]} min"),
if(tanker["status"]=="FAR")
Text(
"⚠ Transport charges higher"),
SizedBox(height:6),
if(tanker["status"]=="AVAILABLE")
Text(
"BEST OPTION",
style:
TextStyle(
color:Colors.green)
)
],
),
),
);
}
}

@ -16,7 +16,6 @@ class _CancelOrderScreenState extends State<CancelOrderScreen> {
final TextEditingController reasonController = TextEditingController();
final List<String> reasons = [
"Changed my mind",
"Tanker not available",
"Vehicle got damaged",
"Buyer asked me to cancel",

@ -24,6 +24,7 @@ class OrdersModel {
String delivery_agent_name = '';
String tanker_name = '';
String water_source_location='';
String remarks='';
OrdersModel();
@ -45,6 +46,7 @@ class OrdersModel {
rtvm.delivery_agent_name = json['delivery_agent'] ?? '';
rtvm.tanker_name = json['tankerName'] ?? '';
rtvm.water_source_location = json['water_source_location'] ?? '';
rtvm.remarks = json['remarks'] ?? '';
// Split and trim
List<String> parts = rtvm.address.split(',').map((e) => e.trim()).toList();

@ -336,8 +336,12 @@ class _DriverDetailsPageState extends State<DriverDetailsPage> {
label: "Age *",
child: TextFormField(
controller: _ageCtrl,
validator: (v) =>
_validatePhone(v, label: "Age"),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return "Driver Age required";
}
return null;
},
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,

@ -13,7 +13,9 @@ class DriversModel {
String age='';
String license_expiry_date='';
String picture='';
String dbId='';
List<dynamic> licenseImages= [];
List<dynamic> blocked_dates = [];
DriversModel();
factory DriversModel.fromJson(Map<String, dynamic> json) {
@ -22,6 +24,7 @@ class DriversModel {
rtvm.supplier_name = json['suppliername'] ?? '';
rtvm.driver_name = json['name'] ?? ''; // Correct
rtvm.status = json['status'] ?? '';
rtvm.dbId = json['_id'] ?? '';
rtvm.address = json['address'] ?? '';
rtvm.phone_number = json['phone'] ?? '';
rtvm.alt_phone_number = json['alternativeContactNumber'] ?? '';
@ -32,6 +35,8 @@ class DriversModel {
rtvm.license_expiry_date=json['license_number'] ?? '';
rtvm.age=json['age'] ?? '';
rtvm.licenseImages = json['images'] ?? [];
rtvm.blocked_dates =
json['blocked_dates'] ?? [];
return rtvm;
}
}

@ -1395,8 +1395,14 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
final q = search.trim().toLowerCase();
String capacityClean =
it.capacity.replaceAll(",", "");
bool matchesSearch =
q.isEmpty || it.tanker_name.toLowerCase().contains(q);
q.isEmpty ||
it.tanker_name.toLowerCase().contains(q) ||
capacityClean.contains(q.replaceAll(",", "")) ||
it.type_of_water.toLowerCase().contains(q);
bool matchesFilter = true;
@ -1512,16 +1518,52 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
),
const SizedBox(height: 12),
IntrinsicHeight(
child: Row(
child: /*Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(child: SmallMetricBox(title: 'Active', value: activeCount.toString())),
const SizedBox(width: 8),
Expanded(child: SmallMetricBox(title: 'Inactive', value: inactiveCount.toString())),
*//*const SizedBox(width: 8),
Expanded(child: SmallMetricBox(title: 'Inactive', value: inactiveCount.toString())),*//*
const SizedBox(width: 8),
Expanded(child: SmallMetricBox(title: 'Under Maintenance', value: maintenanceCount.toString())),
],
),
),*/
Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: GestureDetector(
onTap: (){
setState(() {
selectedFilter = "Active";
});
},
child: SmallMetricBox(
title: 'Active',
value: activeCount.toString()
),
),
),
SizedBox(width: 8),
Expanded(
child: GestureDetector(
onTap: (){
setState(() {
selectedFilter = "Maintenance";
});
},
child: SmallMetricBox(
title: 'Under Maintenance',
value: maintenanceCount.toString()
),
),
),
],
)
),
],
),

@ -1,4 +1,5 @@
class TankersModel {
class TankersModel {
String tanker_name = '';
String address = '';
String type_of_water = '';
@ -13,32 +14,77 @@ class TankersModel {
String insurance_expiry='';
String tanker_type='';
String pumping_fee='';
List<dynamic> availability= [];
List<dynamic> images= [];
/// ADD THIS
List<dynamic> blocked_dates = [];
TankersModel();
factory TankersModel.fromJson(Map<String, dynamic> json){
TankersModel rtvm = new TankersModel();
rtvm.tanker_name = json['tankerName']?? '';
rtvm.dbId = json['_id']?? '';
rtvm.address = json['supplier_address']?? '';
rtvm.type_of_water = json['typeofwater'] ?? '';
rtvm.capacity = json['capacity'] ?? '';
rtvm.license_plate = json['license_plate'] ?? '';
rtvm.supplier_name = json['supplier_name'] ?? '';
rtvm.price = json['price'] ?? '';
rtvm.delivery_fee = json['delivery_fee'] ?? '';
rtvm.availability = json['availability'] ?? [];
rtvm.images = json['images'] ?? [];
rtvm.manufacturing_year = json['manufacturing_year'] ?? '';
rtvm.insurance_expiry = json['insurance_exp_date'] ?? '';
rtvm.tanker_type = json['tanker_type'] ?? '';
rtvm.pumping_fee = json['pumping_fee'] ?? '';
TankersModel rtvm =
TankersModel();
rtvm.tanker_name =
json['tankerName'] ?? '';
rtvm.dbId =
json['_id'] ?? '';
rtvm.address =
json['supplier_address'] ?? '';
rtvm.type_of_water =
json['typeofwater'] ?? '';
rtvm.capacity =
json['capacity'] ?? '';
rtvm.license_plate =
json['license_plate'] ?? '';
rtvm.supplier_name =
json['supplier_name'] ?? '';
rtvm.price =
json['price'] ?? '';
rtvm.delivery_fee =
json['delivery_fee'] ?? '';
rtvm.availability =
json['availability'] ?? [];
rtvm.images =
json['images'] ?? [];
/// ADD THIS
rtvm.blocked_dates =
json['blocked_dates'] ?? [];
rtvm.manufacturing_year =
json['manufacturing_year'] ?? '';
rtvm.insurance_expiry =
json['insurance_exp_date'] ?? '';
rtvm.tanker_type =
json['tanker_type'] ?? '';
rtvm.pumping_fee =
json['pumping_fee'] ?? '';
return rtvm;
}
Map<String, dynamic> toJson() => {
"boreName":this.tanker_name,
"tankerName": tanker_name,
};
}
Loading…
Cancel
Save