mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 07:38:10 +00:00
Merge branch 'freight_feature/contrat' of github.com:Tria-plc/edr-platform into freight_feature/contrat
This commit is contained in:
@@ -110,11 +110,12 @@ export function ContractClearanceReviewSection({
|
|||||||
(clearance?.documents ?? []).filter((d) => d.uploadedBy === "customer"),
|
(clearance?.documents ?? []).filter((d) => d.uploadedBy === "customer"),
|
||||||
[clearance],
|
[clearance],
|
||||||
);
|
);
|
||||||
|
// GL output documents — anything not uploaded by the customer. The backend
|
||||||
|
// tags these `uploadedBy: 'gl'`; matching on "not customer" keeps it robust if
|
||||||
|
// that ever splits into gl_et / gl_dj.
|
||||||
const glDocs = useMemo(
|
const glDocs = useMemo(
|
||||||
() =>
|
() =>
|
||||||
(clearance?.documents ?? []).filter(
|
(clearance?.documents ?? []).filter((d) => d.uploadedBy !== "customer"),
|
||||||
(d) => d.uploadedBy === "gl_et" || d.uploadedBy === "gl_dj",
|
|
||||||
),
|
|
||||||
[clearance],
|
[clearance],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,11 @@ function ClearanceHero({
|
|||||||
stats: { pct: number; approved: number; total: number };
|
stats: { pct: number; approved: number; total: number };
|
||||||
}) {
|
}) {
|
||||||
const direction = contract?.tradeDirection ?? "—";
|
const direction = contract?.tradeDirection ?? "—";
|
||||||
|
const serviceName = contract?.serviceType?.serviceName ?? null;
|
||||||
|
const customs =
|
||||||
|
contract?.serviceType?.includesCustoms ??
|
||||||
|
contract?.customsClearingEnabled ??
|
||||||
|
false;
|
||||||
const routes = [...(contract?.routes ?? [])].sort(
|
const routes = [...(contract?.routes ?? [])].sort(
|
||||||
(a, b) => a.sortOrder - b.sortOrder,
|
(a, b) => a.sortOrder - b.sortOrder,
|
||||||
);
|
);
|
||||||
@@ -253,16 +258,27 @@ function ClearanceHero({
|
|||||||
>
|
>
|
||||||
{direction}
|
{direction}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge
|
{customs ? (
|
||||||
size="sm"
|
<Badge
|
||||||
variant="light"
|
size="sm"
|
||||||
color="edr-green"
|
variant="light"
|
||||||
radius="sm"
|
color="edr-green"
|
||||||
leftSection={<ShieldCheck size={12} />}
|
radius="sm"
|
||||||
>
|
leftSection={<ShieldCheck size={12} />}
|
||||||
Customs
|
>
|
||||||
</Badge>
|
Customs
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge size="sm" variant="light" color="gray" radius="sm">
|
||||||
|
No customs
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
|
{serviceName && (
|
||||||
|
<Text size="sm" fw={600} c="edr-text" mt={6} truncate maw={280}>
|
||||||
|
{serviceName}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
<Group gap={8} mt={6} wrap="nowrap">
|
<Group gap={8} mt={6} wrap="nowrap">
|
||||||
<Text size="sm" fw={600} truncate maw={160}>
|
<Text size="sm" fw={600} truncate maw={160}>
|
||||||
{origin}
|
{origin}
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ interface ClearanceRow {
|
|||||||
originLabel: string;
|
originLabel: string;
|
||||||
destinationLabel: string;
|
destinationLabel: string;
|
||||||
contractKind: string;
|
contractKind: string;
|
||||||
|
serviceTypeName: string;
|
||||||
|
customs: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
/** true once GL has finalized clearance — customer now books in the portal. */
|
/** true once GL has finalized clearance — customer now books in the portal. */
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
@@ -84,11 +86,32 @@ function toClearanceRow(contract: Freight.IContract): ClearanceRow {
|
|||||||
originLabel: yardLabel(first?.originYard),
|
originLabel: yardLabel(first?.originYard),
|
||||||
destinationLabel: yardLabel(last?.destinationYard),
|
destinationLabel: yardLabel(last?.destinationYard),
|
||||||
contractKind: contract.contractKind,
|
contractKind: contract.contractKind,
|
||||||
|
serviceTypeName: contract.serviceType?.serviceName ?? "—",
|
||||||
|
customs:
|
||||||
|
contract.serviceType?.includesCustoms ?? contract.customsClearingEnabled,
|
||||||
status: contract.status,
|
status: contract.status,
|
||||||
ready: contract.status === "CLEARANCE_READY_FOR_BOOKING",
|
ready: contract.status === "CLEARANCE_READY_FOR_BOOKING",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CustomsBadge({ customs }: { customs: boolean }) {
|
||||||
|
return customs ? (
|
||||||
|
<Badge
|
||||||
|
size="xs"
|
||||||
|
variant="light"
|
||||||
|
color="edr-green"
|
||||||
|
radius="sm"
|
||||||
|
leftSection={<ShieldCheck size={11} />}
|
||||||
|
>
|
||||||
|
Customs
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge size="xs" variant="light" color="gray" radius="sm">
|
||||||
|
No customs
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function DirectionIcon({ direction }: { direction: string }) {
|
function DirectionIcon({ direction }: { direction: string }) {
|
||||||
const isImport = direction === "IMPORT";
|
const isImport = direction === "IMPORT";
|
||||||
const Icon = isImport ? Truck : ShipWheel;
|
const Icon = isImport ? Truck : ShipWheel;
|
||||||
@@ -248,6 +271,21 @@ export default function ContractClearanceListPage() {
|
|||||||
</Badge>
|
</Badge>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "service",
|
||||||
|
header: () => <span className={bookingTable.headerCell}>Service</span>,
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const r = row.original;
|
||||||
|
return (
|
||||||
|
<Stack gap={4} py={2} style={{ minWidth: 0 }}>
|
||||||
|
<Text size="sm" fw={500} truncate maw={160}>
|
||||||
|
{r.serviceTypeName}
|
||||||
|
</Text>
|
||||||
|
<CustomsBadge customs={r.customs} />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "status",
|
id: "status",
|
||||||
header: () => <span className={bookingTable.headerCell}>Status</span>,
|
header: () => <span className={bookingTable.headerCell}>Status</span>,
|
||||||
@@ -545,6 +583,13 @@ function ClearanceCard({
|
|||||||
{row.contractKind === "GENERAL" ? "General" : "One-time"}
|
{row.contractKind === "GENERAL" ? "General" : "One-time"}
|
||||||
</Badge>
|
</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
<Group justify="space-between" mt={8} wrap="nowrap" gap={8}>
|
||||||
|
<Text size="xs" c="dimmed" truncate maw={150}>
|
||||||
|
{row.serviceTypeName}
|
||||||
|
</Text>
|
||||||
|
<CustomsBadge customs={row.customs} />
|
||||||
|
</Group>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ export interface ContractClearanceDocument {
|
|||||||
fileKey: string;
|
fileKey: string;
|
||||||
label: string;
|
label: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
uploadedBy: "customer" | "gl_et" | "gl_dj";
|
uploadedBy: "customer" | "gl" | "gl_et" | "gl_dj";
|
||||||
phase: ContractDocPhase;
|
phase: ContractDocPhase;
|
||||||
settingCode: string;
|
settingCode: string;
|
||||||
file: { id: string; name: string; url: string } | null;
|
file: { id: string; name: string; url: string } | null;
|
||||||
@@ -406,6 +406,14 @@ export interface IContract extends BaseEntity {
|
|||||||
freightType: ContractFreightType;
|
freightType: ContractFreightType;
|
||||||
|
|
||||||
serviceTypeId: string;
|
serviceTypeId: string;
|
||||||
|
/** Loaded service-type relation (queue + detail responses include it). */
|
||||||
|
serviceType?: {
|
||||||
|
id: string;
|
||||||
|
code: string;
|
||||||
|
serviceName: string;
|
||||||
|
canBeBookedAlone: boolean;
|
||||||
|
includesCustoms: boolean;
|
||||||
|
} | null;
|
||||||
paymentCurrency: string;
|
paymentCurrency: string;
|
||||||
customsClearingEnabled: boolean;
|
customsClearingEnabled: boolean;
|
||||||
customsClearingAgent?: string | null;
|
customsClearingAgent?: string | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user