From 3e94aa08f15b0b9da95a194a4ef4b1653c6d5f04 Mon Sep 17 00:00:00 2001 From: Marshal Date: Sat, 4 Jul 2026 04:22:03 +0000 Subject: [PATCH] update joins in repository services to use entity classes and enhance booking form with hazardous/reefer toggles --- .../new-booking-form/step5-cargo-details.tsx | 142 ++++++++++++------ 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/apps/edr-freight-web/portal/src/pages/bookings/new-booking-form/step5-cargo-details.tsx b/apps/edr-freight-web/portal/src/pages/bookings/new-booking-form/step5-cargo-details.tsx index a02138373..ac336c47c 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/new-booking-form/step5-cargo-details.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/new-booking-form/step5-cargo-details.tsx @@ -26,6 +26,70 @@ type BookingForm = UseFormReturn< BookingFormValues >; +/** + * One numbered toggle per container unit in the line โ€” tap units to mark how + * many are hazardous/refrigerated (2 hazardous โ†’ toggle 2 units on). Selection + * fills from unit 1: tapping unit N selects 1..N, tapping a selected unit N + * keeps 1..N-1 โ€” the count is always derived, never free-typed, so it can't + * exceed the line quantity. + */ +function UnitCountToggles({ + total, + value, + onChange, + label, + activeBg, + activeBorder, + activeColor, +}: { + total: number; + value: string; + onChange: (v: string) => void; + label: string; + activeBg: string; + activeBorder: string; + activeColor: string; +}) { + const count = Math.min(total, Math.max(0, Math.floor(Number(value) || 0))); + + return ( +
+ + {label} ยท {count}/{total} selected + +
+ {Array.from({ length: total }, (_, i) => { + const selected = i < count; + return ( + + ); + })} +
+
+ ); +} + export function Step5CargoDetails({ form, referenceData, @@ -144,16 +208,6 @@ export function Step5CargoDetails({ const lineQtyOf = (index: number) => Math.max(1, Number(form.getValues(`containers.${index}.qty`) ?? 1) || 1); const lineMax = (index: number) => lineQtyOf(index); - // When a flag is switched on, default its count to the whole line. - const defaultLineQty = (index: number) => lineQtyOf(index).toString(); - // Clamp a typed value into 1..lineQty (empty stays empty so the field can be - // cleared; the schema flags an empty value as required while the switch is on). - const clampToLine = (raw: string, index: number) => { - if (raw === "") return ""; - const n = Number(raw); - if (Number.isNaN(n)) return raw; - return Math.min(lineQtyOf(index), Math.max(1, Math.floor(n))).toString(); - }; // After the line quantity changes, pull any active count back within bounds. const clampDependentQty = (index: number, newLineQty: number) => { const max = Math.max(1, newLineQty); @@ -636,7 +690,7 @@ export function Step5CargoDetails({ hazField.onChange(v); form.setValue( `containers.${index}.hazardousQty`, - v ? defaultLineQty(index) : "0", + v ? "1" : "0", { shouldDirty: true, shouldValidate: true }, ); }} @@ -645,22 +699,22 @@ export function Step5CargoDetails({ name={`containers.${index}.hazardousQty`} control={form.control} render={({ field: hq, fieldState }) => ( - - hq.onChange( - clampToLine(e.currentTarget.value, index), - ) - } - onBlur={hq.onBlur} - error={fieldState.error?.message} - radius="md" - /> +
+ + {fieldState.error?.message ? ( + + {fieldState.error.message} + + ) : null} +
)} /> @@ -681,7 +735,7 @@ export function Step5CargoDetails({ reeField.onChange(v); form.setValue( `containers.${index}.reeferQty`, - v ? defaultLineQty(index) : "0", + v ? "1" : "0", { shouldDirty: true, shouldValidate: true }, ); }} @@ -690,22 +744,22 @@ export function Step5CargoDetails({ name={`containers.${index}.reeferQty`} control={form.control} render={({ field: rq, fieldState }) => ( - - rq.onChange( - clampToLine(e.currentTarget.value, index), - ) - } - onBlur={rq.onBlur} - error={fieldState.error?.message} - radius="md" - /> +
+ + {fieldState.error?.message ? ( + + {fieldState.error.message} + + ) : null} +
)} />