Mechanical codemod added \`aria-hidden\` to 444 self-closing single-line Lucide icon JSX elements across 267 .tsx files in: - shared/, layout/, dashboard/ - admin/ (all sections) - clients/, berths/, yachts/, companies/, interests/, documents/ - reminders/, reservations/, residential/, expenses/, email/ The regex targeted only the safe pattern \`<IconName className="..." />\` (no other props, self-closing, capitalized component name). Every match inspected is a decorative companion to visible text or sits inside a button whose accessible name comes from \`aria-label\` / sr-only text — the icon itself should not be announced. Screen readers no longer double-read the icon + the adjacent label text (e.g. "Pencil Pencil Edit" → just "Edit"). The existing @axe-core/playwright smoke test (\`20-accessibility.spec.ts\`) continues to pass. Test suite stays at 1315/1315 vitest. typescript clean. Closes task #69 (aria-hidden sweep) from the AUDIT-2026-05-12 follow-ups backlog. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { FileText, ClipboardSignature } from 'lucide-react';
|
|
|
|
import { usePaginatedQuery } from '@/hooks/use-paginated-query';
|
|
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
|
|
|
|
interface HubRootDoc {
|
|
id: string;
|
|
title: string;
|
|
documentType: string;
|
|
status: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface HubRootFile {
|
|
id: string;
|
|
filename: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface Props {
|
|
portSlug: string;
|
|
}
|
|
|
|
const STATUS_PILL_MAP: Record<string, StatusPillStatus> = {
|
|
draft: 'draft',
|
|
sent: 'sent',
|
|
partially_signed: 'partial',
|
|
completed: 'completed',
|
|
signed: 'signed',
|
|
expired: 'expired',
|
|
cancelled: 'cancelled',
|
|
rejected: 'rejected',
|
|
};
|
|
|
|
export function HubRootView({ portSlug }: Props) {
|
|
const { data: workflows, isLoading: workflowsLoading } = usePaginatedQuery<HubRootDoc>({
|
|
queryKey: ['documents', 'hub-root', 'workflows'],
|
|
endpoint: '/api/v1/documents?tab=in_progress',
|
|
filterDefinitions: [],
|
|
});
|
|
const { data: filesData, isLoading: filesLoading } = usePaginatedQuery<HubRootFile>({
|
|
queryKey: ['files', 'hub-root'],
|
|
endpoint: '/api/v1/files?sort=createdAt&order=desc&limit=20',
|
|
filterDefinitions: [],
|
|
});
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<section className="rounded-md border bg-white">
|
|
<h3 className="flex items-center gap-2 border-b px-3 py-2 text-sm font-semibold">
|
|
<ClipboardSignature className="h-4 w-4 text-muted-foreground" aria-hidden />
|
|
Signing in progress
|
|
</h3>
|
|
{workflowsLoading ? (
|
|
<div className="p-3 text-sm text-muted-foreground">Loading...</div>
|
|
) : workflows.length === 0 ? (
|
|
<div className="p-3 text-sm text-muted-foreground">No workflows in flight.</div>
|
|
) : (
|
|
<ul className="divide-y">
|
|
{workflows.map((w) => (
|
|
<li key={w.id} className="flex items-center justify-between gap-2 px-3 py-2 text-sm">
|
|
<Link href={`/${portSlug}/documents/${w.id}`} className="truncate hover:underline">
|
|
{w.title}
|
|
</Link>
|
|
<StatusPill status={STATUS_PILL_MAP[w.status] ?? 'pending'}>
|
|
{w.status.replace(/_/g, ' ')}
|
|
</StatusPill>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</section>
|
|
|
|
<section className="rounded-md border bg-white">
|
|
<h3 className="flex items-center gap-2 border-b px-3 py-2 text-sm font-semibold">
|
|
<FileText className="h-4 w-4 text-muted-foreground" aria-hidden />
|
|
Recent files
|
|
</h3>
|
|
{filesLoading ? (
|
|
<div className="p-3 text-sm text-muted-foreground">Loading...</div>
|
|
) : filesData.length === 0 ? (
|
|
<div className="p-3 text-sm text-muted-foreground">No files yet.</div>
|
|
) : (
|
|
<ul className="divide-y">
|
|
{filesData.map((f) => (
|
|
<li key={f.id} className="flex items-center justify-between px-3 py-2 text-sm">
|
|
<span className="truncate">{f.filename}</span>
|
|
<span className="text-xs text-muted-foreground tabular-nums">
|
|
{new Date(f.createdAt).toLocaleDateString('en-GB')}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|