Files
edr-platform/apps/edr-freight-web/portal/src/pages/consignments/NewConsignmentPage.tsx
2026-05-15 22:17:31 +03:00

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-[#33578D]/50 focus:ring-2 focus:ring-[#33578D]/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-[#33578D] focus:ring-[#33578D]/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-[#33578D] text-white hover:bg-[#33578D]/90">
{submitLabel}
</Button>
</div>
</DialogContent>
</Dialog>
);
}