mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 05:18:11 +00:00
236 lines
7.5 KiB
TypeScript
236 lines
7.5 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { Calendar, Hash, Package, Ruler, Weight } from "lucide-react";
|
|
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from "@/components/ui/dialog";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
|
|
import { bookings } from "../bookings/bookings.mock";
|
|
import type {
|
|
ConsignmentCargo,
|
|
ConsignmentStatus,
|
|
} from "./consignments.mock";
|
|
|
|
export interface ConsignmentFormData {
|
|
trackingNumber?: string;
|
|
bookingId?: number;
|
|
bookingReference?: string;
|
|
cargoType?: ConsignmentCargo;
|
|
description?: string;
|
|
weightKg?: number;
|
|
volumeM3?: number;
|
|
pieces?: number;
|
|
hazardous?: boolean;
|
|
specialHandling?: string;
|
|
status?: ConsignmentStatus;
|
|
estimatedDelivery?: string;
|
|
}
|
|
|
|
export interface NewConsignmentPageProps {
|
|
mode?: "create" | "edit";
|
|
consignment?: ConsignmentFormData;
|
|
children?: ReactNode;
|
|
}
|
|
|
|
const selectClass =
|
|
"flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm text-slate-700 shadow-xs outline-none transition hover:border-slate-300 focus:border-[#10B981]/50 focus:ring-2 focus:ring-[#10B981]/20";
|
|
|
|
export default function NewConsignmentPage({
|
|
mode = "create",
|
|
consignment,
|
|
children,
|
|
}: NewConsignmentPageProps = {}) {
|
|
const isEdit = mode === "edit";
|
|
const title = isEdit ? "Edit Consignment" : "New Consignment";
|
|
const description = isEdit
|
|
? "Update consignment details."
|
|
: "Register a new consignment under a freight booking.";
|
|
const submitLabel = isEdit ? "Save Changes" : "Create Consignment";
|
|
|
|
return (
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
{children ?? (
|
|
<Button>{isEdit ? "Edit" : "New Consignment"}</Button>
|
|
)}
|
|
</DialogTrigger>
|
|
|
|
<DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-3xl rounded-3xl">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-2xl font-bold">{title}</DialogTitle>
|
|
<DialogDescription>{description}</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="grid gap-5 py-4 md:grid-cols-2">
|
|
{/* Tracking Number */}
|
|
<div className="space-y-2">
|
|
<Label>Tracking Number *</Label>
|
|
<div className="relative">
|
|
<Hash className="absolute left-3 top-3 h-4 w-4 text-slate-400" />
|
|
<Input
|
|
defaultValue={consignment?.trackingNumber ?? ""}
|
|
placeholder="e.g. CGM-0001"
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Status */}
|
|
<div className="space-y-2">
|
|
<Label>Status</Label>
|
|
<select
|
|
defaultValue={consignment?.status ?? "Pending"}
|
|
className={selectClass}
|
|
>
|
|
<option>Pending</option>
|
|
<option>In Warehouse</option>
|
|
<option>In Transit</option>
|
|
<option>Delivered</option>
|
|
<option>Returned</option>
|
|
</select>
|
|
</div>
|
|
|
|
{/* Booking */}
|
|
<div className="space-y-2 md:col-span-2">
|
|
<Label>Freight Booking *</Label>
|
|
<select
|
|
defaultValue={consignment?.bookingId ?? ""}
|
|
className={selectClass}
|
|
>
|
|
<option value="" disabled>
|
|
Select freight booking
|
|
</option>
|
|
{bookings.map((b) => (
|
|
<option key={b.id} value={b.id}>
|
|
{b.reference} — {b.customer} ({b.originStation} →{" "}
|
|
{b.destinationStation})
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
{/* Cargo Type */}
|
|
<div className="space-y-2">
|
|
<Label>Cargo Type *</Label>
|
|
<select
|
|
defaultValue={consignment?.cargoType ?? "Containerized"}
|
|
className={selectClass}
|
|
>
|
|
<option>Containerized</option>
|
|
<option>Bulk</option>
|
|
<option>Liquid</option>
|
|
<option>Refrigerated</option>
|
|
<option>Hazardous</option>
|
|
<option>General</option>
|
|
</select>
|
|
</div>
|
|
|
|
{/* Pieces */}
|
|
<div className="space-y-2">
|
|
<Label>Pieces</Label>
|
|
<div className="relative">
|
|
<Package className="absolute left-3 top-3 h-4 w-4 text-slate-400" />
|
|
<Input
|
|
type="number"
|
|
min={1}
|
|
defaultValue={consignment?.pieces ?? 1}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Weight */}
|
|
<div className="space-y-2">
|
|
<Label>Weight (kg)</Label>
|
|
<div className="relative">
|
|
<Weight className="absolute left-3 top-3 h-4 w-4 text-slate-400" />
|
|
<Input
|
|
type="number"
|
|
min={0}
|
|
step="0.1"
|
|
defaultValue={consignment?.weightKg ?? 0}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Volume */}
|
|
<div className="space-y-2">
|
|
<Label>Volume (m³)</Label>
|
|
<div className="relative">
|
|
<Ruler className="absolute left-3 top-3 h-4 w-4 text-slate-400" />
|
|
<Input
|
|
type="number"
|
|
min={0}
|
|
step="0.1"
|
|
defaultValue={consignment?.volumeM3 ?? 0}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* ETA */}
|
|
<div className="space-y-2">
|
|
<Label>Estimated Delivery</Label>
|
|
<div className="relative">
|
|
<Calendar className="absolute left-3 top-3 h-4 w-4 text-slate-400" />
|
|
<Input
|
|
type="date"
|
|
defaultValue={consignment?.estimatedDelivery ?? ""}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Hazardous */}
|
|
<div className="space-y-2">
|
|
<Label>Hazardous Goods</Label>
|
|
<label className="flex h-10 items-center gap-2 rounded-md border border-slate-200 bg-white px-3 text-sm text-slate-700">
|
|
<input
|
|
type="checkbox"
|
|
defaultChecked={consignment?.hazardous ?? false}
|
|
className="h-4 w-4 rounded border-slate-300 text-[#10B981] focus:ring-[#10B981]/20"
|
|
/>
|
|
<span>Mark as hazardous (DG)</span>
|
|
</label>
|
|
</div>
|
|
|
|
{/* Description */}
|
|
<div className="space-y-2 md:col-span-2">
|
|
<Label>Description</Label>
|
|
<Textarea
|
|
defaultValue={consignment?.description ?? ""}
|
|
placeholder="Describe the consignment contents..."
|
|
/>
|
|
</div>
|
|
|
|
{/* Special Handling */}
|
|
<div className="space-y-2 md:col-span-2">
|
|
<Label>Special Handling</Label>
|
|
<Textarea
|
|
defaultValue={consignment?.specialHandling ?? ""}
|
|
placeholder="Any handling instructions..."
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end gap-3">
|
|
<Button variant="outline">Cancel</Button>
|
|
<Button className="bg-[#10B981] text-white hover:bg-[#10B981]/90">
|
|
{submitLabel}
|
|
</Button>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|