diff --git a/lib/common/dashboard.dart b/lib/common/dashboard.dart index 24bcf60..024ce5d 100644 --- a/lib/common/dashboard.dart +++ b/lib/common/dashboard.dart @@ -5,6 +5,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:intl/intl.dart'; import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/financials/financial_main_screen.dart'; import 'package:supplier_new/orders/all_orders.dart'; @@ -765,11 +766,15 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { + int todaysOrdersCount = 0; + int yesterdayPendingOrders = 0; + @override void initState() { super.initState(); _fetchDriverCounts(); _fetchTankerCounts(); + _fetchTodayOrders(); } @@ -841,6 +846,48 @@ class _HomeScreenState extends State { } } + + + Future _fetchTodayOrders() async { + try { + final response = await AppSettings.getAcceptedOrdersFromUsers(); + final data = jsonDecode(response)['data'] as List; + + String todayStr = DateFormat("dd-MMM-yyyy").format(DateTime.now()); + String yesterdayStr = + DateFormat("dd-MMM-yyyy").format(DateTime.now().subtract(Duration(days: 1))); + + int todayCount = 0; + int yesterdayPending = 0; + + for (var order in data) { + String orderDate = order['expectedDateOfDelivery'].toString().trim(); + String status = order['status'].toString().toLowerCase(); + + // today orders + if (orderDate == todayStr) { + todayCount++; + } + + // yesterday but not completed + if (orderDate == yesterdayStr && + status != "delivered" && + status != "completed") { + yesterdayPending++; + } + } + + if (!mounted) return; + + setState(() { + todaysOrdersCount = todayCount; + yesterdayPendingOrders = yesterdayPending; + }); + } catch (e) { + debugPrint("Dashboard orders error: $e"); + } + } + @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -899,8 +946,8 @@ class _HomeScreenState extends State { children: [ DashboardCard( title: "Today's Orders", - value: "12", - subtitle: "+2 from yesterday", + value: "$todaysOrdersCount", + subtitle: "+$yesterdayPendingOrders from yesterday", icon: Icons.shopping_cart_outlined, onTap: () { Navigator.push( diff --git a/lib/common/settings.dart b/lib/common/settings.dart index 676cc14..27924f7 100644 --- a/lib/common/settings.dart +++ b/lib/common/settings.dart @@ -191,6 +191,7 @@ class AppSettings{ static String getSupplierBookingsUrl = host + 'getuserRequestbookingsforplansforsupplier'; static String recurringDateActionUrl = host + 'recurring-booking/date-action'; static String cancelTankerBookingUrl = host + 'update-tank-cancel-status'; + static String rejectPlanRequestUrl = host + 'rejectplans'; static int driverAvailableCount = 0; static int driverOnDeliveryCount = 0; @@ -1496,6 +1497,34 @@ class AppSettings{ } } + static Future> rejectPlan({ + required String planId, + required String reason, + }) async { + + final uri = Uri.parse("$rejectPlanRequestUrl/$planId/reject"); + + final response = await http.put( + uri, + headers: { + ...(await buildRequestHeaders()), + "Content-Type": "application/json", + }, + body: jsonEncode({ + "action": "reject", + "reason": reason, + }), + ); + + print("Reject StatusCode: ${response.statusCode}"); + print("Reject Body: ${response.body}"); + + if (response.statusCode == 200) { + return jsonDecode(response.body); + } else { + throw Exception("Failed API call: ${response.body}"); + } + } /*Apis ends here*/ //save data local diff --git a/lib/orders/all_orders.dart b/lib/orders/all_orders.dart index 52ced1d..57791b8 100644 --- a/lib/orders/all_orders.dart +++ b/lib/orders/all_orders.dart @@ -28,6 +28,12 @@ class _AllOrdersState extends State { final List orders =[]; List ordersList = []; + int todaysOrdersCount = 0; + int boreWaterCount = 0; + int drinkingWaterCount = 0; + + String? selectedFilter; + @override void initState() { super.initState(); @@ -45,6 +51,38 @@ class _AllOrdersState extends State { if (!mounted) return; setState(() { ordersList = data; + + ordersList.sort((a, b) { + try { + DateTime da = DateFormat("dd-MMM-yyyy").parse(a.date); + DateTime db = DateFormat("dd-MMM-yyyy").parse(b.date); + return db.compareTo(da); + } catch (_) { + return 0; + } + }); + + DateTime today = DateTime.now(); + + todaysOrdersCount = data.where((o) { + try { + DateTime d = DateFormat("dd-MMM-yyyy").parse(o.date); + return d.year == today.year && + d.month == today.month && + d.day == today.day; + } catch (_) { + return false; + } + }).length; + + boreWaterCount = data + .where((o) => o.type_of_water.toLowerCase().contains("bore")) + .length; + + drinkingWaterCount = data + .where((o) => o.type_of_water.toLowerCase().contains("drinking")) + .length; + isLoading = false; }); } catch (e) { @@ -53,6 +91,42 @@ class _AllOrdersState extends State { } } + void sortOrders(String type) { + setState(() { + selectedFilter = type; + + if (type == "Building") { + ordersList.sort((a, b) => + a.building_name.toLowerCase().compareTo(b.building_name.toLowerCase())); + } + + if (type == "Status") { + ordersList.sort((a, b) => + a.status.toLowerCase().compareTo(b.status.toLowerCase())); + } + + if (type == "Date") { + ordersList.sort((a, b) { + try { + DateTime da = DateFormat("dd-MMM-yyyy").parse(a.date); + DateTime db = DateFormat("dd-MMM-yyyy").parse(b.date); + + // newest first, oldest last + return db.compareTo(da); + } catch (_) { + return 0; + } + }); + } + + if (type == "Amount") { + ordersList.sort((a, b) => + double.parse(b.quoted_amount.toString()) + .compareTo(double.parse(a.quoted_amount.toString()))); + } + }); + } + @override @@ -105,7 +179,7 @@ class _AllOrdersState extends State { Column( children: [ Text( - "12", + "$todaysOrdersCount", style:fontTextStyle(64, Color(0XFFFF2D2E30), FontWeight.w700), ), Text( @@ -124,7 +198,7 @@ class _AllOrdersState extends State { height: 40, width: 40, ), - value: "16", + value: "$boreWaterCount", label: "Bore Water", ), OrderCategoryCard( @@ -134,7 +208,7 @@ class _AllOrdersState extends State { width: 40, fit: BoxFit.contain, ), - value: "08", + value: "$drinkingWaterCount", label: "Drinking Water", ), ], @@ -177,13 +251,13 @@ class _AllOrdersState extends State { padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ - FilterChipWidget(label: "Building"), + FilterChipWidget(label: "Building", onTap: () => sortOrders("Building")), const SizedBox(width: 8), - FilterChipWidget(label: "Status"), + FilterChipWidget(label: "Status", onTap: () => sortOrders("Status")), const SizedBox(width: 8), - FilterChipWidget(label: "Date"), + FilterChipWidget(label: "Date", onTap: () => sortOrders("Date")), const SizedBox(width: 8), - FilterChipWidget(label: "Amount"), + FilterChipWidget(label: "Amount", onTap: () => sortOrders("Amount")), ], ), ), @@ -265,14 +339,22 @@ class OrderCategoryCard extends StatelessWidget { /// Filter Chip class FilterChipWidget extends StatelessWidget { final String label; - const FilterChipWidget({super.key, required this.label}); + final VoidCallback? onTap; + + const FilterChipWidget({ + super.key, + required this.label, + this.onTap, + }); @override Widget build(BuildContext context) { return ChoiceChip( label: Text(label), selected: false, - onSelected: (_) {}, + onSelected: (_) { + if (onTap != null) onTap!(); + }, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), @@ -289,76 +371,88 @@ class OrderCard extends StatelessWidget { const OrderCard({super.key, required this.order, this.onRefresh}); Color _getStatusColor() { - String st=''; + String st = order.status.toLowerCase(); - if(order.status.toLowerCase()=='advance_paid'){ - st='pending'; - } - else if(order.status.toLowerCase()=='accepted'){ // ⭐ ADDED - st='pending'; - } - else if(order.status.toLowerCase()=='deliveryboy_assigned'){ - st='assigned'; - } - else if(order.status.toLowerCase()=='tanker_assigned'){ - st='assigned'; + if (st == 'advance_paid' || st == 'accepted') { + st = 'pending'; } - else if(order.status.toLowerCase()=='delivered'){ - st='completed'; + else if (st == 'deliveryboy_assigned' || st == 'tanker_assigned') { + st = 'assigned'; } - else{ - st=order.status.toLowerCase(); + else if (st == 'delivered') { + st = 'completed'; } - switch (st.toLowerCase()) { + switch (st) { case "completed": return Color(0XFFC4E8C3); + case "in_progress": return Color(0XFFC9DFFE); + case "cancelled": return Color(0XFFFCEDEC); + case "assigned": return Color(0XFFF9DBC6); + + case "pickup_started": + case "start_loading": + case "loading_completed": + case "out_for_delivery": + case "arrived": + case "unloading_started": + case "unloading_stopped": + case "payment_pending": + return Color(0XFFF9DBC6); + case "pending": return Color(0XFFFDF3D3); + default: return Colors.grey; } } Color _getTextStatusColor() { - String st=''; + String st = order.status.toLowerCase(); - if(order.status.toLowerCase()=='advance_paid'){ - st='pending'; + if (st == 'advance_paid' || st == 'accepted') { + st = 'pending'; } - else if(order.status.toLowerCase()=='accepted'){ // ⭐ ADDED - st='pending'; + else if (st == 'deliveryboy_assigned' || st == 'tanker_assigned') { + st = 'assigned'; } - else if(order.status.toLowerCase()=='deliveryboy_assigned'){ - st='assigned'; - } - else if(order.status.toLowerCase()=='delivered'){ - st='completed'; - } - else if(order.status.toLowerCase()=='tanker_assigned'){ - st='assigned'; - } - else{ - st=order.status.toLowerCase(); + else if (st == 'delivered') { + st = 'completed'; } - switch (st.toLowerCase()) { + switch (st) { case "completed": return Color(0XFF0A9E04); + case "in_progress": return Color(0XFF1D7AFC); + case "cancelled": return Color(0XFFE2483D); + case "assigned": return Color(0XFFE56910); + + case "pickup_started": + case "start_loading": + case "loading_completed": + case "out_for_delivery": + case "arrived": + case "unloading_started": + case "unloading_stopped": + case "payment_pending": + return Color(0XFFE56910); + case "pending": return Color(0XFFD0AE3C); + default: return Colors.grey; } @@ -366,20 +460,47 @@ class OrderCard extends StatelessWidget { @override Widget build(BuildContext context) { + + final statusColor = _getStatusColor(); final textStatusColor = _getTextStatusColor(); - String st = (order.status == 'advance_paid') + String s = order.status.toString().toLowerCase(); + + String st = (s == 'advance_paid') ? 'pending' - : (order.status.toLowerCase() == 'accepted') // ⭐ ADDED + : (s == 'accepted') ? 'pending' - : (order.status.toLowerCase() == 'delivered') // ⭐ ADDED + : (s == 'delivered') ? 'completed' - : (order.status.toString().toLowerCase() == 'deliveryboy_assigned') + : (s == 'deliveryboy_assigned') ? 'assigned' - : (order.status.toString().toLowerCase() == 'tanker_assigned') + : (s == 'tanker_assigned') ? 'assigned' - : order.status.toString().toLowerCase(); + : (s == 'pickup_started' || + s == 'start_loading' || + s == 'loading_completed' || + s == 'out_for_delivery' || + s == 'arrived' || + s == 'unloading_started' || + s == 'unloading_stopped' || + s == 'payment_pending') + ? s + : s; + + bool isTodayOrder = false; + + try { + DateTime orderDate = DateFormat("dd-MMM-yyyy").parse(order.date); + DateTime now = DateTime.now(); + + DateTime today = DateTime(now.year, now.month, now.day); + DateTime orderOnly = DateTime(orderDate.year, orderDate.month, orderDate.day); + + if (orderOnly == today) { + isTodayOrder = true; + } + } catch (_) {} return Padding( padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), @@ -469,7 +590,8 @@ class OrderCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( - onTap: () async { + onTap: isTodayOrder + ? () async { final result = await Navigator.push( context, MaterialPageRoute( @@ -479,21 +601,25 @@ class OrderCard extends StatelessWidget { if (result == true) { onRefresh?.call(); } - }, + } + : null, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(22), - border: Border.all(color: const Color(0XFF939495)), + border: Border.all( + color: isTodayOrder ? const Color(0XFF939495) : Colors.grey, + ), ), - child: const Padding( + child: Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), - child: Text( - "Assign", - style: TextStyle( + child: Text( + "Assign", + style: TextStyle( fontSize: 14, - color: Color(0XFF515253), - fontWeight: FontWeight.w400), - ), + color: isTodayOrder ? const Color(0XFF515253) : Colors.grey, + fontWeight: FontWeight.w400, + ), + ), ), ), ), diff --git a/lib/orders/order_requests.dart b/lib/orders/order_requests.dart index 78fe02b..90a3ac8 100644 --- a/lib/orders/order_requests.dart +++ b/lib/orders/order_requests.dart @@ -80,6 +80,7 @@ class _OrderRequestsPageState extends State { // ✅ Statuses that ignore time if (dbLower == "reject") return {"status": "Rejected", "color": const Color(0XFFE2483D)}; + if (dbLower == "rejected_by_user") return {"status": "Rejected By User", "color": const Color(0XFFE2483D)}; if (dbLower == "accept") 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") { @@ -162,7 +163,7 @@ class _OrderRequestsPageState extends State { price: "₹${AppSettings.formDouble(order.quoted_amount) ?? ''}", ); - final noNavigateStatuses = ["expired", "rejected", "accepted", "advance_paid", "cancelled"]; + final noNavigateStatuses = ["expired", "rejected", "accepted", "advance_paid", "cancelled","rejected by user"]; final disableNavigation = noNavigateStatuses.contains(status.toLowerCase()); final card = OrderCard(order: cardModel); diff --git a/lib/orders/orders_model.dart b/lib/orders/orders_model.dart index fe52b10..a554750 100644 --- a/lib/orders/orders_model.dart +++ b/lib/orders/orders_model.dart @@ -37,7 +37,7 @@ class OrdersModel { rtvm.capacity = json['capacity'] ?? ''; rtvm.quantity = json['quantity']?? ''; rtvm.time = json['time'] ?? ''; - rtvm.date = json['dateOfOrder'] ?? ''; + rtvm.date = json['expectedDateOfDelivery'] ?? ''; rtvm.status = json['orderStatus'] ?? ''; rtvm.quoted_amount = json['price'].toString() ?? ''; rtvm.lng=json['longitude'] ?? 0.0; diff --git a/lib/plans/accept_plan_requests.dart b/lib/plans/accept_plan_requests.dart index 57cca85..4e84b7a 100644 --- a/lib/plans/accept_plan_requests.dart +++ b/lib/plans/accept_plan_requests.dart @@ -599,6 +599,8 @@ class _AcceptPlanRequestsState extends State { AppSettings.longFailedToast("Please Check internet"); }*/ + + showRejectBottomSheet(context); }, child: Row( @@ -972,7 +974,36 @@ class _AcceptPlanRequestsState extends State { child: ElevatedButton( onPressed: selectedReason == null ? null - : () => Navigator.pop(context, selectedReason), + : () async { + + try { + + final response = await AppSettings.rejectPlan( + planId: widget.order.dbId, + reason: selectedReason!, + ); + + print("API Response: $response"); + + if (!context.mounted) return; + + Navigator.pop(context); // close bottom sheet + Navigator.pop(context,true); + + AppSettings.longSuccessToast( + response["message"] ?? "Plan rejected successfully"); + + } catch (e) { + + print("Reject Error: $e"); + + if (!context.mounted) return; + + AppSettings.longFailedToast("Failed to reject plan"); + + } + + }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFE2483D), disabledBackgroundColor: Color(0xFFE2483D), diff --git a/lib/plans/all_plans.dart b/lib/plans/all_plans.dart index 3d39ff9..0b1230e 100644 --- a/lib/plans/all_plans.dart +++ b/lib/plans/all_plans.dart @@ -16,7 +16,7 @@ class PlansModel { final String price; final String advance; final String deliveries; - final String frequency; + final String frequencyDisplay; final String waterType; PlansModel({ @@ -27,7 +27,7 @@ class PlansModel { required this.price, required this.advance, required this.deliveries, - required this.frequency, + required this.frequencyDisplay, required this.waterType, }); @@ -35,18 +35,40 @@ class PlansModel { final supplier = json["my_supplier"] ?? {}; final List dates = json["dates"] ?? []; + double price = + double.tryParse((supplier["quoted_amount"] ?? "0").toString()) ?? 0; + + double advancePaid = + double.tryParse((json["advance_paid"] ?? "0").toString()) ?? 0; + + double balance = price - advancePaid; + + String freq = (json["frequency"] ?? "").toString().toLowerCase(); + + String frequencyDisplay = "0"; + + if (freq == "daily") { + frequencyDisplay = "7"; + } else if (freq.contains("once")) { + frequencyDisplay = "1"; + } else if (freq.contains("twice")) { + frequencyDisplay = "2"; + } else if (freq.contains("thrice")) { + frequencyDisplay = "3"; + } + return PlansModel( - id: json["_id"], + id: json["_id"]?.toString() ?? "", status: ["payment_completed", "processed", "accepted"] - .contains(json["status"].toString().toLowerCase()) + .contains((json["status"] ?? "").toString().toLowerCase()) ? "Active" : "Pending", - apartment: json["customerId"], + apartment: json["customerId"]?.toString() ?? "", liters: "${json["capacity"]} - ${json["type_of_water"]}", - price: "₹${supplier["quoted_amount"] ?? "--"}", - advance: "--", + price: "₹${price.toStringAsFixed(0)}", + advance: "₹${balance.toStringAsFixed(0)}", deliveries: "${dates.length} Deliveries", - frequency: "${json["weekly_count"]}/week", + frequencyDisplay: frequencyDisplay, waterType: json["type_of_water"] ?? "", ); } @@ -316,7 +338,12 @@ class PlansCard extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (_) => PlanDetails(plan: planJson), + builder: (_) => PlanDetails( + plan: { + ...planJson, + "frequencyDisplay": delivery.frequencyDisplay, + }, + ), ), ); }, @@ -370,73 +397,6 @@ class PlansCard extends StatelessWidget { style: const TextStyle(fontSize: 12)), ], ), - Visibility( - visible: delivery.status=='payment_completed', - child: Row( - children: [ - GestureDetector( - onTap: (){ - - }, - child: - ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.transparent, - BlendMode.multiply), - child: Image - .asset( - 'images/wrong_button.png', - width: - 44, - height: - 44, - ), - ), - ), - SizedBox( - width: MediaQuery.of(context) - .size - .width * - .012, - ), - GestureDetector( - onTap: () async { - final confirmed = await showAcceptConfirmDialog(context); - if (!confirmed) return; - - try { - final res = await AppSettings.respondRecurringBooking( - bookingId: planJson["_id"], - supplierId: planJson["my_supplier"]["supplierId"], - action: "accept", - ); - - final List dates = res["data"]["dates"] ?? []; - - if (dates.isEmpty) return; - - /* Navigator.push( - context, - MaterialPageRoute( - builder: (_) => PlanCalendarScreen(dates: dates), - ), - );*/ - } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("Failed to accept plan")), - ); - } - }, - child: Image.asset( - 'images/right_button.png', - width: 44, - height: 44, - ), - ), - - - ], - ),), const SizedBox(height: 12), @@ -451,7 +411,7 @@ class PlansCard extends StatelessWidget { children: [ Text(delivery.deliveries, style: const TextStyle(fontSize: 13)), - Text(delivery.frequency, + Text("${delivery.frequencyDisplay}/week", style: const TextStyle( fontSize: 13, color: Color(0xFF7B5AF4))), ], diff --git a/lib/plans/plan_details.dart b/lib/plans/plan_details.dart index 8a00db9..fdfb90f 100644 --- a/lib/plans/plan_details.dart +++ b/lib/plans/plan_details.dart @@ -83,7 +83,7 @@ class _PlanDetailsState extends State { statusBg = Colors.orange.withOpacity(0.15); statusText = Colors.orange; buttonText = "Assign Tanker"; - showButton = true; + showButton = false; } return Container( @@ -268,8 +268,7 @@ class _PlanDetailsState extends State { const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ - _buildInfoCard( - "${plan["weekly_count"]}/week", "Schedule"), + _buildInfoCard("${plan["frequencyDisplay"] ?? "0"}/week", "Schedule"), const SizedBox(width: 12), _buildInfoCard("$pendingCount", "Pending"), const SizedBox(width: 12), diff --git a/lib/plans/plan_requests.dart b/lib/plans/plan_requests.dart index ef41eea..0244cc9 100644 --- a/lib/plans/plan_requests.dart +++ b/lib/plans/plan_requests.dart @@ -80,7 +80,8 @@ class _PlanRequestsPageState extends State { final dbLower = (dbStatus ?? "").toLowerCase().trim(); // ✅ Statuses that ignore time - if (dbLower == "reject") { + if (dbLower == "rejected"|| + dbLower == "rejected_by_user") { return {"status": "Rejected", "color": const Color(0XFFE2483D)}; }