import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.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'; 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() { switch (order.status.toLowerCase()) { case "completed": return Color(0XFFC4E8C3); case "in-progress": return Color(0XFFE8F2FF); case "cancelled": return Color(0XFFFCEDEC); case "assigned": return Color(0XFFF9DBC6); case "pending": return Color(0XFFFDF3D3); case "advance_paid": return Color(0XFFFDF3D3); default: return Colors.grey; } } Color _getTextStatusColor() { switch (order.status.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); case "advance_paid": return Color(0XFFD0AE3C); default: return Colors.grey; } } @override Widget build(BuildContext context) { final statusColor = _getStatusColor(); final textStatusColor = _getTextStatusColor(); return Padding(padding: 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), ) ], ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Image ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), bottomLeft: Radius.circular(0), ), child: order.imageAsset != '' ? Image.asset( order.imageAsset, height: 145, width: 145, fit: BoxFit.cover, ) : Image.network( order.imageAsset, height: 100, width: 100, fit: BoxFit.cover, ), ), // Right side 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( order.status, style: fontTextStyle(10,textStatusColor,FontWeight.w400) ), ), const SizedBox(height: 6), Text( order.building_name, style:fontTextStyle(16,Color(0XFF2D2E30),FontWeight.w600) ), Text( order.displayAddress, style: fontTextStyle(12,Color(0XFF646566),FontWeight.w400) ), const SizedBox(height: 4), Text( order.capacity+' - '+order.type_of_water, style: fontTextStyle(14,Color(0XFF444444),FontWeight.w500) ), Text( order.time+' , '+order.date, style:fontTextStyle(8,Color(0XFF646566),FontWeight.w400) ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Visibility( visible: order.status.toLowerCase().toString()=='advance_paid', child: GestureDetector( onTap: ()async{ final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => AssignDriverScreen(order: order), ), ); // If result indicates API reload if (result == true) { onRefresh?.call(); // 👈 safe call to refresh parent } }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), border: Border.all(color: const Color(0XFF939495)), ), child: Padding( padding: EdgeInsets.fromLTRB(8,4,8,4), child: Text( "Assign", style: fontTextStyle( 14, const Color(0XFF515253), FontWeight.w400), ), ) ), ),), Visibility( visible: order.status.toLowerCase().toString()=='advance_paid', child: GestureDetector( onTap: ()async{ final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => CancelOrderScreen(order: order), ), ); // If result indicates API reload if (result == true) { onRefresh?.call(); // 👈 safe call to refresh parent } }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), border: Border.all(color: const Color(0XFFE2483D)), color: Color(0XFFE2483D) ), child: Padding( padding: EdgeInsets.fromLTRB(8,4,8,4), child: Text( "Cancel", style: fontTextStyle( 14, const Color(0XFFFFFFFF), FontWeight.w400), ), ) ), ),), ], ) /*Text( order.extraInfo, style:fontTextStyle(12, order.status == "in-progress" ? Color(0XFF1D7AFC) : Color(0XFF646566),FontWeight.w400) ),*/ ], ), ), ), ], ), ),); } }