Files
emaui/apps/backoffice/src/app/features/configuration/components/StcwMappingPanel.tsx
fitse-yotor 0ac75669d4 feat: add ExamStageActions component for exam fee handling
- Implemented ExamStageActions component to manage actions related to exam booking and payment based on application status.
- Added mock-base-query for development, providing a partial mock backend for various API endpoints.
- Introduced mock-data for simulating responses in the mock-base-query, covering profiles, vessels, applications, licenses, exams, and notifications.
2026-08-15 11:51:14 +03:00

160 lines
5.4 KiB
TypeScript

import { Badge, Group, Paper, Stack, Table, Text } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { useLocalized, type LicenseType } from '@ema-platform/api';
interface Props {
licenseType: LicenseType;
}
/**
* The STCW identity of a certificate type — regulation, level, and the
* function and capacity rows a Certificate of Competency prints.
*
* Read-only for now: these are seeded configuration, and editing them safely
* needs the approval workflow the designer guide describes. Showing them
* matters regardless — an officer configuring fees or documents has no other
* way to see what the certificate will actually claim.
*/
export function StcwMappingPanel({ licenseType }: Props) {
const { t } = useTranslation();
const localized = useLocalized();
if (!licenseType.stcwControlled && !licenseType.certificateCategory) {
return null;
}
const functions = licenseType.stcwFunctions ?? [];
const capacities = licenseType.stcwCapacities ?? [];
return (
<Paper withBorder p="md" radius="md">
<Stack gap="sm">
<Group gap="xs">
<Text fw={600} size="sm">
{t('configuration.stcw.title', 'STCW mapping')}
</Text>
{licenseType.certificateCategory && (
<Badge size="sm" variant="light">
{licenseType.certificateCategory}
</Badge>
)}
{licenseType.stcwControlled && (
<Badge size="sm" variant="light" color="teal">
{t('configuration.stcw.controlled', 'STCW controlled')}
</Badge>
)}
</Group>
<Group gap="xl">
<Field
label={t('configuration.stcw.regulation', 'Regulation')}
value={licenseType.stcwRegulation}
/>
<Field
label={t('configuration.stcw.codeSection', 'Code section')}
value={licenseType.stcwCodeSection}
/>
<Field
label={t('configuration.stcw.department', 'Department')}
value={licenseType.stcwDepartment}
/>
<Field
label={t('configuration.stcw.level', 'Level')}
value={licenseType.competencyLevel}
/>
</Group>
{functions.length > 0 && (
<Stack gap={4}>
<Text size="xs" c="dimmed" tt="uppercase" fw={700}>
{t('configuration.stcw.functions', 'Functions')}
</Text>
<Table withTableBorder withColumnBorders fz="xs">
<Table.Thead>
<Table.Tr>
<Table.Th>{t('configuration.stcw.function', 'Function')}</Table.Th>
<Table.Th>{t('configuration.stcw.level', 'Level')}</Table.Th>
<Table.Th>
{t('configuration.stcw.limitation', 'Limitation')}
</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{functions.map((row, i) => (
<Table.Tr key={`${localized(row.function)}-${i}`}>
<Table.Td>{localized(row.function)}</Table.Td>
<Table.Td>{row.level}</Table.Td>
<Table.Td>
{row.limitation
? localized(row.limitation)
: t('configuration.stcw.none', 'None')}
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
</Stack>
)}
{capacities.length > 0 && (
<Stack gap={4}>
<Text size="xs" c="dimmed" tt="uppercase" fw={700}>
{t('configuration.stcw.capacities', 'Capacities')}
</Text>
<Table withTableBorder withColumnBorders fz="xs">
<Table.Thead>
<Table.Tr>
<Table.Th>{t('configuration.stcw.capacity', 'Capacity')}</Table.Th>
<Table.Th>
{t('configuration.stcw.limitation', 'Limitation')}
</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{capacities.map((row, i) => (
<Table.Tr key={`${localized(row.capacity)}-${i}`}>
<Table.Td>{localized(row.capacity)}</Table.Td>
<Table.Td>
{row.limitation
? localized(row.limitation)
: t('configuration.stcw.none', 'None')}
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
</Stack>
)}
{licenseType.prerequisiteLicenseKeys?.length ? (
<Stack gap={4}>
<Text size="xs" c="dimmed" tt="uppercase" fw={700}>
{t('configuration.stcw.prerequisites', 'Must already hold')}
</Text>
<Group gap="xs">
{licenseType.prerequisiteLicenseKeys.map((key) => (
<Badge key={key} size="sm" variant="outline">
{key}
</Badge>
))}
</Group>
</Stack>
) : null}
</Stack>
</Paper>
);
}
function Field({ label, value }: { label: string; value?: string | null }) {
return (
<div>
<Text size="xs" c="dimmed">
{label}
</Text>
<Text size="sm" fw={600}>
{value || '—'}
</Text>
</div>
);
}