import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/orders/delivery_updates.dart'; import 'package:supplier_new/orders/order_requests.dart'; import 'package:supplier_new/orders/orders_model.dart'; import 'package:supplier_new/orders/search_order_appbar.dart'; import 'package:intl/intl.dart'; import 'assign_driver.dart'; import 'cancel_order.dart'; import 'change_driver.dart'; class AllOrders extends StatefulWidget { final String navigationFrom; AllOrders({ super.key, required this.navigationFrom, }); @override State createState() => _AllOrdersState(); } class _AllOrdersState extends State { final TextEditingController searchController = TextEditingController(); bool isLoading=false; final List orders =[]; List ordersList = []; @override void initState() { // TODO: implement initState super.initState(); _fetchOrders(); } Future _fetchOrders() async { setState(() => isLoading = true); try { final response = await AppSettings.getAcceptedOrdersFromUsers(); final data = (jsonDecode(response)['data'] as List) .map((e) => OrdersModel.fromJson(e)) .toList(); if (!mounted) return; setState(() { ordersList = data; isLoading = false; }); } catch (e) { debugPrint("⚠️ Error fetching orders: $e"); setState(() => isLoading = false); } } @override Widget build(BuildContext context) { // ✅ Group orders by date final Map> groupedOrders = {}; String formatOrderDate(String? dateStr) { if (dateStr == null || dateStr.trim().isEmpty) { return ""; // or return a fallback like "N/A" } try { final inputFormat = DateFormat("dd-MMM-yyyy"); // matches 10-Sep-2025 final outputFormat = DateFormat("dd MMM yyyy"); // output 10 Sep 2025 final parsedDate = inputFormat.parse(dateStr); return outputFormat.format(parsedDate); } catch (e) { print("Date parse error: $e"); return dateStr; // fallback to original string } } for (var order in ordersList) { final formattedDate = formatOrderDate(order.date); // "10 Sep 2025" groupedOrders.putIfAbsent(formattedDate, () => []).add(order); } return Scaffold( backgroundColor: Color(0XFFF2F2F2), appBar: widget.navigationFrom.toString().toLowerCase()=='dashboard'? SearchOrderAppBar( controller: searchController, onBack: () => Navigator.pop(context), onHelp: () { // Show help dialog or navigate print("Help tapped"); }, ):null, body: isLoading ? const Center(child: CircularProgressIndicator()) : ordersList.isEmpty?Center( child: Text( 'No Data Available', style: fontTextStyle(16,Color(0XFF000000),FontWeight.w700), ), ):SingleChildScrollView( child: Padding( padding: EdgeInsets.all(16), child: Column( children: [ SizedBox(height: MediaQuery.of(context).size.height * .042), /// Total Orders Column( children: [ Text( "12", style:fontTextStyle(64, Color(0XFFFF2D2E30), FontWeight.w700), ), Text( "Today's Total Orders", style: fontTextStyle(24, Color(0XFFFF2D2E30), FontWeight.w600), ), SizedBox(height: MediaQuery.of(context).size.height * .042), /// Bore Water + Drinking Water Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ OrderCategoryCard( image: Image.asset( 'images/bore-water.png', fit: BoxFit.contain, height: 40, width: 40, ), value: "16", label: "Bore Water", ), OrderCategoryCard( image: Image.asset( 'images/drinking-water.png', height: 40, width: 40, fit: BoxFit.contain, ), value: "08", label: "Drinking Water", ), ], ), SizedBox(height: MediaQuery.of(context).size.height * .024), /// Button Container( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor:Color(0XFF8270DB), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 16), ), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => OrderRequestsPage()), ); }, child: Text( "View Order Requests", style: fontTextStyle(16, Color(0XFFFFFFFFFF), FontWeight.w500), ), ), ) ], ), const SizedBox(height: 20), /// Filters Row SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ FilterChipWidget(label: "Building"), const SizedBox(width: 8), FilterChipWidget(label: "Status"), const SizedBox(width: 8), FilterChipWidget(label: "Date"), const SizedBox(width: 8), FilterChipWidget(label: "Amount"), ], ), ), const SizedBox(height: 20), /// Order Card Example /// Order List ListView( padding: const EdgeInsets.all(12), shrinkWrap: true, // ✅ Important physics: NeverScrollableScrollPhysics(), // ✅ Prevent nested scrolling children: groupedOrders.entries.map((entry) { final date = entry.key; final ordersForDate = entry.value; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Date heading Padding( padding: const EdgeInsets.all(0), child: Text( date, style:fontTextStyle(14, Color(0XFF343637), FontWeight.w600), ), ), // Orders list for this date ...ordersForDate.map((order) => OrderCard( order: order, onRefresh: _fetchOrders, // 👈 pass parent function here )), const SizedBox(height: 12), ], ); }).toList(), ), ], ), ) ), ); } } /// Category Card (Bore Water, Drinking Water) class OrderCategoryCard extends StatelessWidget { final Image image; final String value; final String label; const OrderCategoryCard({ super.key, required this.image, required this.value, required this.label, }); @override Widget build(BuildContext context) { return Column( children: [ SizedBox( width: 40, height: 40, child: image, // ✅ Replaced Icon with Image ), SizedBox(height: MediaQuery.of(context).size.height * .008), Text( value, style: fontTextStyle(20, Color(0XFFFF515253), FontWeight.w700), ), SizedBox(height: MediaQuery.of(context).size.height * .008), Text(label, style: fontTextStyle(16, Color(0XFFFF515253), FontWeight.w400),), ], ); } } /// Filter Chip class FilterChipWidget extends StatelessWidget { final String label; const FilterChipWidget({super.key, required this.label}); @override Widget build(BuildContext context) { return ChoiceChip( label: Text(label), selected: false, onSelected: (_) {}, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), backgroundColor: Colors.white, side: BorderSide(color: Colors.grey.shade300), ); } } class OrderCard extends StatelessWidget { final OrdersModel order; final VoidCallback? onRefresh; const OrderCard({super.key, required this.order, this.onRefresh}); Color _getStatusColor() { String st=''; if(order.status.toLowerCase()=='advance_paid'){ st='pending'; } else if(order.status.toLowerCase()=='deliveryboy_assigned'){ st='assigned'; } else if(order.status.toLowerCase()=='tanker_assigned'){ st='assigned'; } else{ st=order.status.toLowerCase(); } switch (st.toLowerCase()) { case "completed": return Color(0XFFC4E8C3); case "in_progress": return Color(0XFFC9DFFE); case "cancelled": return Color(0XFFFCEDEC); case "assigned": return Color(0XFFF9DBC6); case "pending": return Color(0XFFFDF3D3); default: return Colors.grey; } } Color _getTextStatusColor() { String st=''; if(order.status.toLowerCase()=='advance_paid'){ st='pending'; } else if(order.status.toLowerCase()=='deliveryboy_assigned'){ st='assigned'; } else if(order.status.toLowerCase()=='tanker_assigned'){ st='assigned'; } else{ st=order.status.toLowerCase(); } switch (st.toLowerCase()) { case "completed": return Color(0XFF0A9E04); case "in_progress": return Color(0XFF1D7AFC); case "cancelled": return Color(0XFFE2483D); case "assigned": return Color(0XFFE56910); case "pending": return Color(0XFFD0AE3C); default: return Colors.grey; } } @override Widget build(BuildContext context) { final statusColor = _getStatusColor(); final textStatusColor = _getTextStatusColor(); String st = (order.status == 'advance_paid') ? 'pending' : (order.status.toString().toLowerCase() == 'deliveryboy_assigned') ? 'assigned' : (order.status.toString().toLowerCase() == 'tanker_assigned') ? 'assigned' : order.status.toString().toLowerCase(); return Padding( padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), child: Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 5, offset: const Offset(0, 3), ) ], ), /// 👇 IntrinsicHeight allows both sides of the row to match height dynamically child: IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, // 👈 image stretches children: [ /// 🖼 Left Image ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), bottomLeft: Radius.circular(12), ), child: SizedBox( width: 145, // fixed width child: order.imageAsset.isNotEmpty ? Image.asset( order.imageAsset, fit: BoxFit.cover, // 👈 fills height ) : Image.network( order.imageAsset, fit: BoxFit.cover, ), ), ), /// 📄 Right Content Expanded( child: Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Status chip Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(4), ), child: Text( st, style: fontTextStyle(10, textStatusColor, FontWeight.w400), ), ), const SizedBox(height: 6), Text( order.building_name, style: fontTextStyle(16, const Color(0XFF2D2E30), FontWeight.w600), ), Text( order.displayAddress, style: fontTextStyle(12, const Color(0XFF646566), FontWeight.w400), ), const SizedBox(height: 4), Text( '${order.capacity} - ${order.type_of_water}', style: fontTextStyle(14, const Color(0XFF444444), FontWeight.w500), ), Text( '${order.time} , ${order.date}', style: fontTextStyle(8, const Color(0XFF646566), FontWeight.w400), ), const SizedBox(height: 12), /// =================== /// 🟡 ASSIGN & CANCEL BUTTONS /// =================== Visibility( visible: order.status.toLowerCase() == 'advance_paid', child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => AssignDriverScreen(order: order), ), ); if (result == true) { onRefresh?.call(); } }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), border: Border.all(color: const Color(0XFF939495)), ), child: const Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), child: Text( "Assign", style: TextStyle( fontSize: 14, color: Color(0XFF515253), fontWeight: FontWeight.w400), ), ), ), ), GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DeliveryUpdatesPage( orderId: order.dbId, initialStatus: order.status, ), ), ); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), border: Border.all(color: const Color(0XFFE2483D)), color: const Color(0XFFE2483D), ), child: const Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), child: Text( "Cancel", style: TextStyle( fontSize: 14, color: Colors.white, fontWeight: FontWeight.w400), ), ), ), ), ], ), ), /// =================== /// 🟣 TRACK DELIVERY BUTTON /// =================== Visibility( visible: order.status.toLowerCase() == 'in_progress', child: GestureDetector( onTap: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => AssignDriverScreen(order: order), ), ); if (result == true) { onRefresh?.call(); } }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), color: const Color(0XFF8270DB), border: Border.all(color: const Color(0XFF8270DB)), ), child: const Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), child: Text( "Track Delivery", style: TextStyle( fontSize: 14, color: Colors.white, fontWeight: FontWeight.w400), ), ), ), ), ), Visibility( visible: st.toLowerCase() == 'assigned', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( 'images/avatar.png', fit: BoxFit.cover, width: 12, height: 12, ), const SizedBox(width: 8), // Title + Chips Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( order.delivery_agent_name!=''?"Assigned to ${order.delivery_agent_name}":"Assigned to ${order.tanker_name}", maxLines: 1, overflow: TextOverflow.ellipsis, style: fontTextStyle( 8, const Color(0xFF646566), FontWeight.w400), ), ), ], ), ], ), ), ], ), SizedBox(height: MediaQuery.of(context).size.height * .004), GestureDetector( onTap: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => ChangeDriverScreen(order: order), ), ); if (result == true) { onRefresh?.call(); } }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), color: const Color(0XFF8270DB), border: Border.all(color: const Color(0XFF8270DB)), ), child: const Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), child: Text( "Change", style: TextStyle( fontSize: 14, color: Colors.white, fontWeight: FontWeight.w400), ), ), ), ), ], ) ), Visibility( visible: st.toLowerCase() == 'completed', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( 'images/avatar.png', fit: BoxFit.cover, width: 12, height: 12, ), const SizedBox(width: 8), // Title + Chips Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( order.delivery_agent_name!=''?"Delivered by ${order.delivery_agent_name}":"Assigned to ${order.tanker_name}", maxLines: 1, overflow: TextOverflow.ellipsis, style: fontTextStyle( 8, const Color(0xFF646566), FontWeight.w400), ), ), ], ), ], ), ), ], ), ], ) ), ], ), ), ), ], ), ), ), ); } }