74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
// The project's documents, one row each, with where they are in the pipeline and how many lines wait
|
|
// for a person. Part of a page's view (F10): it holds no state, and every string is passed in.
|
|
|
|
import { type ResourceColumn, ResourceList } from "@conusai-kit/ui/patterns"
|
|
import type { ReactElement } from "react"
|
|
import type { DocumentView } from "../contract/index.js"
|
|
|
|
export interface DocumentListLabels {
|
|
readonly caption: string
|
|
readonly empty: string
|
|
readonly file: string
|
|
readonly status: string
|
|
readonly pages: string
|
|
readonly pending: string
|
|
readonly approved: string
|
|
readonly uploaded: string
|
|
readonly actions: string
|
|
/** `Download {filename}`: a same-origin, project-scoped file stream. */
|
|
readonly download: string
|
|
/** `Review {filename}`: the link's accessible name, so a list of links is not a list of "Review". */
|
|
readonly review: string
|
|
/** The status and failure texts, by code. */
|
|
readonly statuses: Readonly<Record<DocumentView["status"], string>>
|
|
readonly failures: Readonly<Record<NonNullable<DocumentView["failureCode"]>, string>>
|
|
}
|
|
|
|
export function DocumentList({
|
|
documents,
|
|
hrefFor,
|
|
downloadHrefFor,
|
|
labels,
|
|
formatDate,
|
|
}: {
|
|
documents: readonly DocumentView[]
|
|
hrefFor: (fileId: string) => string
|
|
downloadHrefFor: (fileId: string) => string
|
|
labels: DocumentListLabels
|
|
formatDate: (iso: string) => string
|
|
}): ReactElement {
|
|
const columns: ResourceColumn<DocumentView>[] = [
|
|
{ id: "filename", header: labels.file, wrap: true, minWidth: "10rem" },
|
|
{
|
|
id: "status",
|
|
header: labels.status,
|
|
wrap: true,
|
|
cell: (document) =>
|
|
`${labels.statuses[document.status]}${document.failureCode ? ` ${labels.failures[document.failureCode]}` : ""}`,
|
|
},
|
|
{ id: "pageCount", header: labels.pages, align: "end", cell: (document) => document.pageCount ?? "" },
|
|
{ id: "pending", header: labels.pending, align: "end" },
|
|
{ id: "approved", header: labels.approved, align: "end" },
|
|
{ id: "uploadedAt", header: labels.uploaded, cell: (document) => formatDate(document.uploadedAt) },
|
|
{
|
|
id: "actions",
|
|
header: labels.actions,
|
|
cell: (document) => (
|
|
<a href={downloadHrefFor(document.fileId)}>{labels.download.replace("{filename}", document.filename)}</a>
|
|
),
|
|
},
|
|
]
|
|
return (
|
|
<ResourceList
|
|
label={labels.caption}
|
|
columns={columns}
|
|
data={documents}
|
|
rowId={(document) => document.fileId}
|
|
rowHref={(document) => hrefFor(document.fileId)}
|
|
rowLinkLabel={(document) => labels.review.replace("{filename}", document.filename)}
|
|
rowLabel={(document) => document.filename}
|
|
empty={{ title: labels.empty }}
|
|
/>
|
|
)
|
|
}
|