mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 08:32:54 +00:00
fix: the direction for the yard
This commit is contained in:
@@ -70,7 +70,7 @@ export default function NewBookingPage() {
|
||||
const destinationYard = form.watch("destinationYard");
|
||||
|
||||
const direction = useMemo(
|
||||
() => getRouteDirection(originYard, destinationYard),
|
||||
() => getRouteDirection(referenceData?.yard.find((y) => y.id === originYard), referenceData?.yard.find((y) => y.id === destinationYard)),
|
||||
[originYard, destinationYard],
|
||||
);
|
||||
|
||||
@@ -163,12 +163,7 @@ export default function NewBookingPage() {
|
||||
: "WITHOUT_RETURN",
|
||||
originYardId: findYardId(data.originYard),
|
||||
destinationYardId: findYardId(data.destinationYard),
|
||||
tradeDirection:
|
||||
direction === "export"
|
||||
? "EXPORT"
|
||||
: direction === "domestic"
|
||||
? "DOMESTIC"
|
||||
: "IMPORT",
|
||||
tradeDirection: direction!,
|
||||
cargoTypeId: data.cargoType === "container" ? undefined : cargoTypeId,
|
||||
cargoTotalWeightVgm: totalWeight,
|
||||
isHazardous: data.isHazardous,
|
||||
|
||||
@@ -2,15 +2,6 @@ import type { Freight } from "@edr/types";
|
||||
import { DeepPartial, Path } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
export const ETHIOPIA_STATIONS = new Set<string>([
|
||||
"Addis Ababa",
|
||||
"Adama",
|
||||
"Mojo",
|
||||
"Awash",
|
||||
"Mieso",
|
||||
"Dire Dawa",
|
||||
]);
|
||||
|
||||
export const MOCK_VALID_CONTRACTS = [
|
||||
"EDR-2024-10001",
|
||||
"EDR-2024-10002",
|
||||
@@ -23,8 +14,9 @@ export const STEPS = [
|
||||
{ id: 2, label: "Service Type & Mile", short: "Service" },
|
||||
{ id: 3, label: "Route", short: "Route" },
|
||||
{ id: 4, label: "Cargo Details", short: "Cargo" },
|
||||
{ id: 5, label: "Documents", short: "Documents" },
|
||||
{ id: 6, label: "Review & Submit", short: "Submit" },
|
||||
{ id: 5, label: "Shipment Date", short: "Schedule" },
|
||||
{ id: 6, label: "Documents", short: "Documents" },
|
||||
{ id: 7, label: "Review & Submit", short: "Submit" },
|
||||
] as const;
|
||||
|
||||
/**
|
||||
@@ -108,6 +100,7 @@ export const bookingFormSchema = z
|
||||
originYard: z.string().min(1, "Select an origin yard."),
|
||||
destinationYard: z.string().min(1, "Select a destination yard."),
|
||||
shippingLine: z.string(),
|
||||
scheduledDate: z.string().min(1, "Select a shipment date."),
|
||||
cargoType: z.enum(["container", "bulk"], "Select a cargo type."),
|
||||
cargoWeight: z.string(),
|
||||
freightType: z.string(), // parent group
|
||||
@@ -235,6 +228,7 @@ export const initialBookingFormValues: DeepPartial<BookingFormValues> = {
|
||||
originYard: "",
|
||||
destinationYard: "",
|
||||
shippingLine: "",
|
||||
scheduledDate: "",
|
||||
cargoWeight: "",
|
||||
bulkCommoditytype: "",
|
||||
isHazardous: false,
|
||||
@@ -270,12 +264,11 @@ export const stepFields: Record<number, Array<Path<BookingFormValues>>> = {
|
||||
"containers",
|
||||
"consolidationEnabled",
|
||||
],
|
||||
5: ["documents"],
|
||||
6: ["notes", "termsAccepted"],
|
||||
5: ["scheduledDate"],
|
||||
6: ["documents"],
|
||||
7: ["notes", "termsAccepted"],
|
||||
};
|
||||
|
||||
export type RouteDirection = "import" | "export" | "domestic" | null;
|
||||
|
||||
export interface ContainerConfig {
|
||||
type: "20ft" | "40ft";
|
||||
containerType: string;
|
||||
@@ -296,35 +289,21 @@ export interface WagonCalcResult {
|
||||
ft20Wagons: number;
|
||||
}
|
||||
|
||||
export function genContractId(): string {
|
||||
const yr = new Date().getFullYear();
|
||||
const n = Math.floor(10000 + Math.random() * 90000);
|
||||
return `EDR-DRAFT-${yr}-${n}`;
|
||||
}
|
||||
|
||||
export function getRouteDirection(
|
||||
origin: string,
|
||||
dest: string,
|
||||
): RouteDirection {
|
||||
origin: Freight.BookingReferenceYard | null | undefined,
|
||||
dest: Freight.BookingReferenceYard | null | undefined,
|
||||
): Freight.ScheduleTradeDirection | null {
|
||||
if (!origin || !dest) return null;
|
||||
const oLocation = getStationLocation(origin);
|
||||
const dLocation = getStationLocation(dest);
|
||||
if (oLocation === "inside" && dLocation === "outside") return "export";
|
||||
if (oLocation === "outside" && dLocation === "inside") return "import";
|
||||
if (oLocation === "inside" && dLocation === "inside") return "domestic";
|
||||
|
||||
const oEth = ETHIOPIA_STATIONS.has(origin);
|
||||
const dEth = ETHIOPIA_STATIONS.has(dest);
|
||||
if (oEth && !dEth) return "export";
|
||||
if (!oEth && dEth) return "import";
|
||||
if (oEth && dEth) return "domestic";
|
||||
return null;
|
||||
if(origin.country === 'ethiopia' && dest.country === 'ethiopia') {
|
||||
return 'DOMESTIC';
|
||||
}
|
||||
if(origin.country === 'ethiopia' && dest.country === 'djibouti') {
|
||||
return 'IMPORT';
|
||||
}
|
||||
if(origin.country === 'djibouti' && dest.country === 'ethiopia') {
|
||||
return 'EXPORT';
|
||||
}
|
||||
|
||||
function getStationLocation(value: string): "inside" | "outside" | null {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (normalized.startsWith("inside")) return "inside";
|
||||
if (normalized.startsWith("outside")) return "outside";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export function Step4Route({
|
||||
|
||||
const yardOptions = useMemo(() => {
|
||||
if (!referenceData?.yard) return [];
|
||||
return referenceData.yard.map((y) => ({ value: y.name, label: y.name }));
|
||||
return referenceData.yard.map((y) => ({ value: y.id, label: y.name }));
|
||||
}, [referenceData]);
|
||||
|
||||
const shippingLineOptions = useMemo(() => {
|
||||
@@ -35,15 +35,40 @@ export function Step4Route({
|
||||
}, [referenceData]);
|
||||
|
||||
const originData = useMemo(
|
||||
() => yardOptions.filter((o) => o.value !== destinationYard),
|
||||
() => {
|
||||
return yardOptions.filter((o) => o.value !== destinationYard).filter((o) => {
|
||||
const dest = referenceData?.yard.find((y) => y.id === destinationYard);
|
||||
if(!dest) return true;
|
||||
const origin = referenceData?.yard.find((y) => y.id === o.value);
|
||||
|
||||
// can't go from Djibouti to Djibouti
|
||||
if(dest?.country === 'Djibouti' && origin?.country == 'Djibouti') return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
[yardOptions, destinationYard],
|
||||
);
|
||||
console.log({yardOptions,originYard, destinationYard})
|
||||
const destData = useMemo(
|
||||
() => yardOptions.filter((o) => o.value !== originYard),
|
||||
() => {
|
||||
return yardOptions.filter((o) => o.value !== originYard).filter((d) => {
|
||||
|
||||
|
||||
const origin = referenceData?.yard.find((y) => y.id === originYard);
|
||||
if(!origin) return true;
|
||||
|
||||
const dest = referenceData?.yard.find((y) => y.id === d.value);
|
||||
// can't go from Djibouti to Djibouti
|
||||
// if(origin.country === 'Djibouti' && dest?.country == 'Djibouti') return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
[yardOptions, originYard],
|
||||
);
|
||||
|
||||
const direction = getRouteDirection(originYard, destinationYard);
|
||||
const direction = getRouteDirection(referenceData?.yard.find((y) => y.id === originYard), referenceData?.yard.find((y) => y.name === destinationYard));
|
||||
|
||||
const directionStyle: Record<string, string> = {
|
||||
export: "bg-sky-50 text-sky-800 border-sky-200",
|
||||
@@ -57,7 +82,7 @@ export function Step4Route({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (direction === "domestic") {
|
||||
if (direction === "DOMESTIC") {
|
||||
form.setValue("shippingLine", "", { shouldDirty: true });
|
||||
}
|
||||
}, [direction]);
|
||||
@@ -117,7 +142,7 @@ export function Step4Route({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{direction && direction !== "domestic" && (
|
||||
{direction && direction !== "DOMESTIC" && (
|
||||
<Controller
|
||||
name="shippingLine"
|
||||
control={form.control}
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
BookingFormInputValues,
|
||||
calcWagons,
|
||||
type BookingFormValues,
|
||||
type RouteDirection,
|
||||
} from "./schema";
|
||||
import {
|
||||
AlertBox,
|
||||
@@ -27,7 +26,7 @@ export function Step5CargoDetails({
|
||||
isLoading,
|
||||
}: {
|
||||
form: BookingForm;
|
||||
direction: RouteDirection;
|
||||
direction: Freight.ScheduleTradeDirection;
|
||||
referenceData?: Freight.BookingReferenceData;
|
||||
isLoading?: boolean;
|
||||
}) {
|
||||
@@ -65,7 +64,7 @@ export function Step5CargoDetails({
|
||||
vgm: number,
|
||||
): string | null {
|
||||
if (type === "20ft" && vgm > 0) {
|
||||
const limit = direction === "export" ? 25 : 20;
|
||||
const limit = direction === "EXPORT" ? 25 : 20;
|
||||
if (vgm > limit) {
|
||||
return `VGM ${vgm}t exceeds the ${limit}t ${direction ?? "standard"} limit for a 20ft container. An Overweight Surcharge will apply.`;
|
||||
}
|
||||
@@ -282,7 +281,7 @@ export function Step5CargoDetails({
|
||||
val: "20ft" as const,
|
||||
label: "20ft Container (TEU)",
|
||||
limit:
|
||||
direction === "export"
|
||||
direction === "EXPORT"
|
||||
? "Max 25t per container"
|
||||
: "Max 20t per container",
|
||||
},
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
BOOKING_DOCS_SETTING,
|
||||
type BookingDocuments,
|
||||
type BookingFormValues,
|
||||
type RouteDirection,
|
||||
} from "./schema";
|
||||
import { StepHeader } from "./shared";
|
||||
import type { Freight } from "@/types";
|
||||
|
||||
type BookingForm = UseFormReturn<BookingFormInputValues, any, BookingFormValues>;
|
||||
|
||||
@@ -18,7 +18,7 @@ export function Step8Review({
|
||||
}: {
|
||||
form: BookingForm;
|
||||
setStep: (step: number) => void;
|
||||
direction: RouteDirection;
|
||||
direction: Freight.ScheduleTradeDirection;
|
||||
}) {
|
||||
const values = form.watch();
|
||||
const errors = form.formState.errors;
|
||||
|
||||
Reference in New Issue
Block a user