From acd30ce0710e11068b2a8fd67e6c5e5377afbe80 Mon Sep 17 00:00:00 2001 From: estifanos Date: Tue, 4 Aug 2026 11:18:11 +0000 Subject: [PATCH] feat(MyApplicationsPage): implement advanced table for licenses and applications with improved loading and pagination --- .../licensing/pages/MyApplicationsPage.tsx | 349 ++++++++++-------- 1 file changed, 185 insertions(+), 164 deletions(-) diff --git a/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx b/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx index c90f8bc9c..ba16e14fb 100644 --- a/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx +++ b/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx @@ -3,17 +3,15 @@ import { Badge, Button, Card, - Center, Container, Group, - Loader, SimpleGrid, Stack, - Table, Text, Title, } from '@mantine/core'; import { IconDownload } from '@tabler/icons-react'; +import { AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui'; import { LicenseCatalogue } from '../components/LicenseCatalogue'; import { useApplicationPayment } from '../../payments/hooks/useApplicationPayment'; import { notifications } from '@mantine/notifications'; @@ -27,6 +25,8 @@ import { useGetMyApplicationsQuery, useGetMyLicensesQuery, useGetPaymentCapabilitiesQuery, + type LicenseApplication, + type IssuedLicense, } from '@ema-platform/api'; /** @@ -39,10 +39,10 @@ import { */ export function MyApplicationsPage() { const navigate = useNavigate(); - const { data, isLoading } = useGetMyApplicationsQuery(); + const { data, isFetching, refetch } = useGetMyApplicationsQuery(); const { pay, isPaying } = useApplicationPayment(); const { data: capabilities } = useGetPaymentCapabilitiesQuery(); - const { data: licences } = useGetMyLicensesQuery(); + const { data: licences, isFetching: isFetchingLicences, refetch: refetchLicences } = useGetMyLicensesQuery(); const [bypassPayment, { isLoading: bypassing }] = useBypassPaymentMutation(); const [getCertificateUrl] = useGetCertificateUrlMutation(); @@ -101,15 +101,165 @@ export function MyApplicationsPage() { } } - if (isLoading) { - return ( -
- -
- ); - } - const items = data?.items ?? []; + const licenceItems = licences?.items ?? []; + + const { setPageIndex: setLicencePage, pageSize: licencePageSize, paginate: paginateLicences } = + useServerTable({ pageSize: 10 }); + const licencePage = paginateLicences(licenceItems); + + const licenceColumns: AdvancedColumn[] = [ + { + header: 'Certificate', + cell: ({ row }) => ( + + {row.original.certificateNumber} + + ), + }, + { + header: 'Licence', + cell: ({ row }) => {localized(row.original.licenseType?.name) || '—'}, + }, + { + header: 'Valid until', + cell: ({ row }) => ( + + {new Date(row.original.expiryDate).toLocaleDateString()} + + ), + }, + { + header: 'Status', + cell: ({ row }) => ( + + {row.original.status} + + ), + }, + { + header: '', + label: 'Actions', + align: 'right', + cell: ({ row }) => ( + + ), + }, + ]; + + const { setPageIndex, pageSize, paginate } = useServerTable({ pageSize: 10 }); + const page = paginate(items); + + const applicationColumns: AdvancedColumn[] = [ + { + header: 'Number', + cell: ({ row }) => ( + + {row.original.applicationNumber} + + ), + }, + { + header: 'Company', + cell: ({ row }) => {row.original.companyName ?? '—'}, + }, + { + header: 'Status', + cell: ({ row }) => ( + + {STATUS_LABELS[row.original.status]} + + ), + }, + { + header: 'Submitted', + cell: ({ row }) => ( + + {row.original.submittedAt + ? new Date(row.original.submittedAt).toLocaleDateString() + : '—'} + + ), + }, + { + header: '', + label: 'Actions', + align: 'right', + cell: ({ row }) => { + const app = row.original; + return ( + + {capabilities?.bypassEnabled && app.status === 'PAYMENT_PENDING' && ( + + )} + {/* An issued application's primary action is the certificate. It + used to be "View", which opened the application wizard — so + the one thing the applicant came back for was the one thing + the button did not do. */} + {app.status === 'CERTIFICATE_ISSUED' && ( + + )} + + + ); + }, + }, + ]; return ( @@ -126,56 +276,17 @@ export function MyApplicationsPage() { My licences - - - - Certificate - Licence - Valid until - Status - - - - - {(licences?.items ?? []).map((licence) => ( - - - - {licence.certificateNumber} - - - - - {localized(licence.licenseType?.name) || '—'} - - - - - {new Date(licence.expiryDate).toLocaleDateString()} - - - - - {licence.status} - - - - - - - ))} - -
+
)} @@ -205,107 +316,17 @@ export function MyApplicationsPage() { ) : ( - - - - Number - Company - Status - Submitted - - - - - {items.map((app) => ( - - - - {app.applicationNumber} - - - - {app.companyName ?? '—'} - - - - {STATUS_LABELS[app.status]} - - - - - {app.submittedAt - ? new Date(app.submittedAt).toLocaleDateString() - : '—'} - - - - - {capabilities?.bypassEnabled && app.status === 'PAYMENT_PENDING' && ( - - )} - {/* An issued application's primary action is the - certificate. It used to be "View", which opened the - application wizard — so the one thing the applicant - came back for was the one thing the button did not do. */} - {app.status === 'CERTIFICATE_ISSUED' && ( - - )} - - - - - ))} - -
+
)}