mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 11:08:12 +00:00
train gate pass, Telebirr and Wafi
This commit is contained in:
@@ -9,6 +9,8 @@ import {
|
||||
RingProgress,
|
||||
Stack,
|
||||
Text,
|
||||
Textarea,
|
||||
TextInput,
|
||||
ThemeIcon,
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
@@ -88,6 +90,10 @@ export default function TrainScheduleV2DetailPage() {
|
||||
const [previewResult, setPreviewResult] = useState<TrainSchedulePreviewResponse | null>(null);
|
||||
const [containerPlacements, setContainerPlacements] = useState<ContainerPlacement[]>([]);
|
||||
const [maintenanceOpen, setMaintenanceOpen] = useState(false);
|
||||
const [gatepassSecuredAt, setGatepassSecuredAt] = useState("");
|
||||
const [gatepassReference, setGatepassReference] = useState("");
|
||||
const [gatepassFileUrl, setGatepassFileUrl] = useState("");
|
||||
const [gatepassNotes, setGatepassNotes] = useState("");
|
||||
const autoPreviewedRef = useRef(false);
|
||||
|
||||
const detailQuery = useQuery(
|
||||
@@ -98,6 +104,42 @@ export default function TrainScheduleV2DetailPage() {
|
||||
);
|
||||
const schedule = detailQuery.data;
|
||||
const freightType: FreightType | undefined = schedule?.freightType as FreightType | undefined;
|
||||
const isDjiboutiPort = (value?: string | null) =>
|
||||
["DJIBOUTI", "DORALEH", "DMP", "DCT", "NAGAD"].some((token) =>
|
||||
(value ?? "").toUpperCase().includes(token),
|
||||
);
|
||||
const gatepassApplies = Boolean(
|
||||
schedule &&
|
||||
((schedule.direction === "IMPORT" &&
|
||||
isDjiboutiPort(`${schedule.originStation?.code ?? ""} ${schedule.originStation?.label ?? ""}`)) ||
|
||||
(schedule.direction === "EXPORT" &&
|
||||
isDjiboutiPort(`${schedule.destinationStation?.code ?? ""} ${schedule.destinationStation?.label ?? ""}`))),
|
||||
);
|
||||
const gatepassQuery = useQuery({
|
||||
queryKey: ["train-scheduling", "gatepass", scheduleId],
|
||||
queryFn: () => trainSchedulingService.getImportDjiboutiOperation(scheduleId as string),
|
||||
enabled: Boolean(scheduleId && gatepassApplies),
|
||||
});
|
||||
const secureGatepass = useMutation({
|
||||
mutationFn: () =>
|
||||
trainSchedulingService.grantImportDjiboutiGatepass(scheduleId as string, {
|
||||
securedAt: gatepassSecuredAt ? new Date(gatepassSecuredAt).toISOString() : undefined,
|
||||
reference: gatepassReference.trim() || undefined,
|
||||
fileUrl: gatepassFileUrl.trim() || undefined,
|
||||
notes: gatepassNotes.trim() || undefined,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
toast({ title: "Gate pass secured" });
|
||||
void gatepassQuery.refetch();
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Gate pass failed",
|
||||
description: parseError(error, "Could not secure gate pass"),
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const eligibleFilters = useMemo(
|
||||
() =>
|
||||
@@ -133,6 +175,16 @@ export default function TrainScheduleV2DetailPage() {
|
||||
: trainSchedulingService.downloadImportDjiboutiLoadListDocument(id),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const operation = gatepassQuery.data;
|
||||
if (!operation) return;
|
||||
const secured = operation.gatepassSecuredAt ?? operation.gatepassGrantedAt;
|
||||
setGatepassSecuredAt(secured ? new Date(secured).toISOString().slice(0, 16) : "");
|
||||
setGatepassReference(operation.documents?.GATE_PASS?.reference ?? "");
|
||||
setGatepassFileUrl(operation.documents?.GATE_PASS?.fileUrl ?? "");
|
||||
setGatepassNotes(operation.documents?.GATE_PASS?.notes ?? operation.notes ?? "");
|
||||
}, [gatepassQuery.data]);
|
||||
|
||||
const assignedIds = useMemo(
|
||||
() => (schedule?.bookings ?? []).map((b) => b.id),
|
||||
[schedule?.bookings],
|
||||
@@ -899,6 +951,83 @@ export default function TrainScheduleV2DetailPage() {
|
||||
]}
|
||||
/>
|
||||
|
||||
{gatepassApplies ? (
|
||||
<Paper radius="xl" p="lg" withBorder>
|
||||
<Stack gap="md">
|
||||
<Group justify="space-between" align="flex-start" wrap="wrap">
|
||||
<Group gap="md" align="flex-start" wrap="nowrap">
|
||||
<ThemeIcon
|
||||
size={44}
|
||||
radius="md"
|
||||
variant="light"
|
||||
color={gatepassQuery.data?.gatepassStatus === "SECURED" ? "edr-green" : "orange"}
|
||||
>
|
||||
<FileText size={22} />
|
||||
</ThemeIcon>
|
||||
<Stack gap={4}>
|
||||
<Group gap="sm">
|
||||
<Title order={4} fw={700}>
|
||||
Djibouti Port gate pass
|
||||
</Title>
|
||||
<Badge
|
||||
color={gatepassQuery.data?.gatepassStatus === "SECURED" ? "green" : "orange"}
|
||||
variant="light"
|
||||
>
|
||||
{gatepassQuery.data?.gatepassStatus ?? "NOT_SECURED"}
|
||||
</Badge>
|
||||
</Group>
|
||||
<Text size="sm" c="dimmed">
|
||||
{schedule.direction === "IMPORT"
|
||||
? "Secure before dispatch from Djibouti."
|
||||
: "Secure after dispatch before Djibouti Port entry / unloading."}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Group>
|
||||
{gatepassQuery.isLoading ? <Loader size="sm" /> : null}
|
||||
</Group>
|
||||
|
||||
<Group align="flex-end" grow>
|
||||
<TextInput
|
||||
label="Secured date"
|
||||
type="datetime-local"
|
||||
value={gatepassSecuredAt}
|
||||
onChange={(event) => setGatepassSecuredAt(event.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Document reference"
|
||||
placeholder="Optional"
|
||||
value={gatepassReference}
|
||||
onChange={(event) => setGatepassReference(event.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Document URL"
|
||||
placeholder="Optional upload/link"
|
||||
value={gatepassFileUrl}
|
||||
onChange={(event) => setGatepassFileUrl(event.currentTarget.value)}
|
||||
/>
|
||||
</Group>
|
||||
<Textarea
|
||||
label="Notes"
|
||||
placeholder="Optional"
|
||||
autosize
|
||||
minRows={2}
|
||||
value={gatepassNotes}
|
||||
onChange={(event) => setGatepassNotes(event.currentTarget.value)}
|
||||
/>
|
||||
<Group justify="flex-end">
|
||||
<Button
|
||||
color="edr-green"
|
||||
leftSection={<CheckCircle2 size={16} />}
|
||||
loading={secureGatepass.isPending}
|
||||
onClick={() => secureGatepass.mutate()}
|
||||
>
|
||||
Save as Secured
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
) : null}
|
||||
|
||||
<Paper radius="xl" p="lg">
|
||||
<Stack gap="lg">
|
||||
{/* Workflow header with ring progress */}
|
||||
|
||||
Reference in New Issue
Block a user