import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:table_calendar/table_calendar.dart'; import '../common/settings.dart'; class SupplyCalendarScreen extends StatefulWidget { @override State createState() => _SupplyCalendarScreenState(); } class _SupplyCalendarScreenState extends State { late DateTime _focusedDay; late DateTime _firstDay; late DateTime _lastDay; Map>> calendarEvents = {}; DateTime? _selectedDay; bool isLoading = true; @override void initState() { super.initState(); final now = DateTime.now(); _focusedDay = now; _firstDay = DateTime(2025, 1, 1); _lastDay = DateTime(now.year, now.month + 6, 0); fetchOrdersFromApi(); } // =========================================================================== // FETCH API → BUILD TWO EVENTS (ORIGINAL + RESCHEDULED) // =========================================================================== Future fetchOrdersFromApi() async { try { final response = await AppSettings.getAcceptedOrdersFromUsers(); final decoded = jsonDecode(response); if (decoded == null || decoded['data'] == null) { setState(() => isLoading = false); return; } final List orders = decoded['data']; calendarEvents.clear(); for (var order in orders) { String? originalDate = order["date"]; String? newDate = order["reScheduleDateOfDelivery"]; String? resStatus = order["rescheduleOrderStatus"]; bool isRescheduled = newDate != null && newDate.isNotEmpty && resStatus != null && resStatus.isNotEmpty; // ===================== ORIGINAL DATE EVENT ===================== if (originalDate != null && order["orderStatus"] != "cancelled") { try { DateTime d = DateTime.parse(originalDate); DateTime key = DateTime(d.year, d.month, d.day); calendarEvents.putIfAbsent(key, () => []); calendarEvents[key]!.add({ "status": isRescheduled ? "rescheduled_from" : "delivery", "_id": order["_id"], "supplierName": order["supplierName"] ?? "Supplier", "capacity": order["capacity"] ?? "", "time": order["time"] ?? "", "originalDate": originalDate, "newDate": newDate, }); } catch (e) {} } // ===================== NEW RESCHEDULED DATE EVENT ===================== if (isRescheduled) { try { DateTime d2 = DateTime.parse(newDate); DateTime key2 = DateTime(d2.year, d2.month, d2.day); calendarEvents.putIfAbsent(key2, () => []); calendarEvents[key2]!.add({ "status": "rescheduled_to", "_id": order["_id"], "supplierName": order["supplierName"] ?? "Supplier", "capacity": order["capacity"] ?? "", "time": order["time"] ?? "", "originalDate": originalDate, "newDate": newDate, }); } catch (e) {} } // ===================== CANCELLED EVENT ===================== if (order["orderStatus"] == "cancelled") { try { DateTime d = DateTime.parse(originalDate!); DateTime key = DateTime(d.year, d.month, d.day); calendarEvents.putIfAbsent(key, () => []); calendarEvents[key]!.add({ "status": "cancelled", "_id": order["_id"], "supplierName": order["supplierName"] ?? "Supplier", "capacity": order["capacity"] ?? "", "time": order["time"] ?? "", }); } catch (e) {} } } setState(() => isLoading = false); } catch (e) { setState(() => isLoading = false); } } // =========================================================================== // CANCEL ORDER API // =========================================================================== Future cancelDelivery(String id) async { /* try { await AppSettings.cancelPlanOrder(id); // your endpoint await fetchOrdersFromApi(); ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Order cancelled successfully"))); } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Cancel failed"))); }*/ } void _confirmCancel(String orderId) { showDialog( context: context, builder: (_) => AlertDialog( title: Text("Cancel Delivery"), content: Text("Are you sure you want to cancel this delivery?"), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text("No")), TextButton( onPressed: () { Navigator.pop(context); cancelDelivery(orderId); }, child: Text("Yes, Cancel", style: TextStyle(color: Colors.red))), ], ), ); } // =========================================================================== // HELPER FUNCTIONS // =========================================================================== String formatShort(String date) { try { final d = DateTime.parse(date); return "${d.day} ${monthShort[d.month - 1]}"; } catch (e) { return date; } } List monthShort = [ "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec" ]; Widget _buildStatusIcon(String status) { if (status == "rescheduled_from") { return Icon(Icons.subdirectory_arrow_left, color: Colors.orange); } if (status == "rescheduled_to") { return Icon(Icons.subdirectory_arrow_right, color: Colors.deepOrange); } if (status == "cancelled") { return Icon(Icons.cancel, color: Colors.red); } return Icon(Icons.local_shipping, color: Colors.blue); } String _buildStatusText(Map d) { String status = d["status"]; String? originalDate = d["originalDate"]; String? newDate = d["newDate"]; if (status == "rescheduled_from") { return "Rescheduled from this date → ${formatShort(newDate!)}"; } if (status == "rescheduled_to") { return "Rescheduled to this date (from ${formatShort(originalDate!)})"; } if (status == "cancelled") { return "Cancelled"; } return status; } // =========================================================================== // OPEN RESCHEDULE CALENDAR // =========================================================================== Future openRescheduleCalendar(Map delivery) async { DateTime now = DateTime.now(); final DateTime? pickedDate = await showDatePicker( context: context, initialDate: now.add(Duration(days: 1)), firstDate: now.add(Duration(days: 1)), lastDate: DateTime(now.year + 1, 12, 31), ); if (pickedDate == null) return; String formatted = "${pickedDate.year}-${pickedDate.month.toString().padLeft(2,'0')}-${pickedDate.day.toString().padLeft(2,'0')}"; await sendRescheduleToServer(delivery["_id"], formatted); } Future sendRescheduleToServer(String id, String newDate) async { /*try { final payload = {"reScheduleDateOfDelivery": newDate}; await AppSettings.rescheduleOrder(id, payload); await fetchOrdersFromApi(); ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Delivery rescheduled to $newDate"))); } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Reschedule failed"))); }*/ } // =========================================================================== // SHOW DELIVERY LIST // =========================================================================== void showDeliveryList(DateTime date) { final key = DateTime(date.year, date.month, date.day); final events = calendarEvents[key]; if (events == null || events.isEmpty) return; bool isPast = date.isBefore(DateTime( DateTime.now().year, DateTime.now().month, DateTime.now().day)); showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) { final list = events.toList(); return DraggableScrollableSheet( initialChildSize: 0.9, maxChildSize: 0.9, minChildSize: 0.4, builder: (_, controller) { return Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ Row( children: [ Expanded( child: Text( "Select Delivery", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), GestureDetector( onTap: () => Navigator.pop(context), child: Icon(Icons.close)), ], ), Expanded( child: ListView( controller: controller, children: list.map((delivery) { return ListTile( leading: _buildStatusIcon(delivery["status"]), title: Text(_buildStatusText(delivery)), subtitle: Text( "Capacity: ${delivery["capacity"]} • ${delivery["time"]}"), onTap: () { Navigator.pop(context); showActionsForSingleDelivery(delivery, isPast); }, ); }).toList(), ), ) ], ), ); }, ); }, ); } // =========================================================================== // ACTIONS SHEET // =========================================================================== void showActionsForSingleDelivery(Map delivery, bool isPast) { String status = delivery["status"]; // ❌ ORIGINAL DATE → NO ACTIONS if (status == "rescheduled_from") { showModalBottomSheet( context: context, builder: (_) { return Container( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text("Rescheduled from this date", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 10), Text("This delivery was moved to another date.", style: TextStyle(color: Colors.grey)), ], ), ); }, ); return; } // ❌ CANCELLED ORDER → NO ACTIONS if (status == "cancelled") { showModalBottomSheet( context: context, builder: (_) => Container( padding: EdgeInsets.all(20), child: Text("Order was cancelled", style: TextStyle(color: Colors.red)), ), ); return; } // NORMAL OR RESCHEDULED_TO (ACTIONS ENABLED) showModalBottomSheet( context: context, builder: (_) { return Container( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text("${delivery["supplierName"]}", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 16), if (!isPast) ...[ ListTile( leading: Icon(Icons.calendar_month, color: Colors.blue), title: Text("Reschedule Delivery"), onTap: () { Navigator.pop(context); openRescheduleCalendar(delivery); }, ), ListTile( leading: Icon(Icons.delete_forever, color: Colors.red), title: Text("Cancel Delivery"), onTap: () { Navigator.pop(context); _confirmCancel(delivery["_id"]); }, ), ], if (isPast) Text("Past delivery — actions disabled", style: TextStyle(color: Colors.grey)), ], ), ); }, ); } // =========================================================================== // BUILD UI // =========================================================================== @override Widget build(BuildContext context) { if (isLoading) { return Scaffold(body: Center(child: CircularProgressIndicator())); } final height = MediaQuery.of(context).size.height; return Scaffold( backgroundColor: Colors.white, body: Column( children: [ SizedBox(height: 50), Text( "${monthShort[_focusedDay.month - 1]} ${_focusedDay.year}", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), Expanded( child: TableCalendar( firstDay: _firstDay, lastDay: _lastDay, focusedDay: _focusedDay, headerVisible: false, calendarFormat: CalendarFormat.month, rowHeight: (height - 200) / 6, daysOfWeekHeight: 40, onPageChanged: (focused) { setState(() => _focusedDay = focused); }, onDaySelected: (selected, focused) { _focusedDay = focused; _selectedDay = selected; showDeliveryList(selected); setState(() {}); }, calendarBuilders: CalendarBuilders( defaultBuilder: (context, date, _) { final key = DateTime(date.year, date.month, date.day); final events = calendarEvents[key]; Color bg = Colors.transparent; if (events != null && events.isNotEmpty) { String s = events.first["status"]; if (s == "rescheduled_to") bg = Colors.deepOrange.withOpacity(0.10); else if (s == "rescheduled_from") bg = Colors.orange.withOpacity(0.10); else if (s == "cancelled") bg = Colors.red.withOpacity(0.10); else bg = Colors.blue.withOpacity(0.08); } // Grouping counts (delivery, cancelled, rescheduled) Map grouped = {}; if (events != null) { for (var e in events) { grouped[e["status"]] = (grouped[e["status"]] ?? 0) + 1; } } return Container( decoration: BoxDecoration( color: bg, border: Border.all(color: Colors.grey.shade300)), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text("${date.day}", style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold)), if (events != null && events.isNotEmpty) Wrap( spacing: 3, alignment: WrapAlignment.center, children: grouped.entries.map((entry) { IconData icon; Color color; if (entry.key == "rescheduled_from") { icon = Icons.subdirectory_arrow_left; color = Colors.orange; } else if (entry.key == "rescheduled_to") { icon = Icons.subdirectory_arrow_right; color = Colors.deepOrange; } else if (entry.key == "cancelled") { icon = Icons.cancel; color = Colors.red; } else { icon = Icons.local_shipping; color = Colors.blue; } return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 10, color: color), Text("x${entry.value}", style: TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: color)), ], ); }).toList(), ) ], ), ), ); }, ), ), ), ], ), ); } }