From e49f859358d98829f987098cc5488cfda9e0c3fd Mon Sep 17 00:00:00 2001 From: Sneha Date: Fri, 5 Dec 2025 14:41:27 +0530 Subject: [PATCH] changes --- lib/common/settings.dart | 29 +- lib/orders/change_driver.dart | 4 +- lib/plans/accept_plan_requests.dart | 25 +- lib/plans/plan_requests.dart | 2 +- lib/plans/plan_requests_model.dart | 12 +- lib/resources/tanker_details.dart | 1066 +++++++++++++++------------ 6 files changed, 637 insertions(+), 501 deletions(-) diff --git a/lib/common/settings.dart b/lib/common/settings.dart index f0b012d..7c8305e 100644 --- a/lib/common/settings.dart +++ b/lib/common/settings.dart @@ -120,12 +120,10 @@ InputDecoration textFormFieldDecorationHintText(IconData icon,var text){ ); } - TextStyle PreloaderText() { return TextStyle(color:primaryColor); } - class AppSettings{ static SharedPreferences sharedPreferences = SharedPreferences.getInstance() as SharedPreferences; @@ -159,6 +157,7 @@ class AppSettings{ static String acceptOrderRequestsUrl = host + 'request-booking-with-charges'; static String getAcceptedOrdersFromUsersUrl = host + 'getAllTankersBookingdetails'; static String getPlanRequestsFromUsersUrl = host + 'getuserRequestbookingsforplansforsupplier'; + static String acceptPlanRequestsUrl = host + 'supplier/recurring/respond'; static String getTankersUrl = host + 'getTankers'; static String getTankerDetailsByNameUrl = host + 'getsingledetails'; static String addTankerUrl = host + 'addTankers'; @@ -503,6 +502,30 @@ class AppSettings{ } } + static Future acceptPlanRequests(payload,dbId) async { + + var uri = Uri.parse(acceptPlanRequestsUrl+'/'+dbId+'/'+AppSettings.supplierId); + + var response = await http.put(uri, body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return true; + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.put(uri,body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } + static Future getTankers() async { var uri = Uri.parse(getTankersUrl); uri = uri.replace(query: 'supplierId=$supplierId'); @@ -1302,6 +1325,7 @@ class AppSettings{ backgroundColor: Colors.white, elevation: 0, scrolledUnderElevation: 0, + titleSpacing: 0, title: Text(title,style: fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w500),), iconTheme: IconThemeData(color: Color(0XFF2A2A2A)), actions: [ @@ -1424,5 +1448,4 @@ class AppSettings{ ); } - } \ No newline at end of file diff --git a/lib/orders/change_driver.dart b/lib/orders/change_driver.dart index 06778a6..71724dd 100644 --- a/lib/orders/change_driver.dart +++ b/lib/orders/change_driver.dart @@ -134,7 +134,6 @@ class _ChangeDriverScreenState extends State { } } - Widget _assignedTankerDetails() { if (isTankersDataLoading) { return const Center(child: CircularProgressIndicator()); @@ -748,7 +747,7 @@ class _ChangeDriverScreenState extends State { final d = sourcesList[idx]; final isSelected = selectedSourceIndex == idx; - /* final statusColor = d.status == "available" + /* final statusColor = d.status == "available" ? const Color(0XFF0A9E04) : (d.status == "on delivery" ? const Color(0XFFD0AE3C) @@ -893,7 +892,6 @@ class _ChangeDriverScreenState extends State { ); } - @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/plans/accept_plan_requests.dart b/lib/plans/accept_plan_requests.dart index 2a38f63..71d0a57 100644 --- a/lib/plans/accept_plan_requests.dart +++ b/lib/plans/accept_plan_requests.dart @@ -12,18 +12,13 @@ class AcceptPlanRequests extends StatefulWidget { class _AcceptPlanRequestsState extends State { int advancePayable = 0; - int advance =0; + //int advance =0; double amountToPayAfterDelivery = 0.0; - double totalFare = 0.0; @override void initState() { // TODO: implement initState super.initState(); - advance = 150; - advancePayable = advance; - //totalFare = advance + double.parse(widget.order.quoted_amount)??0; - amountToPayAfterDelivery = totalFare - advancePayable; } @override @@ -272,13 +267,10 @@ class _AcceptPlanRequestsState extends State { ), _detailRow("Tanker Price", "₹${AppSettings.formDouble(widget.order.quoted_amount) ?? ''}"), - SizedBox( - height: MediaQuery.of(context).size.height * .004, - ), - _detailRow("Booking Charges", "₹ " + advance.toString()), - SizedBox( + /* SizedBox( height: MediaQuery.of(context).size.height * .004, ), + _detailRow("Total Amount", "₹ " + totalFare.toString()), SizedBox( height: MediaQuery.of(context).size.height * .004, @@ -296,7 +288,7 @@ class _AcceptPlanRequestsState extends State { height: MediaQuery.of(context).size.height * .004, ), _detailRow("Amount to Pay (After Delivery)", - '₹${AppSettings.formDouble(amountToPayAfterDelivery.toString()) ?? ''}'), + '₹${AppSettings.formDouble(amountToPayAfterDelivery.toString()) ?? ''}'),*/ ], ), ), @@ -330,7 +322,6 @@ class _AcceptPlanRequestsState extends State { MaterialPageRoute( builder: (_) => EditPlanRequests( order: widget.order, - advance: advance.toString(), status: widget.status, ), ), @@ -425,12 +416,12 @@ class _AcceptPlanRequestsState extends State { if (isOnline) { var payload = new Map(); - payload["supplierId"] = AppSettings.supplierId; + /*payload["supplierId"] = AppSettings.supplierId; payload["amount"] = int.parse(widget.order.quoted_amount); - payload["delivery_charges"] = advance; + payload["delivery_charges"] = advance;*/ payload["action"] = 'accept'; - bool status = await AppSettings.acceptOrderRequests( + bool status = await AppSettings.acceptPlanRequests( payload, widget.order.dbId); try { @@ -440,7 +431,7 @@ class _AcceptPlanRequestsState extends State { } else{ Navigator.of(context,rootNavigator: true).pop(); - AppSettings.longFailedToast("Accept of order request Failed"); + AppSettings.longFailedToast("Accept of plan request Failed"); } } catch (e) { Navigator.of(context,rootNavigator: true).pop(); diff --git a/lib/plans/plan_requests.dart b/lib/plans/plan_requests.dart index f11f68a..d432cbc 100644 --- a/lib/plans/plan_requests.dart +++ b/lib/plans/plan_requests.dart @@ -81,7 +81,7 @@ class _PlanRequestsPageState extends State { // ✅ Statuses that ignore time if (dbLower == "reject") return {"status": "Rejected", "color": const Color(0XFFE2483D)}; - if (dbLower == "accept") return {"status": "Accepted", "color": const Color(0XFF0A9E04)}; + if (dbLower == "accepted") return {"status": "Accepted", "color": const Color(0XFF0A9E04)}; if (dbLower == "advance_paid") return {"status": "Accepted", "color": const Color(0XFF0A9E04)}; if (dbLower == "cancelled" || dbLower == "cancelled_by_user" || dbLower == "cancelled_by_supplier") { return {"status": "Cancelled", "color": const Color(0XFF757575)}; diff --git a/lib/plans/plan_requests_model.dart b/lib/plans/plan_requests_model.dart index 692b95e..59ad216 100644 --- a/lib/plans/plan_requests_model.dart +++ b/lib/plans/plan_requests_model.dart @@ -25,12 +25,12 @@ class PlanRequestsModel { factory PlanRequestsModel.fromJson(Map json){ PlanRequestsModel rtvm = new PlanRequestsModel(); - // rtvm.building_name = json['customer_details']['buildingName'] ?? ''; + rtvm.building_name = json['customer_details']['buildingName'] ?? ''; rtvm.dbId = json['_id']?? ''; - // rtvm.address = json['customer_details']['profile']['address1'] ?? ''; + rtvm.address = json['customer_details']['profile']['address1'] ?? ''; rtvm.type_of_water = json['type_of_water'] ?? ''; rtvm.capacity = json['capacity'] ?? ''; - //rtvm.quantity = json['quantity']?? ''; + rtvm.quantity = json['quantity']?? ''; rtvm.frequency = json['frequency']?? ''; if(rtvm.frequency.toString().toLowerCase()=='weekly_twice'){ @@ -53,9 +53,9 @@ class PlanRequestsModel { rtvm.averageTime = json['time'] ?? ''; rtvm.time = json['my_supplier_entry']['time'] ?? ''; rtvm.status = json['my_supplier_entry']['status'] ?? ''; - //rtvm.quoted_amount = json['my_supplier_entry']['quoted_amount'].toString() ?? ''; - //rtvm.lng=json['customer_details']['longitude'] ?? 0.0; - //rtvm.lat=json['customer_details']['latitude'] ?? 0.0; + rtvm.quoted_amount = json['my_supplier_entry']['quoted_amount'].toString() ?? ''; + rtvm.lng=json['customer_details']['longitude'] ?? 0.0; + rtvm.lat=json['customer_details']['latitude'] ?? 0.0; // Split and trim List parts = rtvm.address.split(',').map((e) => e.trim()).toList(); diff --git a/lib/resources/tanker_details.dart b/lib/resources/tanker_details.dart index 428c8a5..03c1e4e 100644 --- a/lib/resources/tanker_details.dart +++ b/lib/resources/tanker_details.dart @@ -17,7 +17,6 @@ class FirstCharUppercaseFormatter extends TextInputFormatter { final text = newValue.text; if (text.isEmpty) return newValue; - // Find first non-space char final i = text.indexOf(RegExp(r'\S')); if (i == -1) return newValue; @@ -44,7 +43,6 @@ class TankerDetailsPage extends StatefulWidget { } class _TankerDetailsPageState extends State { - final _formKey = GlobalKey(); final _nameCtrl = TextEditingController(); final _capacityCtrl = TextEditingController(); @@ -52,11 +50,9 @@ class _TankerDetailsPageState extends State { final _mfgYearCtrl = TextEditingController(); final _insExpiryCtrl = TextEditingController(); - // Dropdown selections (sheet) String? selectedType; String? selectedTypeOfWater; - // Dropdown options (adjust to your backend) final List tankerTypes = const [ "Standard Tanker", "High-Capacity Tanker", @@ -75,7 +71,7 @@ class _TankerDetailsPageState extends State { int selectedTab = 0; String search = ''; bool isLoading = false; - bool isTankerTripsLoading=false; + bool isTankerTripsLoading = false; bool isStatusLoading = false; String? currentAvailability; @@ -84,8 +80,8 @@ class _TankerDetailsPageState extends State { @override void initState() { super.initState(); - _nameCtrl.text=widget.tankerDetails.tanker_name ?? ''; - // ✅ If the tanker already has availability from backend, prepare it + _nameCtrl.text = widget.tankerDetails.tanker_name ?? ''; + if (widget.tankerDetails.availability != null && widget.tankerDetails.availability is List && widget.tankerDetails.availability.length == 2) { @@ -93,11 +89,6 @@ class _TankerDetailsPageState extends State { currentAvailability = "${a[0]}|${a[1]}"; _fetchTankerTrips(); - - // ✅ Automatically show dropdown bottom sheet after short delay - /*WidgetsBinding.instance.addPostFrameCallback((_) { - _showDropdownBottomSheet(defaultValue: currentAvailability); - });*/ } } @@ -112,6 +103,7 @@ class _TankerDetailsPageState extends State { final data = (jsonDecode(response)['data'] as List) .map((e) => TankerTripsModel.fromJson(e)) .toList(); + if (!mounted) return; setState(() { tankerTripsList = data; @@ -123,7 +115,6 @@ class _TankerDetailsPageState extends State { } } - // Dropdown options: fill + availability combined final List options = [ "empty|available", "empty|blocked", @@ -139,28 +130,25 @@ class _TankerDetailsPageState extends State { } Future _updateAvailability(String selectedValue) async { - // 🔹 Split the combined dropdown value like "filled|available" final parts = selectedValue.split('|'); final availability = [parts[0], parts[1]]; - // 🔹 Build payload for updateTanker API final payload = { "tankerName": widget.tankerDetails.tanker_name, - "availability": availability, // ✅ send array as backend expects + "availability": availability, }; try { setState(() => isStatusLoading = true); - // 🔹 Reuse your existing update API - final bool tankStatus = await AppSettings.updateTankerAvailability(payload); + final bool tankStatus = + await AppSettings.updateTankerAvailability(payload); if (!mounted) return; if (tankStatus) { AppSettings.longSuccessToast("Tanker status updated successfully"); - // Close sheet and refresh details Navigator.pop(context, true); await _refreshTankerDetails(); } else { @@ -177,12 +165,12 @@ class _TankerDetailsPageState extends State { } void _showDropdownBottomSheet({String? defaultValue}) { - String? selectedValue = defaultValue; // preselect from backend + String? selectedValue = defaultValue; showModalBottomSheet( context: context, isScrollControlled: true, - backgroundColor: Colors.transparent, // nice rounded corners + backgroundColor: Colors.transparent, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), @@ -190,7 +178,7 @@ class _TankerDetailsPageState extends State { final viewInsets = MediaQuery.of(context).viewInsets.bottom; return FractionallySizedBox( - heightFactor: 0.6, // ⬅️ increase/decrease height here (e.g., 0.7 / 0.8) + heightFactor: 0.6, child: Container( decoration: const BoxDecoration( color: Colors.white, @@ -200,7 +188,6 @@ class _TankerDetailsPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // drag handle Center( child: Container( width: 60, @@ -219,7 +206,6 @@ class _TankerDetailsPageState extends State { ), const SizedBox(height: 20), - // Make central content scrollable within fixed height Expanded( child: SingleChildScrollView( child: Column( @@ -250,7 +236,6 @@ class _TankerDetailsPageState extends State { ), ), - // Sticky submit at bottom SizedBox( width: double.infinity, child: ElevatedButton( @@ -271,7 +256,10 @@ class _TankerDetailsPageState extends State { }, child: isLoading ? const SizedBox( - width: 20, height: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) + width: 20, + height: 20, + child: CircularProgressIndicator( + color: Colors.white, strokeWidth: 2)) : const Text("Submit"), ), ), @@ -284,109 +272,120 @@ class _TankerDetailsPageState extends State { } showDeleteTankerDialog(BuildContext context) async { - return showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return AlertDialog( - backgroundColor: Color(0XFFFFFFFF),// Set your desired background color - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), // Optional: Rounded corners - ), - title: Center( - child: Text('Delete Tanker?' ,style: fontTextStyle(16,Color(0XFF3B3B3B),FontWeight.w600),), - ), - content: SingleChildScrollView( - child: ListBody( - children: [ - Container( - child: Text('Do u want to delete "${widget.tankerDetails.tanker_name}"',style: fontTextStyle(14,Color(0XFF101214),FontWeight.w600),), - ), - ], + return StatefulBuilder(builder: + (BuildContext context, StateSetter setState) { + return AlertDialog( + backgroundColor: Color(0XFFFFFFFF), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + title: Center( + child: Text( + 'Delete Tanker?', + style: + fontTextStyle(16, Color(0XFF3B3B3B), FontWeight.w600), + ), + ), + content: SingleChildScrollView( + child: ListBody( + children: [ + Container( + child: Text( + 'Do u want to delete "${widget.tankerDetails.tanker_name}"', + style: fontTextStyle( + 14, Color(0XFF101214), FontWeight.w600), + ), ), - ), - actions: [ - Center( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded(child: GestureDetector( - onTap: (){ - Navigator.pop(context); + ], + ), + ), + + actions: [ + Center( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Color(0XFFFFFFFF), + border: Border.all( + width: 1, color: Color(0XFF1D7AFC)), + borderRadius: BorderRadius.circular(12)), + alignment: Alignment.center, + child: Padding( + padding: EdgeInsets.fromLTRB( + 16, 12, 16, 12), + child: Text( + 'Cancel', + style: fontTextStyle( + 12, + Color(0XFF1D7AFC), + FontWeight.w600), + ), + ), + ), + ), + ), + SizedBox( + width: + MediaQuery.of(context).size.width * .016), + Expanded( + child: GestureDetector( + onTap: () async { + bool status = await AppSettings.deleteTanker( + widget.tankerDetails.tanker_name, + ); + + if (status) { + AppSettings.longSuccessToast( + 'Tanker deleted successfully'); + Navigator.of(context).pop(true); + Navigator.of(context).pop(true); + } else { + Navigator.of(context).pop(true); + AppSettings.longFailedToast( + 'Failed to delete tanker'); + } }, child: Container( decoration: BoxDecoration( shape: BoxShape.rectangle, - color: Color(0XFFFFFFFF), + color: Color(0XFFE2483D), border: Border.all( width: 1, - color: Color(0XFF1D7AFC)), - borderRadius: BorderRadius.circular( - 12, - )), + color: Color(0XFFE2483D)), + borderRadius: + BorderRadius.circular(12)), alignment: Alignment.center, - child: Visibility( - visible: true, - child: Padding( - padding: EdgeInsets.fromLTRB(16,12,16,12), - child: Text('Cancel', style: fontTextStyle(12, Color(0XFF1D7AFC), FontWeight.w600)), + child: Padding( + padding: EdgeInsets.fromLTRB( + 16, 12, 16, 12), + child: Text( + 'Delete', + style: fontTextStyle( + 12, + Color(0XFFFFFFFF), + FontWeight.w600), ), ), ), - ),), - SizedBox(width:MediaQuery.of(context).size.width * .016,), - Expanded(child: GestureDetector( - onTap: ()async{ - - bool status = await AppSettings.deleteTanker(widget.tankerDetails.tanker_name,); - if(status){ - AppSettings.longSuccessToast('Tanker deleted successfully'); - Navigator.of(context).pop(true); - Navigator.of(context).pop(true); - } - else{ - Navigator.of(context).pop(true); - AppSettings.longFailedToast('Failed to delete tanker'); - } - - - }, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: Color(0XFFE2483D), - border: Border.all( - width: 1, - color: Color(0XFFE2483D)), - borderRadius: BorderRadius.circular( - 12, - )), - alignment: Alignment.center, - child: Visibility( - visible: true, - child: Padding( - padding: EdgeInsets.fromLTRB(16,12,16,12), - child: Text( - 'Delete', - style: fontTextStyle( - 12, - Color(0XFFFFFFFF), - FontWeight.w600)), - ), - ), - ) - ),) - - - ], - ), - ), - ], - ); - }); + )), + ], + ), + ), + ], + ); + }); }, ); } @@ -424,7 +423,6 @@ class _TankerDetailsPageState extends State { return Colors.black87; } } - Future _pickInsuranceDate() async { final picked = await showDatePicker( context: context, @@ -497,18 +495,16 @@ class _TankerDetailsPageState extends State { (o) => o.toLowerCase() == inc.toLowerCase(), orElse: () => '', ); - return match.isEmpty ? null : match; // return the exact option string + return match.isEmpty ? null : match; } Future _updateTanker() async { - // Validate final ok = _formKey.currentState?.validate() ?? false; if (!ok) { - setState(() {}); // force rebuild to show errors + setState(() {}); return; } - // Build payload keys to match your backend final payload = { "tankerName": _nameCtrl.text.trim(), "capacity": _capacityCtrl.text.trim(), @@ -521,21 +517,21 @@ class _TankerDetailsPageState extends State { "manufacturing_year": _mfgYearCtrl.text.trim(), "insurance_exp_date": _insExpiryCtrl.text.trim(), "delivery_fee": widget.tankerDetails.delivery_fee, - "pumping_fee":widget.tankerDetails.pumping_fee, + "pumping_fee": widget.tankerDetails.pumping_fee, "price": widget.tankerDetails.price, }; try { - final bool tankStatus = await AppSettings.updateTanker(payload,widget.tankerDetails.tanker_name); + final bool tankStatus = await AppSettings.updateTanker( + payload, widget.tankerDetails.tanker_name); if (!mounted) return; if (tankStatus) { AppSettings.longSuccessToast("Tanker Updated Successfully"); Navigator.pop(context, true); - _refreshTankerDetails();// close sheet + _refreshTankerDetails(); _resetForm(); - // refresh from server } else { AppSettings.longFailedToast("Tanker update failed"); } @@ -547,7 +543,6 @@ class _TankerDetailsPageState extends State { } Future openTankerSimpleSheet(BuildContext context) async { - _nameCtrl.text = widget.tankerDetails.tanker_name ?? ''; _capacityCtrl.text = widget.tankerDetails.capacity ?? ''; _plateCtrl.text = widget.tankerDetails.license_plate ?? ''; @@ -555,7 +550,8 @@ class _TankerDetailsPageState extends State { _insExpiryCtrl.text = widget.tankerDetails.insurance_expiry ?? ''; selectedType = fitToOption(widget.tankerDetails.tanker_type, tankerTypes); - selectedTypeOfWater = fitToOption(widget.tankerDetails.type_of_water, typeOfWater); + selectedTypeOfWater = + fitToOption(widget.tankerDetails.type_of_water, typeOfWater); await showModalBottomSheet( context: context, @@ -601,14 +597,18 @@ class _TankerDetailsPageState extends State { label: "Tanker Name *", child: TextFormField( controller: _nameCtrl, - validator: (v) => _required(v, field: "Tanker Name"), + validator: (v) => + _required(v, field: "Tanker Name"), textCapitalization: TextCapitalization.none, inputFormatters: const [ - FirstCharUppercaseFormatter(), // << live first-letter caps + FirstCharUppercaseFormatter(), ], decoration: InputDecoration( hintText: "Enter Tanker Name", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), @@ -620,16 +620,21 @@ class _TankerDetailsPageState extends State { label: "Tanker Capacity (in L) *", child: TextFormField( controller: _capacityCtrl, - validator: (v) => _required(v, field: "Tanker Capacity"), + validator: (v) => + _required(v, field: "Tanker Capacity"), decoration: InputDecoration( hintText: "10,000", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), keyboardType: TextInputType.number, inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[0-9,]')), + FilteringTextInputFormatter.allow( + RegExp(r'[0-9,]')), ], textInputAction: TextInputAction.next, ), @@ -640,21 +645,31 @@ class _TankerDetailsPageState extends State { child: DropdownButtonFormField( value: selectedType, items: tankerTypes - .map((t) => DropdownMenuItem(value: t, child: Text(t))) + .map((t) => + DropdownMenuItem(value: t, child: Text(t))) .toList(), - onChanged: (v) => setState(() => selectedType = v), - validator: (v) => v == null || v.isEmpty ? "Tanker Type is required" : null, + onChanged: (v) => + setState(() => selectedType = v), + validator: (v) => + v == null || v.isEmpty + ? "Tanker Type is required" + : null, isExpanded: true, alignment: Alignment.centerLeft, hint: Text( "Select Type", - style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + style: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), ), - icon: Image.asset('images/downarrow.png', width: 16, height: 16), + icon: Image.asset('images/downarrow.png', + width: 16, height: 16), decoration: const InputDecoration( border: OutlineInputBorder(), isDense: false, - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14), + contentPadding: EdgeInsets.symmetric( + horizontal: 12, vertical: 14), ), ), ), @@ -662,25 +677,37 @@ class _TankerDetailsPageState extends State { _LabeledField( label: "Type of water *", child: DropdownButtonFormField( - value: (selectedTypeOfWater != null && typeOfWater.contains(selectedTypeOfWater)) + value: (selectedTypeOfWater != null && + typeOfWater + .contains(selectedTypeOfWater)) ? selectedTypeOfWater - : null, // <- ensure null instead of "" or a non-member + : null, items: typeOfWater - .map((t) => DropdownMenuItem(value: t, child: Text(t))) + .map((t) => + DropdownMenuItem(value: t, child: Text(t))) .toList(), - onChanged: (v) => setState(() => selectedTypeOfWater = v), - validator: (v) => v == null || v.isEmpty ? "Type of water is required" : null, + onChanged: (v) => + setState(() => selectedTypeOfWater = v), + validator: (v) => + v == null || v.isEmpty + ? "Type of water is required" + : null, isExpanded: true, alignment: Alignment.centerLeft, hint: Text( "Select type of water", - style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + style: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), ), - icon: Image.asset('images/downarrow.png', width: 16, height: 16), + icon: Image.asset('images/downarrow.png', + width: 16, height: 16), decoration: const InputDecoration( border: OutlineInputBorder(), isDense: false, - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14), + contentPadding: EdgeInsets.symmetric( + horizontal: 12, vertical: 14), ), ), ), @@ -689,14 +716,19 @@ class _TankerDetailsPageState extends State { label: "License Plate *", child: TextFormField( controller: _plateCtrl, - validator: (v) => _required(v, field: "License Plate"), + validator: (v) => + _required(v, field: "License Plate"), decoration: InputDecoration( hintText: "AB 05 H 4948", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), - textCapitalization: TextCapitalization.characters, + textCapitalization: + TextCapitalization.characters, textInputAction: TextInputAction.next, ), ), @@ -707,7 +739,10 @@ class _TankerDetailsPageState extends State { controller: _mfgYearCtrl, decoration: InputDecoration( hintText: "YYYY", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), @@ -727,10 +762,15 @@ class _TankerDetailsPageState extends State { readOnly: true, decoration: InputDecoration( hintText: "DD-MM-YYYY", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), + hintStyle: fontTextStyle( + 14, + const Color(0xFF939495), + FontWeight.w400), border: const OutlineInputBorder(), isDense: true, - suffixIcon: const Icon(Icons.calendar_today_outlined, size: 18), + suffixIcon: const Icon( + Icons.calendar_today_outlined, + size: 18), ), onTap: _pickInsuranceDate, ), @@ -744,34 +784,21 @@ class _TankerDetailsPageState extends State { style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8270DB), foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric( + vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), ), - onPressed: (){ + onPressed: () { _updateTanker(); - - /*if (_formKey.currentState!.validate()) { - final updatedTanker = { - "tanker_name": _nameCtrl.text.trim(), - "capacity": _capacityCtrl.text.trim(), - "license_plate": _plateCtrl.text.trim(), - "manufacturing_year": _mfgYearCtrl.text.trim(), - "insurance_expiry": _insExpiryCtrl.text.trim(), - "tanker_type": selectedType, - "type_of_water": selectedTypeOfWater, - }; - - // You can now call your update API or local DB function - print("Updated Tanker: $updatedTanker"); - - Navigator.pop(context); - }*/ }, child: Text( "Update", - style: fontTextStyle(14, Colors.white, FontWeight.w600), + style: fontTextStyle( + 14, + Colors.white, + FontWeight.w600), ), ), ), @@ -790,329 +817,417 @@ class _TankerDetailsPageState extends State { Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { - // ✅ Return true to indicate successful tanker update refresh - Navigator.pop(context, true); - return false; // prevent default pop since we manually handled it - }, - child: Scaffold( - backgroundColor: Color(0XFFF1F1F1), - appBar: AppSettings.supplierAppBarWithActionsText(widget.tankerDetails.tanker_name.isNotEmpty - ? widget.tankerDetails.tanker_name[0].toUpperCase() + - widget.tankerDetails.tanker_name.substring(1) - : '', context), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - decoration: const BoxDecoration( - color: Color(0XFFFFFFFF), - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24), - ), - ), - padding: const EdgeInsets.all(16), - child: Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Stack( - children: [ - Image.asset( - 'images/tanker_image.jpeg', // Replace with your image + Navigator.pop(context, true); + return false; + }, + child: Scaffold( + backgroundColor: Color(0XFFF1F1F1), + appBar: AppSettings.supplierAppBarWithActionsText( + widget.tankerDetails.tanker_name.isNotEmpty + ? widget.tankerDetails.tanker_name[0].toUpperCase() + + widget.tankerDetails.tanker_name.substring(1) + : '', + context), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: const BoxDecoration( + color: Color(0XFFFFFFFF), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24), + ), + ), + padding: const EdgeInsets.all(16), + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Image.asset( + 'images/tanker_image.jpeg', width: double.infinity, height: 180, fit: BoxFit.cover, ), - /*Positioned( - bottom: 12, - left: 12, - child: Row( - children: [ - _buildStatusChip("filled", const Color(0xFF4F46E5)), - const SizedBox(width: 8), - _buildStatusChip("available", const Color(0xFF0A9E04)), - ], - ), - ),*/ - ], - ), - ), - const SizedBox(height: 16), - Row( - children: widget.tankerDetails.availability - .map((s) { - final chipTextColor = _chipTextColor(s); - return Container( - margin: const EdgeInsets.only(right: 6), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: _chipColor(s), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: chipTextColor, width: 1), - ), - child: Text( - s, - style: fontTextStyle(10, chipTextColor, FontWeight.w400), - ), - ); - }) - .toList(), - ), - const SizedBox(height: 16), - // 🚚 Tanker Info - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.tankerDetails.tanker_name, - style: fontTextStyle(16, const Color(0xFF2A2A2A), FontWeight.w600), - ), - SizedBox(height: 2), - Text( - widget.tankerDetails.type_of_water+' - '+widget.tankerDetails.capacity+' L', - style: fontTextStyle(10, const Color(0xFF646566), FontWeight.w400), + ), + const SizedBox(height: 16), + + Row( + children: widget.tankerDetails.availability + .map((s) { + final chipTextColor = _chipTextColor(s); + return Container( + margin: + const EdgeInsets.only(right: 6), + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: _chipColor(s), + borderRadius: + BorderRadius.circular(8), + border: Border.all( + color: chipTextColor, width: 1), ), - SizedBox(height: 2), - Text( - widget.tankerDetails.license_plate, - style: fontTextStyle(10, const Color(0xFF646566), FontWeight.w400), + child: Text( + s, + style: fontTextStyle( + 10, + chipTextColor, + FontWeight.w400), ), - ], - ), + ); + }).toList(), ), - PopupMenuButton( - // 🔁 Use `child:` so you can place any widget (your 3-dots image) - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0), - child: Image.asset( - 'images/popup_menu.png', // your 3-dots image - width: 22, - height: 22, - // If you want to tint it like an icon: - color: Color(0XFF939495), // remove if you want original colors - colorBlendMode: BlendMode.srcIn, - ), - ), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - offset: const Offset(0, 40), - color: Colors.white, - elevation: 4, - onSelected: (value) { - if (value == 'edit') { - openTankerSimpleSheet(context); - } else if (value == 'disable') { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Disable selected')), - ); - } else if (value == 'delete') { - showDeleteTankerDialog(context); - } - }, - itemBuilder: (context) => [ - PopupMenuItem( - value: 'edit', - child: Row( + const SizedBox(height: 16), + + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, children: [ - Image.asset( - 'images/edit.png', - width: 20, - height: 20, - color: Color(0XFF646566), // tint (optional) - colorBlendMode: BlendMode.srcIn, - ), - const SizedBox(width: 12), Text( - 'Edit', - style: fontTextStyle(14, const Color(0XFF646566), FontWeight.w400), + widget.tankerDetails.tanker_name, + style: fontTextStyle( + 16, + const Color(0xFF2A2A2A), + FontWeight.w600), ), - ], - ), - ), - PopupMenuItem( - value: 'disable', - child: Row( - children: [ - Image.asset( - 'images/disable.png', - width: 20, - height: 20, - color: Color(0XFF646566), // tint (optional) - colorBlendMode: BlendMode.srcIn, + SizedBox(height: 2), + Text( + widget.tankerDetails + .type_of_water + + ' - ' + + widget.tankerDetails + .capacity + + ' L', + style: fontTextStyle( + 10, + const Color(0xFF646566), + FontWeight.w400), ), - const SizedBox(width: 12), + SizedBox(height: 2), Text( - 'Disable', - style: fontTextStyle(14, const Color(0XFF646566), FontWeight.w400), + widget.tankerDetails + .license_plate, + style: fontTextStyle( + 10, + const Color(0xFF646566), + FontWeight.w400), ), ], ), ), - PopupMenuItem( - value: 'delete', - child: Row( - children: [ - Image.asset( - 'images/delete.png', - width: 20, - height: 20, - color: Color(0XFFE2483D), // red like your example - colorBlendMode: BlendMode.srcIn, + + PopupMenuButton( + child: Padding( + padding: + const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 8.0), + child: Image.asset( + 'images/popup_menu.png', + width: 22, + height: 22, + color: Color(0XFF939495), + colorBlendMode: + BlendMode.srcIn, + ), + ), + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(12)), + offset: const Offset(0, 40), + color: Colors.white, + elevation: 4, + onSelected: (value) { + if (value == 'edit') { + openTankerSimpleSheet(context); + } else if (value == + 'disable') { + ScaffoldMessenger.of(context) + .showSnackBar( + const SnackBar( + content: Text( + 'Disable selected')), + ); + } else if (value == + 'delete') { + showDeleteTankerDialog( + context); + } + }, + itemBuilder: (context) => [ + PopupMenuItem( + value: 'edit', + child: Row( + children: [ + Image.asset( + 'images/edit.png', + width: 20, + height: 20, + color: Color( + 0XFF646566), + colorBlendMode: + BlendMode.srcIn, + ), + const SizedBox( + width: 12), + Text( + 'Edit', + style: fontTextStyle( + 14, + const Color( + 0XFF646566), + FontWeight + .w400), + ), + ], ), - const SizedBox(width: 12), - Text( - 'Delete', - style: fontTextStyle(14, const Color(0xFFE2483D), FontWeight.w400), + ), + PopupMenuItem( + value: 'disable', + child: Row( + children: [ + Image.asset( + 'images/disable.png', + width: 20, + height: 20, + color: Color( + 0XFF646566), + colorBlendMode: + BlendMode.srcIn, + ), + const SizedBox( + width: 12), + Text( + 'Disable', + style: fontTextStyle( + 14, + const Color( + 0XFF646566), + FontWeight + .w400), + ), + ], ), - ], - ), + ), + PopupMenuItem( + value: 'delete', + child: Row( + children: [ + Image.asset( + 'images/delete.png', + width: 20, + height: 20, + color: Color( + 0XFFE2483D), + colorBlendMode: + BlendMode.srcIn, + ), + const SizedBox( + width: 12), + Text( + 'Delete', + style: fontTextStyle( + 14, + const Color( + 0xFFE2483D), + FontWeight + .w400), + ), + ], + ), + ), + ], ), ], - ) + ), + const SizedBox(height: 12), + + Row( + children: [ + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: + const Color(0xFFFFFFFF), + foregroundColor: + const Color(0xFF515253), + padding: + const EdgeInsets.symmetric( + vertical: 10), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular( + 24), + side: const BorderSide( + color: + Color(0xFF939495), + width: 0.5), + ), + ), + onPressed: () async { + _showDropdownBottomSheet( + defaultValue: + currentAvailability); + }, + child: Text( + "Change Status", + style: fontTextStyle( + 14, + const Color(0xFF515253), + FontWeight.w500), + ), + )), + SizedBox(width: 8), + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: + const Color(0xFF8270DB), + foregroundColor: + const Color(0xFFFFFFFF), + padding: + const EdgeInsets.symmetric( + vertical: 10), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular( + 24), + side: const BorderSide( + color: + Color(0xFF8270DB), + width: 0.5), + ), + ), + onPressed: () async {}, + child: Text( + "Assign", + style: fontTextStyle( + 14, + const Color(0xFFFFFFFF), + FontWeight.w500), + ), + )), + ], + ), ], ), - const SizedBox(height: 12), + ), - Row( + Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, children: [ - Expanded( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFFFFF), - foregroundColor: const Color(0xFF515253), - padding: const EdgeInsets.symmetric(vertical: 10), - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - side: const BorderSide(color: Color(0xFF939495), width: 0.5), - ), - // Or: side: const BorderSide(color: Color(0xFFC3C4C4), width: 1.2), - ), - onPressed: () async { - _showDropdownBottomSheet(defaultValue: currentAvailability); - }, - child: Text( - "Change Status", - style: fontTextStyle(14, const Color(0xFF515253), FontWeight.w500), - ), - ) + Text( + "RECENT TRIPS", + style: fontTextStyle( + 10, + const Color(0xFF343637), + FontWeight.w600), ), - SizedBox(width: 8), - Expanded( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF8270DB), - foregroundColor: const Color(0xFFFFFFFF), - padding: const EdgeInsets.symmetric(vertical: 10), - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - side: const BorderSide(color: Color(0xFF8270DB), width: 0.5), - ), - // Or: side: const BorderSide(color: Color(0xFFC3C4C4), width: 1.2), - ), - onPressed: () async { - // _showAssignTankerBottomSheet(); - }, - child: Text( - "Assign", - style: fontTextStyle(14, const Color(0xFFFFFFFF), FontWeight.w500), - ), - ) + const SizedBox(height: 12), + + _buildTripCard( + driverName: "Ramesh Krishna", + time: + "7:02 PM, 28 Jun 2025", + from: + "Bachupally Filling Station", + to: "Akriti Heights", + ), + const SizedBox(height: 8), + _buildTripCard( + driverName: "Ramesh Krishna", + time: + "12:44 PM, 26 Jun 2025", + from: + "Bachupally Filling Station", + to: "Akriti Heights", ), ], ), - ], - ), - ), - - Padding(padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "RECENT TRIPS", - style: fontTextStyle(10, const Color(0xFF343637), FontWeight.w600), - ), - const SizedBox(height: 12), - - _buildTripCard( - driverName: "Ramesh Krishna", - time: "7:02 PM, 28 Jun 2025", - from: "Bachupally Filling Station", - to: "Akriti Heights", - ), - const SizedBox(height: 8), - _buildTripCard( - driverName: "Ramesh Krishna", - time: "12:44 PM, 26 Jun 2025", - from: "Bachupally Filling Station", - to: "Akriti Heights", - ), - ], - ), - ), + ), - Expanded( - child: isTankerTripsLoading - ? const Center(child: CircularProgressIndicator()) - : (tankerTripsList.isEmpty - ? Center( - child: Padding( + // ⭐️ FIX — Removed Expanded (illegal inside ScrollView) + Padding( padding: const EdgeInsets.symmetric( - vertical: 12), - child: Text( - 'No Data Available', - style: fontTextStyle( - 12, - const Color(0xFF939495), - FontWeight.w500), - ), - ), - ) - : ListView.separated( - itemCount: tankerTripsList.length, - separatorBuilder: (_, __) => const SizedBox(height: 10), - itemBuilder: (context, idx) { - final it = tankerTripsList[idx]; - return GestureDetector( - onTap: () async{ - /*final result = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TankerDetailsPage(tankerDetails: it), + horizontal: 16), + child: isTankerTripsLoading + ? const Center( + child: + CircularProgressIndicator()) + : tankerTripsList.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( + itemCount: + tankerTripsList + .length, + shrinkWrap: true, // ⭐ Fix + physics: + NeverScrollableScrollPhysics(), // ⭐ Fix + separatorBuilder: + (_, __) => + const SizedBox( + height: + 10), + itemBuilder: + (context, idx) { + final it = + tankerTripsList[ + idx]; + return GestureDetector( + onTap: () async {}, + child: _buildTripCard( + driverName: + it.driver_name, + time: + "7:02 PM, 28 Jun 2025", + from: + "Bachupally Filling Station", + to: + "Akriti Heights", ), ); - if (result == true) { - _fetchTankers(); - }*/ }, - child: _buildTripCard( - driverName: it.driver_name, - time: "7:02 PM, 28 Jun 2025", - from: "Bachupally Filling Station", - to: "Akriti Heights", - ), - ); - }, - )), + ), + ), + ], ), - - ], + ), ), - ), - ), - ) - ); + )); } Widget _buildTripCard({ @@ -1128,17 +1243,19 @@ class _TankerDetailsPageState extends State { borderRadius: BorderRadius.circular(12), ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, children: [ - // Driver + time Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ Row( children: [ const CircleAvatar( radius: 14, - backgroundImage: AssetImage('images/avatar.png'), + backgroundImage: + AssetImage('images/avatar.png'), ), const SizedBox(width: 8), Text( @@ -1160,10 +1277,11 @@ class _TankerDetailsPageState extends State { ], ), const SizedBox(height: 8), - // From location + Row( children: [ - const Icon(Icons.location_on, color: Color(0xFF4F46E5), size: 16), + const Icon(Icons.location_on, + color: Color(0xFF4F46E5), size: 16), const SizedBox(width: 6), Expanded( child: Text( @@ -1178,10 +1296,11 @@ class _TankerDetailsPageState extends State { ], ), const SizedBox(height: 4), - // To location + Row( children: [ - const Icon(Icons.location_on, color: Colors.red, size: 16), + const Icon(Icons.location_on, + color: Colors.red, size: 16), const SizedBox(width: 6), Expanded( child: Text( @@ -1199,10 +1318,8 @@ class _TankerDetailsPageState extends State { ), ); } - } -// ====== Labeled Field Wrapper ====== class _LabeledField extends StatelessWidget { final String label; final Widget child; @@ -1213,19 +1330,25 @@ class _LabeledField extends StatelessWidget { if (input.isEmpty) return input; final i = input.indexOf(RegExp(r'\S')); if (i == -1) return input; - return input.replaceRange(i, i + 1, input[i].toUpperCase()); + return input.replaceRange( + i, i + 1, input[i].toUpperCase()); } @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.only(bottom: 14.0), + padding: + const EdgeInsets.only(bottom: 14.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, children: [ Text( _capFirstWord(label), - style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w600), + style: fontTextStyle( + 12, + const Color(0xFF515253), + FontWeight.w600), ), const SizedBox(height: 6), child, @@ -1234,3 +1357,4 @@ class _LabeledField extends StatelessWidget { ); } } +