updates on the reverse logistics

This commit is contained in:
2026-10-06 17:30:06 +05:30
parent 806f4a2b3f
commit 6e73b59ca9
12 changed files with 1069 additions and 21 deletions

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useMemo, useState } from 'react';
import dayjs from 'dayjs';
import { Ban, Bell, Bike, Clock, FileSpreadsheet, PackageSearch, Truck } from 'lucide-react';
import { Ban, Bell, Bike, Clock, FileSpreadsheet, PackageCheck, PackageSearch, RotateCcw, Truck, Undo2 } from 'lucide-react';
import {
Alert, Button, DataTable, DatePicker, Drawer, EmptyState, Field, IconButton, SearchInput, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Modal,
Stack, StatusBadge, Surface, Tabs, Textarea, ZoneSelector,
@@ -17,6 +17,8 @@ import { currency, exportRows, km as formatKm, matchesQuery, orDash, useDebounce
import { toDateRange } from '@/lib/dateRange';
import { pickupSourceTypeLabel } from '@/lib/orderFlow';
import { summariseRouting } from '@/lib/routingSummary';
import { useAuth } from '@/lib/AuthContext';
import { ResolveRtoModal, StartRtoModal, rtoActionsFor } from '@/components/doormile/RtoDialogs';
/**
* Deliveries — orders that have moved past merely being created.
@@ -45,6 +47,9 @@ const STATUS_TABS = [
{ value: 'skipped', label: 'Skipped', countKey: 'skippedLength' },
{ value: 'delivered', label: 'Delivered', countKey: 'coveredLength' },
{ value: 'cancelled', label: 'Cancelled', countKey: 'cancelLength' },
// Reverse logistics: parcels going back to the sender, and those back.
{ value: 'rto', label: 'In return', countKey: 'rtoLength' },
{ value: 'returned', label: 'Returned', countKey: 'returnedLength' },
];
const KNOWN_STATUSES = STATUS_TABS.map((tab) => tab.value).concat('canceled');
@@ -89,6 +94,11 @@ export default function Deliveries() {
const [nextStatus, setNextStatus] = useState('delivered');
const [cancelRow, setCancelRow] = useState(null);
const [cancelReason, setCancelReason] = useState('');
// Reverse logistics. Starting/closing a return is a Doormile-staff action;
// a client login sees the statuses but no buttons (the server refuses too).
const { isClient } = useAuth();
const [rtoRow, setRtoRow] = useState(null);
const [resolveRto, setResolveRto] = useState({ row: null, mode: 'cancel' });
const dateParams = useMemo(() => toDateRange(selectedDate), [selectedDate]);
@@ -309,7 +319,7 @@ export default function Deliveries() {
key: 'actions',
header: 'Actions',
align: 'right',
width: '130px',
width: '170px',
cell: (row) => (
<div className="flex justify-end gap-1">
<IconButton
@@ -320,7 +330,10 @@ export default function Deliveries() {
onClick={() => setDetailRow(row)}
/>
{row.orderstatus !== 'delivered' && row.milerprofileid ? (
{/* Not on parcels in or through a return: the generic "process
deliveries" text is wrong for them, and starting a return
already pushes the rider a return-specific message. */}
{!['delivered', 'rto', 'returned'].includes(String(row.orderstatus || '').toLowerCase()) && row.milerprofileid ? (
<IconButton
label="Notify rider"
icon={Bell}
@@ -349,18 +362,51 @@ export default function Deliveries() {
/>
) : null}
<IconButton
label="Update status"
icon={Truck}
variant="ghost"
size="sm"
onClick={() => {
setStatusRow(row);
setNextStatus('delivered');
}}
/>
{!isClient && rtoActionsFor(row).canStart ? (
<IconButton
label="Return to sender"
icon={Undo2}
variant="ghost"
size="sm"
onClick={() => setRtoRow(row)}
/>
) : null}
{!['delivered', 'cancelled', 'canceled'].includes(String(row.orderstatus || '').toLowerCase()) ? (
{!isClient && rtoActionsFor(row).canResolve ? (
<>
<IconButton
label="Re-attempt delivery"
icon={RotateCcw}
variant="ghost"
size="sm"
onClick={() => setResolveRto({ row, mode: 'cancel' })}
/>
<IconButton
label="Mark returned"
icon={PackageCheck}
variant="ghost"
size="sm"
onClick={() => setResolveRto({ row, mode: 'complete' })}
/>
</>
) : null}
{/* A parcel in or through a return is moved only by the return
actions above — the server refuses a plain status change. */}
{!['rto', 'returned'].includes(String(row.orderstatus || '').toLowerCase()) ? (
<IconButton
label="Update status"
icon={Truck}
variant="ghost"
size="sm"
onClick={() => {
setStatusRow(row);
setNextStatus('delivered');
}}
/>
) : null}
{!['delivered', 'cancelled', 'canceled', 'rto', 'returned'].includes(String(row.orderstatus || '').toLowerCase()) ? (
<IconButton
label="Cancel delivery"
icon={Ban}
@@ -376,7 +422,7 @@ export default function Deliveries() {
),
},
],
[notifyMiler]
[notifyMiler, isClient]
);
const exportColumns = [
@@ -697,6 +743,13 @@ export default function Deliveries() {
</Field>
</Modal>
<StartRtoModal row={rtoRow} onClose={() => setRtoRow(null)} />
<ResolveRtoModal
row={resolveRto.row}
mode={resolveRto.mode}
onClose={() => setResolveRto({ row: null, mode: 'cancel' })}
/>
<OrderDetailDrawer row={detailRow} onClose={() => setDetailRow(null)} />
</Stack>
);