import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Text } from '@astryxdesign/core/Text'; import { VStack } from '@astryxdesign/core/VStack'; import { errorMessage } from '@/api/client'; import { deliveriesApi } from '@/api/deliveries'; import type { DeliveryRow } from '@/api/types'; import { queryKeys } from '@/queries/keys'; import { stampNow } from './assignDelivery'; /** * Moving a delivery along from the back office. * * The rider's app drives this ladder in the ordinary case. This is for when it * cannot: a rider whose phone died, a job cancelled by phone, a delivery that * was completed but never marked. Without it the only way to correct a stuck * job is a database write. * * ── Two things the backend does that shape this ───────────────────────────── * * `updatedelivery` mirrors the status onto the parent order for `pending`, * `delivered` and `cancelled` — but NOT for `picked`, which updates the * delivery and leaves the order where it was. So the order and its delivery * legitimately disagree in the middle of a journey, and this does not try to * paper over that. * * The lifecycle timestamp is sent explicitly. `Updates()` skips zero-valued * struct fields, so a status sent without its stamp moved the status and left * the column blank — which is how a delivery ends up marked delivered with no * delivery time against it. */ /** What can be set from here, in the order a job actually walks. */ const MOVES = [ { to: 'picked', label: 'Picked up', stamp: 'pickuptime' }, { to: 'delivered', label: 'Delivered', stamp: 'deliverytime' }, { to: 'cancelled', label: 'Cancelled', stamp: 'canceltime' }, ] as const; /** The end states. Nothing follows them, so nothing is offered. */ const SETTLED = ['delivered', 'cancelled']; export function DeliveryProgress({ job }: { job: DeliveryRow }) { const client = useQueryClient(); const [problem, setProblem] = useState(null); const status = (job.orderstatus ?? '').trim().toLowerCase(); const isSettled = SETTLED.includes(status); const move = useMutation({ mutationFn: ({ to, stamp }: { to: string; stamp: string }) => deliveriesApi.update({ deliveryid: job.deliveryid, orderheaderid: job.orderheaderid ?? 0, orderstatus: to, [stamp]: stampNow(), }), onSuccess: () => client.invalidateQueries({ queryKey: queryKeys.insights.all }), onError: (error) => setProblem(errorMessage(error)), }); if (isSettled) { return ( This job is {status}. Nothing further to record. ); } return (
{MOVES.map((step) => ( ))}
{problem ? ( {problem} ) : ( Use these only when the rider's app has not. Marking a job delivered here also closes the order. )}
); }