feat(i18n): add new translations for refresh, view, toggle columns, and no results

refactor(payment): remove payment API client and related tests, consolidating payment logic

refactor(payment): delete payment modal and associated constants, hooks, and types

fix(ui): enhance AdvancedTable with refresh button and column toggle functionality

fix(ui): implement pagination in useServerTable for better data handling
This commit is contained in:
estifanos
2026-08-03 09:22:02 +00:00
parent 52e2f4c009
commit 599dc4aa83
19 changed files with 452 additions and 1395 deletions

View File

@@ -4,7 +4,6 @@ import {
Title,
Group,
Button,
Table,
Badge,
ActionIcon,
Modal,
@@ -12,14 +11,13 @@ import {
TextInput,
Textarea,
Paper,
Loader,
Center,
Card,
Alert,
} 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, useErrorHandler } from '@ema-platform/ui';
import { notify, useErrorHandler, AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui';
import {
useGetCertificationsQuery,
useCreateCertificationMutation,
@@ -76,7 +74,8 @@ export function CertificationPage() {
const { t, i18n } = useTranslation();
const locale = i18n.language as 'en' | 'am';
const { handleError } = useErrorHandler();
const { data, isLoading, isError } = useGetCertificationsQuery();
const { data, isFetching, isError, refetch } = useGetCertificationsQuery();
const { setPageIndex, pageSize, paginate } = useServerTable({ pageSize: 25 });
const [createCert, { isLoading: isCreating }] = useCreateCertificationMutation();
const [updateCert, { isLoading: isUpdating }] = useUpdateCertificationMutation();
const [deleteCert] = useDeleteCertificationMutation();
@@ -122,9 +121,44 @@ export function CertificationPage() {
}
};
if (isLoading) return <Center py="xl"><Loader /></Center>;
if (isError) return <Alert icon={<IconInfoCircle size={16} />} color="red" title={t('certification.loadError')} />;
const columns: AdvancedColumn<Certification>[] = [
{
header: t('certification.columns.name'),
cell: ({ row }) => <Text fz="sm" fw={500}>{row.original.name[locale]}</Text>,
},
{
header: t('certification.columns.description'),
cell: ({ row }) => <Text fz="sm" lineClamp={2} maw={250}>{row.original.description[locale]}</Text>,
},
{
header: t('certification.columns.status'),
cell: ({ row }) => (
<Badge size="sm" variant="light" color={row.original.isActive ? 'teal' : 'gray'}>
{row.original.isActive ? t('certification.status.active') : t('certification.status.inactive')}
</Badge>
),
},
{
header: '',
label: t('certification.columns.actions', 'Actions'),
size: 90,
cell: ({ row }) => (
<Group gap="xs">
<ActionIcon variant="subtle" color="blue" size="sm" onClick={() => { setEditing(row.original); setShowForm(true); }}>
<IconEdit size={14} />
</ActionIcon>
<ActionIcon variant="subtle" color="red" size="sm" onClick={() => { setDeleteTarget(row.original); openDelete(); }}>
<IconTrash size={14} />
</ActionIcon>
</Group>
),
},
];
const page = paginate(certifications);
return (
<Stack gap="lg">
<Group justify="space-between" align="flex-end">
@@ -148,50 +182,20 @@ 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>
</Paper>
<Card withBorder padding={0}>
<AdvancedTable
columns={columns}
data={page.rows}
tableName={t('certification.title')}
itemCount={page.itemCount}
pageIndex={page.pageIndex}
onPageChange={setPageIndex}
pageSize={pageSize}
refresh={refetch}
isLoading={isFetching}
emptyText={t('certification.noItems')}
/>
</Card>
<Modal opened={deleteOpened} onClose={closeDelete} title={t('certification.confirmDelete')} size="sm">
<Text mb="md">{t('certification.deleteConfirmText', { name: deleteTarget?.name?.[locale] })}</Text>