diff --git a/apps/backoffice/src/app/features/seafarer-document-review/pages/SeafarerDocumentQueuePage.tsx b/apps/backoffice/src/app/features/seafarer-document-review/pages/SeafarerDocumentQueuePage.tsx new file mode 100644 index 000000000..961545a97 --- /dev/null +++ b/apps/backoffice/src/app/features/seafarer-document-review/pages/SeafarerDocumentQueuePage.tsx @@ -0,0 +1,161 @@ +import { useMemo, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Badge, Container, Group, Select, Text, TextInput, Title } from '@mantine/core'; +import { IconSearch } from '@tabler/icons-react'; +import { useDebouncedValue } from '@mantine/hooks'; +import { + SEAFARER_DOCUMENT_KIND_LABELS, + SEAFARER_DOCUMENT_STATUS_COLORS, + SEAFARER_DOCUMENT_STATUS_LABELS, + useListSeafarerDocumentsQuery, + type SeafarerDocumentKind, + type SeafarerDocumentRow, + type SeafarerDocumentStatus, +} from '@ema-platform/api'; +import { AdvancedTable, type AdvancedColumn } from '@ema-platform/ui'; +import { useDateDisplayer } from '@ema-platform/shared'; + +const PAGE_SIZE = 10; + +/** Statuses an officer filters by — held and withdrawn requests are not work. */ +const STATUS_FILTERS = ( + ['PAYMENT_PENDING', 'PAID', 'PAYMENT_CONFIRMED', 'SCHEDULED', 'ISSUED', 'REJECTED'] as SeafarerDocumentStatus[] +).map((value) => ({ value, label: SEAFARER_DOCUMENT_STATUS_LABELS[value] })); + +/** + * The Seaman Book queue and the BTC queue — one page, keyed by kind. Requests + * appear here once the seafarer registration that opened them is approved. + */ +export function SeafarerDocumentQueuePage({ kind }: { kind: SeafarerDocumentKind }) { + const navigate = useNavigate(); + const showDate = useDateDisplayer(); + const [status, setStatus] = useState(null); + const [search, setSearch] = useState(''); + const [debouncedSearch] = useDebouncedValue(search, 300); + const [page, setPage] = useState(0); + const [pageSize, setPageSize] = useState(PAGE_SIZE); + + const { data, isLoading, isFetching, refetch } = useListSeafarerDocumentsQuery({ + kind, + status: status ?? undefined, + search: debouncedSearch || undefined, + take: pageSize, + skip: page * pageSize, + }); + + const columns: AdvancedColumn[] = useMemo( + () => [ + { + header: 'Request №', + accessorKey: 'requestNumber', + cell: ({ row }) => ( +
+ + {row.original.requestNumber} + + {row.original.documentNumber && ( + + {row.original.documentNumber} + + )} +
+ ), + }, + { + header: 'Seafarer', + accessorKey: 'applicant.name', + cell: ({ row }) => ( +
+ + {row.original.applicant?.name ?? '—'} + + + {row.original.applicant?.seafarerNumber ?? '—'} + +
+ ), + }, + { + header: 'Fee', + accessorKey: 'feeAmount', + cell: ({ row }) => ( + + {row.original.feeAmount !== null ? `${row.original.feeAmount} ${row.original.feeCurrency}` : '—'} + + ), + }, + { + header: 'Released', + accessorKey: 'submittedAt', + cell: ({ row }) => ( + {row.original.submittedAt ? showDate(row.original.submittedAt) : '—'} + ), + }, + { + header: 'Status', + accessorKey: 'status', + cell: ({ row }) => ( + + {SEAFARER_DOCUMENT_STATUS_LABELS[row.original.status]} + + ), + }, + ], + [showDate], + ); + + return ( + + + {SEAFARER_DOCUMENT_KIND_LABELS[kind]} Queue + + + Requests released by an approved seafarer registration: confirm payment, schedule the + collection date, then issue. + + + } + value={search} + onChange={(e) => { + setSearch(e.currentTarget.value); + setPage(0); + }} + w={280} + /> +