48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useQuery } from '@tanstack/react-query';
|
||
|
|
import { FileSignature } from 'lucide-react';
|
||
|
|
|
||
|
|
import { apiFetch } from '@/lib/api/client';
|
||
|
|
|
||
|
|
interface DocumentRow {
|
||
|
|
id: string;
|
||
|
|
documentType: string;
|
||
|
|
status: string;
|
||
|
|
archivedAt: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DocumentsResponse {
|
||
|
|
data: DocumentRow[];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Subtle chip that surfaces when an interest has multiple in-flight EOI
|
||
|
|
* documents (status != voided, not archived). Per product direction we
|
||
|
|
* intentionally allow multi-EOI cases (sometimes a deal really does need
|
||
|
|
* a second EOI for a different berth combo), but the rep should see the
|
||
|
|
* conflict at a glance so they don't accidentally re-send.
|
||
|
|
*/
|
||
|
|
export function MultiEoiChip({ interestId }: { interestId: string }) {
|
||
|
|
const { data } = useQuery<DocumentsResponse>({
|
||
|
|
queryKey: ['documents', { interestId, documentType: 'eoi' }],
|
||
|
|
queryFn: () => apiFetch(`/api/v1/documents?interestId=${interestId}&documentType=eoi`),
|
||
|
|
staleTime: 60_000,
|
||
|
|
});
|
||
|
|
|
||
|
|
const inflight = (data?.data ?? []).filter(
|
||
|
|
(d) => !d.archivedAt && d.status !== 'voided' && d.status !== 'declined',
|
||
|
|
);
|
||
|
|
if (inflight.length < 2) return null;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<span
|
||
|
|
title={`This interest has ${inflight.length} in-flight EOI documents — review on the EOI tab.`}
|
||
|
|
className="inline-flex items-center gap-1 rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-[11px] font-medium text-amber-800"
|
||
|
|
>
|
||
|
|
<FileSignature className="size-3" aria-hidden />
|
||
|
|
{inflight.length} EOIs
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|