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 }) => (
+ }
+ onClick={() => downloadCertificate(row.original.id)}
+ >
+ Certificate
+
+ ),
+ },
+ ];
+
+ 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' && (
+ handleBypass(app.id)}
+ title="Testing only — marks the fee paid and issues the licence"
+ >
+ Bypass payment
+
+ )}
+ {/* 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' && (
+ }
+ onClick={() => openCertificateForApplication(app.id)}
+ >
+ Certificate
+
+ )}
+
+ // Paying leaves the SPA for Telebirr, so this is a provider
+ // hand-off rather than a route change.
+ app.status === 'PAYMENT_PENDING'
+ ? pay(app.id)
+ : navigate(
+ `/licensing/${app.licenseType?.key ?? 'FREIGHT_FORWARDER'}/applications/${app.id}`,
+ )
+ }
+ >
+ {app.status === 'DRAFT'
+ ? 'Continue'
+ : app.status === 'RESUBMIT_REQUIRED'
+ ? 'Fix & resubmit'
+ : app.status === 'PAYMENT_PENDING'
+ ? `Pay ${Number(app.feeAmount ?? 0).toLocaleString()} ${app.feeCurrency}`
+ : app.status === 'CERTIFICATE_ISSUED'
+ ? 'Application'
+ : 'View'}
+
+
+ );
+ },
+ },
+ ];
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}
-
-
-
- }
- onClick={() => downloadCertificate(licence.id)}
- >
- Certificate
-
-
-
- ))}
-
-
+
>
)}
@@ -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' && (
- handleBypass(app.id)}
- title="Testing only — marks the fee paid and issues the licence"
- >
- Bypass payment
-
- )}
- {/* 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' && (
- }
- onClick={() => openCertificateForApplication(app.id)}
- >
- Certificate
-
- )}
-
- // Paying leaves the SPA for Telebirr, so this is a
- // provider hand-off rather than a route change.
- app.status === 'PAYMENT_PENDING'
- ? pay(app.id)
- : navigate(
- `/licensing/${app.licenseType?.key ?? 'FREIGHT_FORWARDER'}/applications/${app.id}`,
- )
- }
- >
- {app.status === 'DRAFT'
- ? 'Continue'
- : app.status === 'RESUBMIT_REQUIRED'
- ? 'Fix & resubmit'
- : app.status === 'PAYMENT_PENDING'
- ? `Pay ${Number(app.feeAmount ?? 0).toLocaleString()} ${app.feeCurrency}`
- : app.status === 'CERTIFICATE_ISSUED'
- ? 'Application'
- : 'View'}
-
-
-
-
- ))}
-
-
+
)}