diff --git a/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx b/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx index a28886878..328591367 100644 --- a/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx +++ b/apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx @@ -1,3 +1,4 @@ +import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Badge, @@ -5,13 +6,15 @@ import { Card, Container, Group, - SimpleGrid, + Paper, + Select, Stack, Text, + TextInput, Title, } from '@mantine/core'; -import { IconDownload } from '@tabler/icons-react'; -import { AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui'; +import { IconDownload, IconSearch, IconX } from '@tabler/icons-react'; +import { AdvancedTable, AmharicDatePicker, useServerTable, type AdvancedColumn } from '@ema-platform/ui'; import { LicenseCatalogue } from '../components/LicenseCatalogue'; import { useApplicationPayment } from '../../payments/hooks/useApplicationPayment'; import { notifications } from '@mantine/notifications'; @@ -26,9 +29,12 @@ import { useGetMyLicensesQuery, useGetPaymentCapabilitiesQuery, type LicenseApplication, + type LicenseStatus, type IssuedLicense, } from '@ema-platform/api'; +const ALL_APPLICATION_STATUSES = Object.keys(STATUS_LABELS) as LicenseStatus[]; + /** * The applicant's landing page: which licences they can apply for, and the * state of anything already filed. @@ -101,9 +107,32 @@ export function MyApplicationsPage() { } } - const items = data?.items ?? []; + const allItems = data?.items ?? []; const licenceItems = licences?.items ?? []; + const [search, setSearch] = useState(''); + const [statusFilter, setStatusFilter] = useState(null); + const [dateFrom, setDateFrom] = useState(''); + const [dateTo, setDateTo] = useState(''); + const hasFilters = Boolean(search || statusFilter || dateFrom || dateTo); + + const items = useMemo(() => { + const q = search.trim().toLowerCase(); + return allItems.filter((app) => { + if (q) { + const haystack = `${app.applicationNumber} ${app.companyName ?? ''}`.toLowerCase(); + if (!haystack.includes(q)) return false; + } + if (statusFilter && app.status !== statusFilter) return false; + // Drafts have no submittedAt, so date filtering falls back to createdAt + // rather than silently excluding every draft from a date-ranged search. + const at = app.submittedAt ?? app.createdAt; + if (dateFrom && (!at || at < dateFrom)) return false; + if (dateTo && (!at || at > `${dateTo}T23:59:59.999Z`)) return false; + return true; + }); + }, [allItems, search, statusFilter, dateFrom, dateTo]); + const { setPageIndex: setLicencePage, pageSize: licencePageSize, @@ -310,12 +339,68 @@ export function MyApplicationsPage() { )} + {allItems.length > 0 && ( + + + } + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} + w={220} + /> +