Last Mile Courier Dispatch
blockdashboardLast-mile courier dispatch matrix with real-time route progress, ETA telemetry, and Proof of Delivery (POD) logging.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/last-mile-courier-dispatch.json$npx shadcn@latest add https://uipkge.dev/r/react/last-mile-courier-dispatch.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/last-mile-courier-dispatch.json$bunx shadcn@latest add https://uipkge.dev/r/react/last-mile-courier-dispatch.jsonNamed registry:
npx shadcn@latest add @uipkge-react/last-mile-courier-dispatchInstalls to:components/blocks/last-mile-courier-dispatch/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
routeId | string | — | optional |
driverName | string | — | optional |
vehicleCode | string | — | optional |
className | string | — | optional |
accessToken | string | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
DeliveryStopinterface DeliveryStop {
id: string
stopNumber: number
trackingCode: string
recipient: string
address: string
parcels: number
timeWindow: string
eta: string
status: 'delivered' | 'en_route' | 'scheduled' | 'failed'
podType?: 'signature' | 'photo_scanned' | 'front_door'
podTimestamp?: string
coords?: [number, number]
}Files installed (2)
components/blocks/last-mile-courier-dispatch/LastMileCourierDispatch.tsx14.8 kB
'use client' import * as React from 'react' import { BatteryCharging, Navigation, Phone, Radio, Truck } from 'lucide-react' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Map, MapMarker, MapSource, MapLayer } from '@/components/ui/map' import { cn } from '@/lib/utils' export interface DeliveryStop { id: string stopNumber: number trackingCode: string recipient: string address: string parcels: number timeWindow: string eta: string status: 'delivered' | 'en_route' | 'scheduled' | 'failed' podType?: 'signature' | 'photo_scanned' | 'front_door' podTimestamp?: string coords?: [number, number] } export interface LastMileDispatchProps { routeId?: string driverName?: string vehicleCode?: string className?: string accessToken?: string } export function LastMileCourierDispatch({ routeId = 'RTE-METRO-409', driverName = 'Elena Rostova', vehicleCode = 'VAN-EV-09 (Ford E-Transit)', className, accessToken, }: LastMileDispatchProps) { const [stops, setStops] = React.useState<DeliveryStop[]>([ { id: 'stp-1', stopNumber: 1, trackingCode: 'TRK-9941-8812', recipient: 'Apex Logistics HQ', address: '742 Evergreen Terrace, Sector 4', parcels: 3, timeWindow: '08:30 - 09:30', eta: '08:52 AM', status: 'delivered', podType: 'signature', podTimestamp: '08:54 AM (Signed by J. Doe)', coords: [-73.991, 40.743], }, { id: 'stp-2', stopNumber: 2, trackingCode: 'TRK-9941-8813', recipient: 'David K. Miller', address: '1204 Pinehurst Ave, Apt 3B', parcels: 1, timeWindow: '09:30 - 10:30', eta: '09:45 AM', status: 'delivered', podType: 'photo_scanned', podTimestamp: '09:48 AM (Doorstep Verified)', coords: [-73.987, 40.747], }, { id: 'stp-3', stopNumber: 3, trackingCode: 'TRK-9941-8814', recipient: 'Global Tech Labs', address: '450 Innovation Parkway, Suite 100', parcels: 4, timeWindow: '10:00 - 11:30', eta: '10:25 AM', status: 'en_route', coords: [-73.982, 40.751], }, { id: 'stp-4', stopNumber: 4, trackingCode: 'TRK-9941-8815', recipient: 'Sarah Jenkins', address: '88 Riverfront Blvd', parcels: 2, timeWindow: '11:30 - 12:30', eta: '11:45 AM', status: 'scheduled', coords: [-73.978, 40.755], }, { id: 'stp-5', stopNumber: 5, trackingCode: 'TRK-9941-8816', recipient: 'Metro Health Clinic', address: '310 Health Sciences Way', parcels: 1, timeWindow: '12:30 - 14:00', eta: '01:10 PM', status: 'scheduled', coords: [-73.971, 40.758], }, ]) const completedCount = stops.filter((s) => s.status === 'delivered').length const totalStops = stops.length const onTimeRate = '98.4%' const routePolylineGeoJson = React.useMemo( () => ({ type: 'Feature' as const, properties: {}, geometry: { type: 'LineString' as const, coordinates: stops.map((s) => s.coords).filter(Boolean) as [number, number][], }, }), [stops], ) const courierRoutePaint = { 'line-color': '#0284c7', 'line-width': 3, 'line-dasharray': [2, 2], } function markDelivered(id: string) { setStops((prev) => { let foundTarget = false return prev.map((stop) => { if (stop.id === id) { foundTarget = true return { ...stop, status: 'delivered' as const, podType: 'signature' as const, podTimestamp: 'Just now (Signed)', } } if (foundTarget && stop.status === 'scheduled') { foundTarget = false return { ...stop, status: 'en_route' as const } } return stop }) }) } return ( <div data-slot="last-mile-courier-dispatch" className={`w-full space-y-6 ${className ?? ''}`}> {/* Header / Dispatch Telemetry Overview */} <Card> <CardHeader className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"> <div className="space-y-1"> <div className="flex items-center gap-2"> <span className="text-foreground font-mono text-sm font-semibold">{routeId}</span> <Badge variant="outline" className="font-mono text-xs"> {vehicleCode} </Badge> <Badge variant="secondary" className="gap-1 text-xs"> <Radio className="text-foreground size-3" /> Live Telemetry Active </Badge> </div> <CardTitle className="text-xl">Last-Mile Courier Dispatch & POD Telemetry</CardTitle> <CardDescription> Courier: <span className="text-foreground font-medium">{driverName}</span> · Urban Route Dispatch Matrix </CardDescription> </div> <div className="flex items-center gap-2"> <Button variant="outline" size="sm" className="gap-1.5"> <Phone className="size-3.5" /> Contact Driver </Button> <Button variant="default" size="sm" className="gap-1.5"> <Navigation className="size-3.5" /> Live GPS Map </Button> </div> </CardHeader> <CardContent className="border-border grid grid-cols-1 gap-4 border-t pt-4 sm:grid-cols-4"> {/* Progress Metric */} <div className="border-border space-y-1 rounded-lg border p-3"> <div className="text-muted-foreground text-xs font-medium">ROUTE COMPLETION</div> <div className="flex items-baseline justify-between pt-1"> <div className="font-mono text-xl font-semibold"> {completedCount} / {totalStops} </div> <span className="text-muted-foreground font-mono text-xs"> {Math.round((completedCount / totalStops) * 100)}% </span> </div> </div> {/* On-time SLA */} <div className="border-border space-y-1 rounded-lg border p-3"> <div className="text-muted-foreground text-xs font-medium">ON-TIME WINDOW SLA</div> <div className="pt-1 font-mono text-xl font-semibold">{onTimeRate}</div> </div> {/* Vehicle Telemetry */} <div className="border-border space-y-1 rounded-lg border p-3"> <div className="text-muted-foreground flex items-center gap-1 text-xs font-medium"> <BatteryCharging className="size-3.5" /> <span>EV BATTERY / RANGE</span> </div> <div className="pt-1 font-mono text-xl font-semibold">74% · 142 km</div> </div> {/* Next Stop ETA */} <div className="border-border space-y-1 rounded-lg border p-3"> <div className="text-muted-foreground text-xs font-medium">CURRENT TARGET ETA</div> <div className="pt-1 font-mono text-xl font-semibold">10:25 AM (Stop #3)</div> </div> </CardContent> </Card> {/* Live GPS Route Map */} <Card className="overflow-hidden"> <CardHeader className="border-border/70 border-b pb-3"> <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div> <CardTitle className="flex items-center gap-2 text-base font-semibold"> <Navigation className="text-info size-4" /> <span>Live GPS Telemetry & Corridor Map</span> </CardTitle> <CardDescription> Real-time courier positioning with sequenced drop waypoints and completion status. </CardDescription> </div> <div className="flex items-center gap-2"> <span className="bg-success inline-flex size-2 animate-ping rounded-full" /> <span className="text-muted-foreground font-mono text-xs">GPS Synced · 3s ago</span> </div> </div> </CardHeader> <div className="relative h-72 w-full sm:h-80"> <Map variant="dark" accessToken={accessToken} center={[-73.982, 40.75]} zoom={13.8} className="size-full"> {/* Route Polyline */} <MapSource id="courier-route-source" type="geojson" data={routePolylineGeoJson}> <MapLayer id="courier-route-line" type="line" paint={courierRoutePaint} /> </MapSource> {/* Delivery Stop Markers */} {stops.map((stop) => ( <MapMarker key={stop.id} longitude={stop.coords![0]} latitude={stop.coords![1]} anchor="center"> <div className="flex flex-col items-center"> <div className={cn( 'border-background flex size-6 items-center justify-center rounded-full border-2 font-mono text-xs font-bold shadow-md', stop.status === 'delivered' ? 'bg-success text-white' : stop.status === 'en_route' ? 'bg-warning text-white ring-2 ring-amber-400/50' : 'bg-muted text-muted-foreground', )} > {stop.stopNumber} </div> <span className="border-border/80 bg-background/90 py-0.2 mt-0.5 rounded border px-1 font-mono text-xs font-medium shadow-xs backdrop-blur-xs"> {stop.recipient.split(' ')[0]} </span> </div> </MapMarker> ))} {/* Live Courier Van Marker */} <MapMarker longitude={-73.984} latitude={40.749} anchor="center" className="z-30"> <div className="relative flex size-9 items-center justify-center"> <span className="bg-info absolute inline-flex size-full animate-ping rounded-full opacity-60" /> <div className="bg-info relative flex size-8 items-center justify-center rounded-full border-2 border-white text-white shadow-lg"> <Truck className="size-4" /> </div> </div> </MapMarker> </Map> </div> </Card> {/* Dispatch Sequence Table */} <Card> <CardHeader className="pb-3"> <CardTitle className="text-base font-semibold">Delivery Manifest & Proof of Delivery (POD)</CardTitle> <CardDescription> Ordered drop sequence with recipient signature capture and delivery window timestamps. </CardDescription> </CardHeader> <CardContent className="p-0"> <Table> <TableHeader> <TableRow> <TableHead className="w-[60px]">Stop</TableHead> <TableHead className="w-[180px]">Tracking ID</TableHead> <TableHead className="w-[260px]">Recipient & Address</TableHead> <TableHead>Window / ETA</TableHead> <TableHead className="text-right">Parcels</TableHead> <TableHead>Status & Proof of Delivery</TableHead> <TableHead className="w-[100px] text-right">Action</TableHead> </TableRow> </TableHeader> <TableBody> {stops.map((stop) => ( <TableRow key={stop.id} className={stop.status === 'en_route' ? 'bg-muted/40 font-medium' : ''}> {/* Stop Number */} <TableCell className="text-muted-foreground font-mono text-xs">#0{stop.stopNumber}</TableCell> {/* Tracking Code */} <TableCell> <div className="text-foreground font-mono text-xs font-semibold">{stop.trackingCode}</div> </TableCell> {/* Recipient & Address */} <TableCell> <div className="text-foreground font-medium">{stop.recipient}</div> <div className="text-muted-foreground truncate text-xs">{stop.address}</div> </TableCell> {/* Time Window & ETA */} <TableCell> <div className="text-foreground text-xs">{stop.timeWindow}</div> <div className="text-muted-foreground font-mono text-xs">ETA: {stop.eta}</div> </TableCell> {/* Parcels Count */} <TableCell className="text-right font-mono text-sm">{stop.parcels} pkg</TableCell> {/* Status & Proof of Delivery */} <TableCell> <div className="flex flex-col gap-1"> <div className="flex items-center gap-2"> <Badge variant={ stop.status === 'delivered' ? 'default' : stop.status === 'en_route' ? 'secondary' : 'outline' } className="capitalize" > {stop.status.replace('_', ' ')} </Badge> </div> {stop.podTimestamp && ( <span className="text-muted-foreground font-mono text-xs">{stop.podTimestamp}</span> )} </div> </TableCell> {/* Action */} <TableCell className="text-right"> {stop.status === 'en_route' && ( <Button size="sm" variant="default" className="h-7 text-xs" onClick={() => markDelivered(stop.id)} > Confirm POD </Button> )} {stop.status === 'delivered' && <span className="text-muted-foreground text-xs">Logged</span>} {stop.status === 'scheduled' && <span className="text-muted-foreground text-xs">Queued</span>} </TableCell> </TableRow> ))} </TableBody> </Table> </CardContent> <CardFooter className="border-border text-muted-foreground flex items-center justify-between border-t py-3 text-xs"> <div>Geotagged proof of delivery records are synced automatically to customer tracking portals.</div> <div className="text-foreground font-medium"> Route summary: <span className="font-mono">{totalStops}</span> total consignments </div> </CardFooter> </Card> </div> ) }components/blocks/last-mile-courier-dispatch/index.ts0.1 kB
export { LastMileCourierDispatch } from './LastMileCourierDispatch' export type { DeliveryStop, LastMileDispatchProps } from './LastMileCourierDispatch'
Raw manifest:https://uipkge.dev/r/react/last-mile-courier-dispatch.json