mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-09 07:08:20 +00:00
feat: add read-only SeafarerScopeFields component to profile page for displaying certification scope details
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
displaySeafarerAnswer,
|
||||
useGetActiveDepartmentsQuery,
|
||||
useGetMySeafarerRegistrationQuery,
|
||||
useLocalized,
|
||||
} from '@ema-platform/api';
|
||||
import { PORTAL_PERMISSIONS, usePermissions } from '@ema-platform/auth';
|
||||
|
||||
/**
|
||||
* Department and STCW limitation, read-only.
|
||||
*
|
||||
* Answered once in the registration wizard and never again, yet between them
|
||||
* they decide which certificates, examinations and services the portal offers
|
||||
* — so a seafarer has to be able to see what they are without reopening a
|
||||
* submitted registration. Not editable here on purpose: either answer moves
|
||||
* the applicant onto a different CoC ladder, which is EMA's decision on
|
||||
* review, not a profile edit.
|
||||
*
|
||||
* `tier` lives only on the registration record — the profile carries the
|
||||
* department alone (`seafarerDepartment`) — so the registration is the source
|
||||
* for both, with the profile's department as the fallback for an account whose
|
||||
* registration is not readable.
|
||||
*/
|
||||
export function SeafarerScopeFields({
|
||||
fallbackDepartment,
|
||||
}: {
|
||||
/** `profile.seafarerDepartment`, used when no registration comes back. */
|
||||
fallbackDepartment?: string | null;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const localized = useLocalized();
|
||||
// Same permission the registration page and `/seafarer-registrations/mine`
|
||||
// are behind — asking without it would only 403.
|
||||
const { can } = usePermissions();
|
||||
const mayRegister = can([PORTAL_PERMISSIONS.APPLY_SEAFARER_REGISTRATION]);
|
||||
const { data, isLoading } = useGetMySeafarerRegistrationQuery(undefined, {
|
||||
skip: !mayRegister,
|
||||
});
|
||||
const registration = data?.registration ?? null;
|
||||
|
||||
const department = registration?.department ?? fallbackDepartment ?? null;
|
||||
const tier = registration?.tier ?? null;
|
||||
|
||||
// Live department names, so a department configured after this release still
|
||||
// shows its own name — the same list the registration wizard picks from.
|
||||
const { data: departments } = useGetActiveDepartmentsQuery(undefined, { skip: !department });
|
||||
const departmentOptions = departments?.map((d) => ({ value: d.code, label: localized(d.name) }));
|
||||
|
||||
// Nothing recorded yet — the registration wizard is where these are answered.
|
||||
if (isLoading || (!department && !tier)) return null;
|
||||
|
||||
return (
|
||||
<Paper p="xl" mt="md" shadow="sm" radius="lg" withBorder>
|
||||
<Stack gap="md">
|
||||
<div>
|
||||
<Title order={5}>{t('profile.seafarerScope.title')}</Title>
|
||||
<Text size="sm" c="dimmed">
|
||||
{t('profile.seafarerScope.subtitle')}
|
||||
</Text>
|
||||
</div>
|
||||
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="md">
|
||||
<TextInput
|
||||
label={t('profile.seafarerScope.department')}
|
||||
readOnly
|
||||
variant="filled"
|
||||
value={department ? displaySeafarerAnswer('department', department, departmentOptions) : '—'}
|
||||
/>
|
||||
<TextInput
|
||||
label={t('profile.seafarerScope.tier')}
|
||||
readOnly
|
||||
variant="filled"
|
||||
value={tier ? t(`profile.seafarerScope.tiers.${tier}`) : '—'}
|
||||
description={
|
||||
tier
|
||||
? department === 'ENGINE'
|
||||
? t('profile.seafarerScope.tierHintEngine')
|
||||
: t('profile.seafarerScope.tierHintDeck')
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
{registration && registration.status !== 'APPROVED' && (
|
||||
<Text size="xs" c="dimmed">
|
||||
{t('profile.seafarerScope.pending')}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
@@ -68,6 +68,7 @@ import {
|
||||
import { useSaveMyAddressMutation } from '../api/address-api';
|
||||
import { toAddressPayload } from '../types/address';
|
||||
import { OperationsFormContent } from '../components/OperationsFormContent';
|
||||
import { SeafarerScopeFields } from '../components/SeafarerScopeFields';
|
||||
import { MySignaturePad } from '../components/SignaturePad';
|
||||
import { SEAFARER_PROFILE_REQUIREMENT } from '../components/RequireSeafarerProfile';
|
||||
import classes from './ProfilePage.module.css';
|
||||
@@ -768,6 +769,12 @@ export function ProfilePage() {
|
||||
</form>
|
||||
)}
|
||||
</Paper>
|
||||
|
||||
{/* Department and STCW limitation — answered at registration, shown
|
||||
here because they decide which certificates apply. */}
|
||||
<SeafarerScopeFields
|
||||
fallbackDepartment={(resolvedProfile ?? storedProfile)?.seafarerDepartment}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
|
||||
{/* ---- Address ---- */}
|
||||
|
||||
@@ -464,6 +464,21 @@ export const am: Translations = {
|
||||
noProfile: 'ምንም መገለጫ አልተገኘም። መጀመሪያ መገለጫዎን ያጠናቅቁ።',
|
||||
save: 'መገለጫ አስቀምጥ',
|
||||
},
|
||||
seafarerScope: {
|
||||
title: 'የምስክር ወረቀት ወሰን',
|
||||
subtitle:
|
||||
'እንደ መርከበኛ በተመዘገቡበት ጊዜ የተመዘገበ። አንድ ላይ የትኞቹ የምስክር ወረቀቶች፣ ፈተናዎችና አገልግሎቶች እንደሚመለከቱዎት ይወስናሉ — ለመቀየር EMAን ያነጋግሩ።',
|
||||
department: 'ክፍል',
|
||||
tier: 'የማዕረግ ደረጃ',
|
||||
tiers: {
|
||||
ABOVE: 'ከላይ',
|
||||
BELOW: 'ከታች',
|
||||
},
|
||||
tierHintDeck: 'ከላይ 3,000 ጠቅላላ ቶን እና ከዚያ በላይ የሆኑ መርከቦችን ይሸፍናል፤ ከታች ከ500–3,000 ጠቅላላ ቶን ይሸፍናል።',
|
||||
tierHintEngine:
|
||||
'ከላይ 3,000 ኪ.ዋ እና ከዚያ በላይ የማንቀሳቀሻ ኃይል ያላቸውን መርከቦች ይሸፍናል፤ ከታች ከ750–3,000 ኪ.ዋ ይሸፍናል።',
|
||||
pending: 'ገና ካልጸደቀው የመርከበኛ ምዝገባዎ የተወሰደ።',
|
||||
},
|
||||
addressSection: {
|
||||
title: 'አድራሻ እና መገናኛ',
|
||||
subtitle: 'የመታወቂያ ሰነዶችዎ፣ የመገናኛ ዝርዝሮችዎ እና የአደጋ ጊዜ ተጠሪ',
|
||||
|
||||
@@ -470,6 +470,22 @@ export const en = {
|
||||
noProfile: 'No profile found. Complete your profile setup first.',
|
||||
save: 'Save Profile',
|
||||
},
|
||||
seafarerScope: {
|
||||
title: 'Certification Scope',
|
||||
subtitle:
|
||||
'Recorded when you registered as a seafarer. Together they decide which certificates, examinations and services apply to you — contact EMA to change either.',
|
||||
department: 'Department',
|
||||
tier: 'Certificate Limitation',
|
||||
tiers: {
|
||||
ABOVE: 'Above',
|
||||
BELOW: 'Below',
|
||||
},
|
||||
tierHintDeck:
|
||||
'Above covers ships of 3,000 gross tonnage or more; Below covers 500–3,000 GT.',
|
||||
tierHintEngine:
|
||||
'Above covers ships of 3,000 kW propulsion power or more; Below covers 750–3,000 kW.',
|
||||
pending: 'From your seafarer registration, which is not approved yet.',
|
||||
},
|
||||
addressSection: {
|
||||
title: 'Address & Contact',
|
||||
subtitle: 'Your identity documents, contact details and emergency contact',
|
||||
|
||||
Reference in New Issue
Block a user