master
Sneha 1 month ago
parent a7a868fcdd
commit 0bdaa99c55

@ -187,7 +187,9 @@ class AppSettings{
static String acceptAdvanceFromCustomerUrl = host + 'advance/confirm';
static String getAdvanceTransactionsBySupplierAndCustomerUrl = host + 'advance/transactions';
static String respondRecurringBookingUrl = host + 'customer/recurring/respond';
static String getSupplierBookingsUrl = host + 'getsupplierbookings';
static String getSupplierBookingsUrl = host + 'getuserRequestbookingsforplansforsupplier';
static String recurringDateActionUrl = host + 'recurring-booking/date-action';
@ -1424,6 +1426,26 @@ class AppSettings{
}
}
static Future<void> recurringDateAction(
String bookingId,
Map<String, dynamic> payload,
) async {
final url = Uri.parse("$recurringDateActionUrl/${bookingId}");
final response = await http.post(
url,
headers: await buildRequestHeaders(),
body: jsonEncode(payload),
);
if (response.statusCode != 200) {
throw Exception(
"Recurring date action failed: ${response.body}",
);
}
}
/*Apis ends here*/

@ -18,6 +18,56 @@ class _SupplierCalendarState extends State<SupplierCalendar> {
bool isLoading = true;
Future<void> cancelSingleDate(Map<String, dynamic> delivery) async {
try {
await AppSettings.recurringDateAction(
delivery["_id"],
{
"action": "cancel",
"date": delivery["date"], // IMPORTANT
"reason": "Cancelled by supplier",
},
);
await fetchOrdersFromApi();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Delivery cancelled successfully")),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Cancel failed")),
);
}
}
Future<void> rescheduleSingleDate(
Map<String, dynamic> delivery,
String newDate,
) async {
try {
await AppSettings.recurringDateAction(
delivery["_id"],
{
"action": "reschedule",
"date": delivery["date"], // original date
"new_date": newDate, // selected date
"reason": "Rescheduled by supplier",
},
);
await fetchOrdersFromApi();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Delivery rescheduled")),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Reschedule failed")),
);
}
}
@override
void initState() {
super.initState();
@ -49,66 +99,48 @@ class _SupplierCalendarState extends State<SupplierCalendar> {
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) {}
final String capacity = order["capacity"] ?? "";
final String time = order["time"] ?? "";
final String bookingStatus = order["booking_status"] ?? "";
final String supplierName =
order["customer_details"]?["profile"]?["username"] ?? "Customer";
final List<dynamic> dates = order["dates"] ?? [];
for (var d in dates) {
final String? dateStr = d["date"];
if (dateStr == null) continue;
DateTime date = DateTime.parse(dateStr);
DateTime key = DateTime(date.year, date.month, date.day);
calendarEvents.putIfAbsent(key, () => []);
// ---------------- STATUS LOGIC ----------------
String status = "delivery";
if (d["status"] == "rescheduled") {
status = "rescheduled_from";
}
if (d["rescheduled_from"] != null) {
status = "rescheduled_to";
}
if (d["status"] == "cancelled") {
status = "cancelled";
}
calendarEvents[key]!.add({
"status": status,
"_id": order["_id"],
"supplierName": supplierName,
"capacity": capacity,
"time": time,
"date": dateStr,
"originalDate": d["rescheduled_from"],
"newDate": d["rescheduled_to"],
});
}
}
@ -118,6 +150,7 @@ class _SupplierCalendarState extends State<SupplierCalendar> {
}
}
// ===========================================================================
// CANCEL ORDER API
// ===========================================================================
@ -219,6 +252,7 @@ class _SupplierCalendarState extends State<SupplierCalendar> {
String formatted =
"${pickedDate.year}-${pickedDate.month.toString().padLeft(2,'0')}-${pickedDate.day.toString().padLeft(2,'0')}";
await rescheduleSingleDate(delivery, formatted);
//await sendRescheduleToServer(delivery["_id"], formatted);
}
@ -379,7 +413,7 @@ class _SupplierCalendarState extends State<SupplierCalendar> {
title: Text("Cancel Delivery"),
onTap: () {
Navigator.pop(context);
// _confirmCancel(delivery["_id"]);
cancelSingleDate(delivery);
},
),
],

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import '../common/settings.dart';
class PlanDetails extends StatefulWidget {
final Map<String, dynamic> plan; // 🔥 pass full plan object
final Map<String, dynamic> plan;
const PlanDetails({super.key, required this.plan});
@ -11,14 +11,19 @@ class PlanDetails extends StatefulWidget {
}
class _PlanDetailsState extends State<PlanDetails> {
late List<DateTime> deliveryDates;
late List<Map<String, dynamic>> deliveryDates;
@override
void initState() {
super.initState();
deliveryDates = (widget.plan["dates"] as List)
.map((d) => DateTime.parse(d))
.toList();
// 🔥 Now expecting:
// "dates": [
// { "date": "2026-02-10", "status": "scheduled" }
// ]
deliveryDates =
List<Map<String, dynamic>>.from(widget.plan["dates"] ?? []);
}
// ================= INFO CARD =================
@ -36,8 +41,7 @@ class _PlanDetailsState extends State<PlanDetails> {
style: fontTextStyle(18, Colors.black, FontWeight.w600)),
const SizedBox(height: 4),
Text(label,
style:
fontTextStyle(13, Colors.black54, FontWeight.w400)),
style: fontTextStyle(13, Colors.black54, FontWeight.w400)),
],
),
),
@ -45,22 +49,12 @@ class _PlanDetailsState extends State<PlanDetails> {
}
// ================= DELIVERY CARD =================
Widget _buildDeliveryCard(DateTime date) {
final now = DateTime.now();
String status;
Widget _buildDeliveryCard(Map<String, dynamic> delivery) {
DateTime date = DateTime.parse(delivery["date"]);
String status = delivery["status"] ?? "scheduled";
String buttonText = "";
bool showButton = true;
if (date.isBefore(now)) {
status = "completed";
showButton = false;
} else if (date.difference(now).inHours < 24) {
status = "in-progress";
buttonText = "Track Order";
} else {
status = "pending";
buttonText = "Assign Tanker";
}
bool showButton = false;
Color statusBg;
Color statusText;
@ -70,13 +64,26 @@ class _PlanDetailsState extends State<PlanDetails> {
statusBg = Colors.green.withOpacity(0.15);
statusText = Colors.green;
break;
case "rescheduled":
statusBg = Colors.purple.withOpacity(0.15);
statusText = Colors.purple;
buttonText = "View Details";
showButton = true;
break;
case "in-progress":
statusBg = Colors.blue.withOpacity(0.15);
statusText = Colors.blue;
buttonText = "Track Order";
showButton = true;
break;
default:
default: // scheduled
statusBg = Colors.orange.withOpacity(0.15);
statusText = Colors.orange;
buttonText = "Assign Tanker";
showButton = true;
}
return Container(
@ -100,15 +107,16 @@ class _PlanDetailsState extends State<PlanDetails> {
borderRadius: BorderRadius.circular(8),
),
child: Text(
status,
style: fontTextStyle(12, statusText, FontWeight.w600),
status.toUpperCase(),
style:
fontTextStyle(12, statusText, FontWeight.w600),
),
),
const Spacer(),
Text(
"${date.day}-${date.month}-${date.year}",
style:
fontTextStyle(12, Colors.black54, FontWeight.w400),
style: fontTextStyle(
12, Colors.black54, FontWeight.w400),
),
],
),
@ -118,7 +126,7 @@ class _PlanDetailsState extends State<PlanDetails> {
style: fontTextStyle(14, Colors.black, FontWeight.w600),
),
const SizedBox(height: 10),
/* if (showButton)
if (showButton)
Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
@ -135,7 +143,7 @@ class _PlanDetailsState extends State<PlanDetails> {
fontTextStyle(13, Colors.white, FontWeight.w600),
),
),
)*/
),
],
),
);
@ -147,8 +155,14 @@ class _PlanDetailsState extends State<PlanDetails> {
final plan = widget.plan;
final int totalDeliveries = deliveryDates.length;
final int pendingCount =
deliveryDates.where((d) => d.isAfter(DateTime.now())).length;
final int pendingCount = deliveryDates
.where((d) => d["status"] == "scheduled")
.length;
final int rescheduledCount = deliveryDates
.where((d) => d["status"] == "rescheduled")
.length;
return Scaffold(
backgroundColor: Colors.white,
@ -156,7 +170,8 @@ class _PlanDetailsState extends State<PlanDetails> {
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black),
icon:
const Icon(Icons.arrow_back_ios_new, color: Colors.black),
onPressed: () => Navigator.pop(context),
),
title: Text(
@ -202,8 +217,8 @@ class _PlanDetailsState extends State<PlanDetails> {
Column(
children: [
Text(plan["customerId"],
style:
fontTextStyle(18, Colors.black, FontWeight.w600)),
style: fontTextStyle(
18, Colors.black, FontWeight.w600)),
const SizedBox(height: 4),
Row(
mainAxisAlignment: MainAxisAlignment.center,
@ -213,7 +228,8 @@ class _PlanDetailsState extends State<PlanDetails> {
const SizedBox(width: 4),
Text(plan["type_of_water"],
style: fontTextStyle(
14, const Color(0xFF8270DB),
14,
const Color(0xFF8270DB),
FontWeight.w500)),
],
),
@ -230,7 +246,8 @@ class _PlanDetailsState extends State<PlanDetails> {
// INFO ROWS
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
padding:
const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
_buildInfoCard(plan["capacity"], "Quantity"),
@ -247,14 +264,17 @@ class _PlanDetailsState extends State<PlanDetails> {
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
padding:
const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
_buildInfoCard("${plan["weekly_count"]}/week", "Schedule"),
_buildInfoCard(
"${plan["weekly_count"]}/week", "Schedule"),
const SizedBox(width: 12),
_buildInfoCard("$pendingCount", "Pending"),
const SizedBox(width: 12),
_buildInfoCard("0", "Rescheduled"),
_buildInfoCard(
"$rescheduledCount", "Rescheduled"),
],
),
),
@ -268,7 +288,8 @@ class _PlanDetailsState extends State<PlanDetails> {
// BOTTOM BUTTONS
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
padding:
const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
@ -278,14 +299,17 @@ class _PlanDetailsState extends State<PlanDetails> {
side: const BorderSide(
color: Color(0xFF8270DB)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
borderRadius:
BorderRadius.circular(24),
),
padding:
const EdgeInsets.symmetric(vertical: 14),
const EdgeInsets.symmetric(
vertical: 14),
),
child: Text(
"Edit Plan",
style: fontTextStyle(14,
style: fontTextStyle(
14,
const Color(0xFF8270DB),
FontWeight.w600),
),
@ -296,17 +320,22 @@ class _PlanDetailsState extends State<PlanDetails> {
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFE2483D),
backgroundColor:
const Color(0xFFE2483D),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
borderRadius:
BorderRadius.circular(24),
),
padding:
const EdgeInsets.symmetric(vertical: 14),
const EdgeInsets.symmetric(
vertical: 14),
),
child: Text(
"Discontinue",
style: fontTextStyle(
14, Colors.white, FontWeight.w600),
14,
Colors.white,
FontWeight.w600),
),
),
),

Loading…
Cancel
Save