mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
feat: add in-flight registration application tracking and status dashboard to vessel registration page
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
@@ -8,6 +9,7 @@ import {
|
||||
Divider,
|
||||
Group,
|
||||
Paper,
|
||||
Progress,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
@@ -25,13 +27,24 @@ import {
|
||||
IconInfoCircle,
|
||||
IconClockHour4,
|
||||
IconTransferIn,
|
||||
IconArrowRight,
|
||||
} from '@tabler/icons-react';
|
||||
import { useApiMutation } from '@ema-platform/api';
|
||||
import {
|
||||
STATUS_COLORS,
|
||||
STATUS_LABELS,
|
||||
STATUS_PROGRESS,
|
||||
TERMINAL_STATUSES,
|
||||
useApiMutation,
|
||||
useGetMyApplicationsQuery,
|
||||
} from '@ema-platform/api';
|
||||
import { authStorage } from '@ema-platform/auth';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Registration applications run through the config-driven licensing wizard. */
|
||||
const REGISTRATION_TYPE_KEY = 'VESSEL_REGISTRATION';
|
||||
|
||||
type VesselRegStatus = 'Pending' | 'Under Review' | 'Approved' | 'Rejected' | 'Correction Required';
|
||||
type VesselCategory = 'Inland Waterway Vessel' | 'Sea-going Vessel (International)';
|
||||
type RenewalStatus = 'Valid' | 'Due Soon' | 'Overdue' | 'Not Applicable';
|
||||
@@ -118,6 +131,8 @@ function CertificateCard({ label, description }: { label: string; description: s
|
||||
// ---------------------------------------------------------------------------
|
||||
export function VesselRegistrationPage() {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const { data: applications } = useGetMyApplicationsQuery();
|
||||
const [registration, setRegistration] = useState<VesselRegistration | null>(null);
|
||||
const [fetchTrigger] = useApiMutation<VesselRegistration>();
|
||||
const fetched = useRef(false);
|
||||
@@ -132,6 +147,14 @@ export function VesselRegistrationPage() {
|
||||
.catch(() => {/* no registration yet */});
|
||||
}, [fetchTrigger]);
|
||||
|
||||
// Drafts and anything still moving through review — the applicant's own
|
||||
// registration applications, straight from the licensing queue.
|
||||
const inFlight = (applications?.items ?? []).filter(
|
||||
(app) =>
|
||||
app.licenseType?.key === REGISTRATION_TYPE_KEY &&
|
||||
!TERMINAL_STATUSES.includes(app.status),
|
||||
);
|
||||
|
||||
const certs = registration?.category === 'Sea-going Vessel (International)'
|
||||
? SEAGOING_CERTIFICATES
|
||||
: INLAND_CERTIFICATES;
|
||||
@@ -148,6 +171,54 @@ export function VesselRegistrationPage() {
|
||||
</div>
|
||||
</Group>
|
||||
|
||||
{/* ── Drafts / submitted applications ───────────────────────────── */}
|
||||
{inFlight.length > 0 && (
|
||||
<Stack gap="sm">
|
||||
<Text fw={700} fz="md">{t('vesselRegistration.inFlight.title')}</Text>
|
||||
{inFlight.map((app) => {
|
||||
const isDraft = app.status === 'DRAFT';
|
||||
const needsAction = app.status === 'RESUBMIT_REQUIRED';
|
||||
return (
|
||||
<Card key={app.id} withBorder radius="md" p="md">
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<div>
|
||||
<Group gap="xs">
|
||||
<Text fw={600}>{app.applicationNumber}</Text>
|
||||
{app.kind === 'RENEWAL' && (
|
||||
<Badge size="sm" variant="light">
|
||||
{t('vesselRegistration.inFlight.renewalBadge')}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
<Progress value={STATUS_PROGRESS[app.status]} mt="xs" w={260} />
|
||||
</div>
|
||||
<Group wrap="nowrap">
|
||||
<Badge color={STATUS_COLORS[app.status]}>
|
||||
{STATUS_LABELS[app.status]}
|
||||
</Badge>
|
||||
<Button
|
||||
size="compact-sm"
|
||||
variant={needsAction ? 'filled' : 'light'}
|
||||
color={needsAction ? 'orange' : undefined}
|
||||
rightSection={<IconArrowRight size={14} />}
|
||||
onClick={() =>
|
||||
navigate(`/licensing/${REGISTRATION_TYPE_KEY}/applications/${app.id}`)
|
||||
}
|
||||
>
|
||||
{isDraft
|
||||
? t('common.continue')
|
||||
: needsAction
|
||||
? t('vesselRegistration.inFlight.fix')
|
||||
: t('vesselRegistration.inFlight.view')}
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{/* ── No registration yet ───────────────────────────────────────── */}
|
||||
{!registration && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user