mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 13:02:50 +00:00
172 lines
5.5 KiB
TypeScript
172 lines
5.5 KiB
TypeScript
import { useMemo, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import {Badge, Container, Select, Text, TextInput} 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, PageHeader, WaitingFor, 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<SeafarerDocumentStatus | null>(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<SeafarerDocumentRow>[] = useMemo(
|
|
() => [
|
|
{
|
|
header: 'Request №',
|
|
accessorKey: 'requestNumber',
|
|
cell: ({ row }) => (
|
|
<div>
|
|
<Text size="sm" ff="monospace">
|
|
{row.original.requestNumber}
|
|
</Text>
|
|
{row.original.documentNumber && (
|
|
<Text size="xs" c="teal" ff="monospace">
|
|
{row.original.documentNumber}
|
|
</Text>
|
|
)}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
header: 'Seafarer',
|
|
accessorKey: 'applicant.name',
|
|
cell: ({ row }) => (
|
|
<div>
|
|
<Text size="sm" fw={500}>
|
|
{row.original.applicant?.name ?? '—'}
|
|
</Text>
|
|
<Text size="xs" c="dimmed" ff="monospace">
|
|
{row.original.applicant?.seafarerNumber ?? '—'}
|
|
</Text>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
header: 'Fee',
|
|
accessorKey: 'feeAmount',
|
|
cell: ({ row }) => (
|
|
<Text size="sm">
|
|
{row.original.feeAmount !== null ? `${row.original.feeAmount} ${row.original.feeCurrency}` : '—'}
|
|
</Text>
|
|
),
|
|
},
|
|
{
|
|
header: 'Released',
|
|
accessorKey: 'submittedAt',
|
|
cell: ({ row }) => (
|
|
<Text size="sm">{row.original.submittedAt ? showDate(row.original.submittedAt) : '—'}</Text>
|
|
),
|
|
},
|
|
{
|
|
header: 'Waiting',
|
|
accessorKey: 'submittedAt',
|
|
size: 90,
|
|
cell: ({ row }) => (
|
|
<WaitingFor
|
|
since={row.original.submittedAt}
|
|
done={row.original.status === 'ISSUED' || row.original.status === 'REJECTED'}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
header: 'Status',
|
|
accessorKey: 'status',
|
|
cell: ({ row }) => (
|
|
<Badge size="sm" variant="light" color={SEAFARER_DOCUMENT_STATUS_COLORS[row.original.status]}>
|
|
{SEAFARER_DOCUMENT_STATUS_LABELS[row.original.status]}
|
|
</Badge>
|
|
),
|
|
},
|
|
],
|
|
[showDate],
|
|
);
|
|
|
|
return (
|
|
<Container size="xl" py="md">
|
|
<PageHeader
|
|
title={`${SEAFARER_DOCUMENT_KIND_LABELS[kind]} Queue`}
|
|
subtitle="Requests released by an approved seafarer registration: confirm payment, schedule the collection date, then issue."
|
|
/>
|
|
<AdvancedTable
|
|
columns={columns}
|
|
data={data?.items ?? []}
|
|
tableName={`${SEAFARER_DOCUMENT_KIND_LABELS[kind]} requests`}
|
|
toolbar={
|
|
<>
|
|
<TextInput
|
|
placeholder="Search number, name or seafarer №…"
|
|
leftSection={<IconSearch size={14} />}
|
|
value={search}
|
|
onChange={(e) => {
|
|
setSearch(e.currentTarget.value);
|
|
setPage(0);
|
|
}}
|
|
w={260}
|
|
/>
|
|
<Select
|
|
placeholder="All statuses"
|
|
data={STATUS_FILTERS}
|
|
value={status}
|
|
onChange={(v) => {
|
|
setStatus(v as SeafarerDocumentStatus | null);
|
|
setPage(0);
|
|
}}
|
|
clearable
|
|
w={200}
|
|
/>
|
|
</>
|
|
}
|
|
itemCount={data?.total ?? 0}
|
|
pageIndex={page}
|
|
onPageChange={setPage}
|
|
pageSize={pageSize}
|
|
onPageSizeChange={(size) => {
|
|
setPageSize(size);
|
|
setPage(0);
|
|
}}
|
|
refresh={refetch}
|
|
isLoading={isLoading || isFetching}
|
|
emptyText="No requests match."
|
|
onRowClick={(row) => navigate(`/seafarer-documents/${row.id}`)}
|
|
/>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
export const SeamanBookQueuePage = () => <SeafarerDocumentQueuePage kind="SEAMAN_BOOK" />;
|
|
export const BtcQueuePage = () => <SeafarerDocumentQueuePage kind="BTC_BASIC_TRAINING" />;
|