Files
pn-new-crm/src/components/interests/interest-documents-tab.tsx
Matt Ciaccio 8699f81879
Some checks failed
Build & Push Docker Images / lint (push) Failing after 1m18s
Build & Push Docker Images / build-and-push (push) Has been skipped
chore(style): codebase em-dash sweep + minor layout polish
Replaces every em-dash and en-dash with regular ASCII hyphens
across comments, JSX strings, and dev-facing logs. Mostly cosmetic
but stops the inconsistent mix that crept in over the last few
months (some files used em-dashes in comments, others didn't,
some used both).

Bundles two small dashboard-layout tweaks that touch a couple of
already-modified files:
- (dashboard)/layout.tsx main padding goes from p-6 to pt-3 px-6
  pb-6 so page content sits closer to the topbar.
- Sidebar now receives the ports list it needs for the footer
  port switcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 22:57:01 +02:00

86 lines
3.0 KiB
TypeScript

'use client';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { FileSignature } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { DocumentList } from '@/components/documents/document-list';
import { EoiGenerateDialog } from '@/components/documents/eoi-generate-dialog';
import { apiFetch } from '@/lib/api/client';
interface InterestDocumentsTabProps {
interestId: string;
}
interface InterestData {
id: string;
yachtId?: string | null;
berthId?: string | null;
clientName?: string | null;
/** Surfaced by getInterestById for the EOI prerequisites checklist. */
clientPrimaryEmail?: string | null;
clientHasAddress?: boolean;
}
export function InterestDocumentsTab({ interestId }: InterestDocumentsTabProps) {
const [eoiDialogOpen, setEoiDialogOpen] = useState(false);
// Same query key + queryFn shape as InterestDetail's parent query, so the
// cache is consistent. (Mismatched shapes on the same key clobber each other
// and the parent header degenerates to "Unknown Client".)
const { data: interest } = useQuery<InterestData>({
queryKey: ['interests', interestId],
queryFn: () =>
apiFetch<{ data: InterestData }>(`/api/v1/interests/${interestId}`).then((r) => r.data),
});
const prerequisites = {
// Required (EOI Section 2 - top paragraph): name, address, email.
hasName: Boolean(interest?.clientName),
hasEmail: Boolean(interest?.clientPrimaryEmail),
hasAddress: Boolean(interest?.clientHasAddress),
// Optional (EOI Section 3): yacht + berth. Render blank when absent.
hasYacht: Boolean(interest?.yachtId),
hasBerth: Boolean(interest?.berthId),
};
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-sm font-medium text-muted-foreground">Documents</h3>
<Button size="sm" variant="outline" onClick={() => setEoiDialogOpen(true)}>
Generate EOI
</Button>
</div>
<DocumentList
interestId={interestId}
emptyState={
<div className="flex flex-col items-center gap-3 rounded-lg border border-dashed border-border bg-muted/20 px-6 py-10 text-center">
<div className="flex size-10 items-center justify-center rounded-full bg-background text-muted-foreground">
<FileSignature className="size-5" />
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-foreground">No documents yet</p>
<p className="text-xs text-muted-foreground">
Generate the EOI to send it for signing in one click.
</p>
</div>
<Button size="sm" onClick={() => setEoiDialogOpen(true)}>
Generate EOI
</Button>
</div>
}
/>
<EoiGenerateDialog
interestId={interestId}
open={eoiDialogOpen}
onOpenChange={setEoiDialogOpen}
prerequisites={prerequisites}
/>
</div>
);
}