mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 08:03:13 +00:00
162 lines
5 KiB
TypeScript
162 lines
5 KiB
TypeScript
import { Table, TableBody, TableCell, TableHead, TableRow } from "@mui/material";
|
|
import { Eye, FileText, Pencil, Search } from "lucide-react";
|
|
import type { MouseEvent } from "react";
|
|
import { TableLoadingRow } from "@/components/ui/table-state-rows";
|
|
import { Text } from "@/components/ui/text";
|
|
import { COMPLETION_TEMPLATE_COPY } from "@/domain/completion-templates/constants/completion-template-constants";
|
|
import type { CompletionTemplate } from "@/domain/completion-templates/types/completion-template";
|
|
import { formatTemplateDate } from "@/domain/completion-templates/utils/format-template-date";
|
|
import { CompletionTemplateCreatedBy } from "./completion-template-created-by";
|
|
|
|
const HEAD_CELL_SX = {
|
|
fontSize: 10.5,
|
|
fontWeight: 700,
|
|
letterSpacing: "0.06em",
|
|
textTransform: "uppercase",
|
|
background: "var(--color-bg-muted)",
|
|
padding: "11px 14px",
|
|
whiteSpace: "nowrap",
|
|
} as const;
|
|
|
|
const BODY_CELL_SX = { fontSize: 13, padding: "8px 12px" } as const;
|
|
|
|
type CompletionTemplatesTableProps = {
|
|
templates: CompletionTemplate[];
|
|
isLoading: boolean;
|
|
/** The load failed: the page shows the error, so there is no search result to explain. */
|
|
hasError: boolean;
|
|
canEdit: boolean;
|
|
onView: (template: CompletionTemplate) => void;
|
|
onEdit: (template: CompletionTemplate) => void;
|
|
};
|
|
|
|
function RowAction({
|
|
label,
|
|
icon: Icon,
|
|
onClick,
|
|
}: {
|
|
label: string;
|
|
icon: typeof Eye;
|
|
onClick: () => void;
|
|
}) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
title={label}
|
|
aria-label={label}
|
|
onClick={(event: MouseEvent) => {
|
|
event.stopPropagation();
|
|
onClick();
|
|
}}
|
|
className="flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-primary"
|
|
>
|
|
<Icon size={15} />
|
|
</button>
|
|
);
|
|
}
|
|
|
|
function EmptyRow() {
|
|
return (
|
|
<TableRow>
|
|
<TableCell colSpan={4} sx={{ padding: 0, borderBottom: 0 }}>
|
|
<div
|
|
className="flex flex-col items-center justify-center gap-2 text-center"
|
|
style={{ padding: "64px 16px" }}
|
|
>
|
|
<Search size={22} aria-hidden style={{ color: "var(--color-text-muted)" }} />
|
|
<Text variant="body" sx={{ fontSize: 14, fontWeight: 600 }}>
|
|
{COMPLETION_TEMPLATE_COPY.emptySearchTitle}
|
|
</Text>
|
|
<Text variant="description" tone="muted" sx={{ fontSize: 12.5 }}>
|
|
{COMPLETION_TEMPLATE_COPY.emptySearchHint}
|
|
</Text>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
}
|
|
|
|
function TemplateRow({
|
|
template,
|
|
canEdit,
|
|
onView,
|
|
onEdit,
|
|
}: Omit<CompletionTemplatesTableProps, "templates" | "isLoading" | "hasError"> & {
|
|
template: CompletionTemplate;
|
|
}) {
|
|
return (
|
|
<TableRow hover onClick={() => onView(template)} sx={{ cursor: "pointer", height: 52 }}>
|
|
<TableCell sx={BODY_CELL_SX}>
|
|
<span className="inline-flex items-center gap-2.5">
|
|
<span
|
|
aria-hidden
|
|
className="inline-flex shrink-0 items-center justify-center rounded-full"
|
|
style={{
|
|
width: 28,
|
|
height: 28,
|
|
background: "var(--color-bg-muted)",
|
|
color: "var(--color-primary)",
|
|
}}
|
|
>
|
|
<FileText size={14} />
|
|
</span>
|
|
{template.name}
|
|
</span>
|
|
</TableCell>
|
|
<TableCell sx={{ ...BODY_CELL_SX, color: "text.secondary" }}>
|
|
{formatTemplateDate(template.lastUpdatedAt)}
|
|
</TableCell>
|
|
<TableCell sx={BODY_CELL_SX}>
|
|
<CompletionTemplateCreatedBy name={template.createdByName} />
|
|
</TableCell>
|
|
<TableCell sx={BODY_CELL_SX}>
|
|
<span className="flex items-center gap-1">
|
|
<RowAction label="View details" icon={Eye} onClick={() => onView(template)} />
|
|
{canEdit && <RowAction label="Edit" icon={Pencil} onClick={() => onEdit(template)} />}
|
|
</span>
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
}
|
|
|
|
export function CompletionTemplatesTable({
|
|
templates,
|
|
isLoading,
|
|
hasError,
|
|
canEdit,
|
|
onView,
|
|
onEdit,
|
|
}: CompletionTemplatesTableProps) {
|
|
return (
|
|
<Table
|
|
stickyHeader
|
|
size="small"
|
|
aria-label="Completion document templates"
|
|
sx={{ minWidth: 700 }}
|
|
>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell sx={{ ...HEAD_CELL_SX, width: 360 }}>Document Title</TableCell>
|
|
<TableCell sx={{ ...HEAD_CELL_SX, width: 140 }}>Last Updated</TableCell>
|
|
<TableCell sx={{ ...HEAD_CELL_SX, width: 180 }}>Created By</TableCell>
|
|
<TableCell sx={{ ...HEAD_CELL_SX, width: 90 }}>
|
|
<span className="sr-only">Actions</span>
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{isLoading && <TableLoadingRow colSpan={4} />}
|
|
{!isLoading && !hasError && templates.length === 0 && <EmptyRow />}
|
|
{templates.map((template) => (
|
|
<TemplateRow
|
|
key={template.id}
|
|
template={template}
|
|
canEdit={canEdit}
|
|
onView={onView}
|
|
onEdit={onEdit}
|
|
/>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
);
|
|
}
|