feat(vessel-registration): add vessel registration page with incident reporting and certificate download functionality

feat(waiver): implement waiver page with application tracking and letter download feature

feat(ui): introduce AdvancedTable component for enhanced table functionality across the application

chore: update package-lock.json to remove unnecessary dependencies
This commit is contained in:
Nati
2026-08-13 09:11:50 +00:00
parent a7e74cb7bd
commit 2af9e60800
67 changed files with 4209 additions and 3446 deletions

View File

@@ -0,0 +1,29 @@
import { IconEdit, IconTrash } from '@tabler/icons-react';
import type { TFunction } from 'i18next';
import type { AdvancedTableAction } from '@ema-platform/ui';
import type { Certification } from '../../types/certification';
export function certificationColumnActions(
t: TFunction,
handlers: {
onEdit: (cert: Certification) => void;
onDelete: (cert: Certification) => void;
},
): AdvancedTableAction<Certification>[] {
return [
{
key: 'edit',
label: t('certification.update'),
color: 'blue',
icon: <IconEdit size={14} />,
onClick: handlers.onEdit,
},
{
key: 'delete',
label: t('certification.delete'),
color: 'red',
icon: <IconTrash size={14} />,
onClick: handlers.onDelete,
},
];
}

View File

@@ -0,0 +1,31 @@
import { Badge, Text } from '@mantine/core';
import type { TFunction } from 'i18next';
import type { AdvancedTableColumn } from '@ema-platform/ui';
import type { Certification } from '../../types/certification';
export function certificationColumns(
t: TFunction,
locale: 'en' | 'am',
): AdvancedTableColumn<Certification>[] {
return [
{
key: 'name',
header: t('certification.columns.name'),
render: (cert) => <Text fz="sm" fw={500}>{cert.name[locale]}</Text>,
},
{
key: 'description',
header: t('certification.columns.description'),
render: (cert) => <Text fz="sm" lineClamp={2} maw={250}>{cert.description[locale]}</Text>,
},
{
key: 'status',
header: t('certification.columns.status'),
render: (cert) => (
<Badge size="sm" variant="light" color={cert.isActive ? 'teal' : 'gray'}>
{cert.isActive ? t('certification.status.active') : t('certification.status.inactive')}
</Badge>
),
},
];
}

View File

@@ -4,9 +4,6 @@ import {
Title,
Group,
Button,
Table,
Badge,
ActionIcon,
Modal,
Text,
TextInput,
@@ -18,15 +15,17 @@ import {
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { useTranslation } from 'react-i18next';
import { IconEdit, IconTrash, IconPlus, IconInfoCircle, IconCertificate } from '@tabler/icons-react';
import { notify } from '@ema-platform/ui';
import { IconPlus, IconInfoCircle } from '@tabler/icons-react';
import { AdvancedTable, notify } from '@ema-platform/ui';
import { certificationColumns } from './columns';
import { certificationColumnActions } from './actions';
import {
useGetCertificationsQuery,
useCreateCertificationMutation,
useUpdateCertificationMutation,
useDeleteCertificationMutation,
} from '../api/certification-api';
import type { Certification } from '../types/certification';
} from '../../api/certification-api';
import type { Certification } from '../../types/certification';
function CertificationForm({
editing,
@@ -75,7 +74,7 @@ function CertificationForm({
export function CertificationPage() {
const { t, i18n } = useTranslation();
const locale = i18n.language as 'en' | 'am';
const { data, isLoading, isError } = useGetCertificationsQuery();
const { data, isLoading, isError, refetch } = useGetCertificationsQuery();
const [createCert, { isLoading: isCreating }] = useCreateCertificationMutation();
const [updateCert, { isLoading: isUpdating }] = useUpdateCertificationMutation();
const [deleteCert] = useDeleteCertificationMutation();
@@ -148,48 +147,17 @@ export function CertificationPage() {
)}
<Paper withBorder radius="md">
<Table striped highlightOnHover>
<Table.Thead bg="var(--mantine-color-default-hover)">
<Table.Tr>
<Table.Th>{t('certification.columns.name')}</Table.Th>
<Table.Th>{t('certification.columns.description')}</Table.Th>
<Table.Th>{t('certification.columns.status')}</Table.Th>
<Table.Th />
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{certifications.map((cert) => (
<Table.Tr key={cert.id}>
<Table.Td><Text fz="sm" fw={500}>{cert.name[locale]}</Text></Table.Td>
<Table.Td>
<Text fz="sm" lineClamp={2} maw={250}>{cert.description[locale]}</Text>
</Table.Td>
<Table.Td>
<Badge size="sm" variant="light" color={cert.isActive ? 'teal' : 'gray'}>
{cert.isActive ? t('certification.status.active') : t('certification.status.inactive')}
</Badge>
</Table.Td>
<Table.Td>
<Group gap="xs">
<ActionIcon variant="subtle" color="blue" size="sm" onClick={() => { setEditing(cert); setShowForm(true); }}>
<IconEdit size={14} />
</ActionIcon>
<ActionIcon variant="subtle" color="red" size="sm" onClick={() => { setDeleteTarget(cert); openDelete(); }}>
<IconTrash size={14} />
</ActionIcon>
</Group>
</Table.Td>
</Table.Tr>
))}
{certifications.length === 0 && (
<Table.Tr>
<Table.Td colSpan={4}>
<Text c="dimmed" ta="center" py="xl">{t('certification.noItems')}</Text>
</Table.Td>
</Table.Tr>
)}
</Table.Tbody>
</Table>
<AdvancedTable
columns={certificationColumns(t, locale)}
data={certifications}
rowKey={(cert) => cert.id}
actions={certificationColumnActions(t, {
onEdit: (cert) => { setEditing(cert); setShowForm(true); },
onDelete: (cert) => { setDeleteTarget(cert); openDelete(); },
})}
onRefresh={refetch}
emptyTitle={t('certification.noItems')}
/>
</Paper>
<Modal opened={deleteOpened} onClose={closeDelete} title={t('certification.confirmDelete')} size="sm">