Merge branch 'freight_feature/contrat' of github.com:Tria-plc/edr-platform into freight_feature/contrat

This commit is contained in:
marshal
2026-07-01 05:45:46 +03:00
9 changed files with 6 additions and 99 deletions

View File

@@ -200,7 +200,9 @@ export class ContractDocumentViewModelBuilder {
serviceType: this.valueOrDash(
contract.serviceType?.serviceName ?? contract.serviceType?.code,
),
scheduledDate: this.formatDate(contract.estimatedShipmentDate),
// Estimated shipment date was removed from the contract wizard; the
// binding scheduled date is set per-booking, not on the contract.
scheduledDate: this.formatDate(null),
contractType: this.valueOrDash(contract.contractType),
cargoDescription: this.valueOrDash(cargoName),
totalWeightVgm: '—',

View File

@@ -200,9 +200,6 @@ export class ContractsService {
lastMileDeliveryLng: dto.lastMileDeliveryLng ?? null,
isHazardous: dto.isHazardous ?? false,
isReefer: dto.isReefer ?? false,
estimatedShipmentDate: dto.estimatedShipmentDate
? new Date(dto.estimatedShipmentDate)
: null,
contractType: dto.contractType ?? null,
status: 'DRAFT',
clearanceStatus: 'NOT_APPLICABLE',
@@ -347,9 +344,6 @@ export class ContractsService {
lastMileDeliveryLng: dto.lastMileDeliveryLng ?? existing.lastMileDeliveryLng,
contractType: dto.contractType ?? existing.contractType,
};
if (dto.estimatedShipmentDate) {
updates.estimatedShipmentDate = new Date(dto.estimatedShipmentDate);
}
if (dto.renewalOfId !== undefined) updates.renewalOfId = dto.renewalOfId ?? null;
// Customs clearing always mirrors the (possibly changed) service type.

View File

@@ -4,7 +4,6 @@ import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDateString,
IsIn,
IsNumber,
IsOptional,
@@ -219,14 +218,6 @@ export class CreateContractDto {
@Transform(({ value }) => value === 'true' || value === true)
isReefer?: boolean;
@ApiPropertyOptional({
description: 'Non-binding estimate from the wizard (NOT validated against departures)',
example: '2026-07-15T00:00:00.000Z',
})
@IsOptional()
@IsDateString()
estimatedShipmentDate?: string;
@ApiPropertyOptional({ description: 'Contract document type (SPOT, etc.)' })
@IsOptional()
@IsString()

View File

@@ -449,17 +449,6 @@ export default function ContractDetailPage() {
routes[0]?.destinationYard?.label ?? "—"
}`}
/>
<MetaItem
label="Estimated shipment"
icon={<CalendarClock size={15} color={MUTED} />}
value={
contract.estimatedShipmentDate
? new Date(
contract.estimatedShipmentDate,
).toLocaleDateString()
: "—"
}
/>
<MetaItem
label="Customs clearance"
icon={<FileText size={15} color={MUTED} />}

View File

@@ -541,13 +541,6 @@ export default function NewContractPage({
isHazardous: data.isHazardous,
// Reefer is a contract-level flag for both container and bulk.
isReefer: data.isRefrigerated,
...(data.estimatedShipmentDate
? {
estimatedShipmentDate: new Date(
data.estimatedShipmentDate,
).toISOString(),
}
: {}),
...(data.previousContractRef
? { renewalOfId: data.previousContractRef }
: {}),

View File

@@ -16,12 +16,6 @@ function directionToOperation(
return "intercity";
}
/** ISO timestamp → `YYYY-MM-DD` for the native date input. "" when absent. */
function isoToDateInput(iso: string | null | undefined): string {
if (!iso) return "";
return iso.slice(0, 10);
}
/**
* Rebuild the cargo-type path `[groupId, commodityId]` from a flat cargoTypeId
* by locating which reference cargo-type group owns it.
@@ -138,7 +132,6 @@ export function contractToFormValues(
originYard: primaryRoute?.originYardId ?? "",
destinationYard: primaryRoute?.destinationYardId ?? "",
extraRoutes,
estimatedShipmentDate: isoToDateInput(contract.estimatedShipmentDate),
documents: {},
};

View File

@@ -187,8 +187,6 @@ export const contractFormSchema = z
}),
)
.default([]),
// Non-binding estimate. The binding scheduled date is captured at booking.
estimatedShipmentDate: z.string().default(""),
documents: z.record(z.string(), z.any()).default({}),
notes: z.string().default(""),
@@ -222,15 +220,6 @@ export const contractFormSchema = z
},
)
.superRefine((data, ctx) => {
// Estimated shipment date is a planning value and is required for all
// contracts (doc §7 step 4).
if (!data.estimatedShipmentDate.trim()) {
ctx.addIssue({
code: "custom",
path: ["estimatedShipmentDate"],
message: "Select an estimated shipment date.",
});
}
if (data.cargoType === "container") {
// Container scope: at least one enabled size.
if (data.enabledContainerSizes.length === 0) {
@@ -287,7 +276,6 @@ export const initialContractFormValues: DeepPartial<ContractFormValues> = {
originYard: "",
destinationYard: "",
extraRoutes: [],
estimatedShipmentDate: "",
documents: {},
notes: "",
@@ -311,7 +299,7 @@ export const contractStepFields: Record<
"firstMile",
"lastMile",
],
// Step 1 — Cargo & Route: scope, sizes, flags, origin/destination, date.
// Step 1 — Cargo & Route: scope, sizes, flags, origin/destination.
1: [
"cargoType",
"enabledContainerSizes",
@@ -324,7 +312,6 @@ export const contractStepFields: Record<
"originYard",
"destinationYard",
"extraRoutes",
"estimatedShipmentDate",
],
// Step 2 — Review & Submit. (The separate Documents step was removed — the
// company profile documents are attached to the contract automatically.)

View File

@@ -1,6 +1,6 @@
import type { Freight } from "@edr/types";
import { Box, Button, Group, Skeleton, Stack, Text, TextInput } from "@mantine/core";
import { CalendarDays, MapPin, Plus, Trash2 } from "lucide-react";
import { Box, Button, Group, Skeleton, Stack, Text } from "@mantine/core";
import { MapPin, Plus, Trash2 } from "lucide-react";
import { useCallback, useEffect, useMemo } from "react";
import {
Controller,
@@ -125,12 +125,6 @@ export function Step4Route({
const stationSelectDisabled = yardOptions.length === 0;
const todayISODate = useMemo(() => {
const now = new Date();
const tz = now.getTimezoneOffset() * 60000;
return new Date(now.getTime() - tz).toISOString().slice(0, 10);
}, []);
return (
<Stack gap={16}>
{isLoading ? (
@@ -177,27 +171,6 @@ export function Step4Route({
</div>
)}
{/* Estimated shipment date — a planning value for every contract. The
binding scheduled date is captured later at booking time. */}
<Box style={{ maxWidth: 280 }}>
<Controller
name="estimatedShipmentDate"
control={form.control}
render={({ field, fieldState }) => (
<TextInput
type="date"
label="Estimated shipment date *"
description="A non-binding planning estimate. The actual shipment date is chosen when you book against this contract."
min={todayISODate}
leftSection={<CalendarDays size={16} />}
error={fieldState.error?.message}
value={field.value ?? ""}
onChange={(e) => field.onChange(e.currentTarget.value)}
radius="md"
/>
)}
/>
</Box>
</div>
)}

View File

@@ -9,9 +9,7 @@ import {
Text,
Textarea,
} from "@mantine/core";
import { format } from "date-fns";
import {
Calendar,
CheckCircle2,
Circle,
ClipboardCheck,
@@ -248,10 +246,6 @@ export function Step8Review({
referenceData?.yard.find((y) => y.id === values.destinationYard)?.name ??
values.destinationYard;
const scheduleLabel = values.estimatedShipmentDate
? format(new Date(values.estimatedShipmentDate), "EEEE, MMM d, yyyy")
: "—";
const directionLabel = direction
? direction.charAt(0) + direction.slice(1).toLowerCase()
: "—";
@@ -353,11 +347,6 @@ export function Step8Review({
: directionLabel
}
/>
<SummaryItem
icon={<Calendar size={18} />}
label="Estimated shipment"
value={scheduleLabel}
/>
<SummaryItem
icon={<Package size={18} />}
label="Cargo scope"
@@ -485,10 +474,6 @@ export function Step8Review({
done={Boolean(values.originYard && values.destinationYard)}
label="Route selected"
/>
<ReadinessItem
done={Boolean(values.estimatedShipmentDate)}
label="Estimated date selected"
/>
<ReadinessItem
done={
values.cargoType === "container"