Files
pn-new-crm/src/components/companies/company-owned-yachts-tab.tsx

157 lines
4.3 KiB
TypeScript
Raw Normal View History

'use client';
import Link from 'next/link';
import { useQuery } from '@tanstack/react-query';
import { Loader2 } from 'lucide-react';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { EmptyState } from '@/components/shared/empty-state';
import { apiFetch } from '@/lib/api/client';
interface OwnedYachtRow {
id: string;
name: string;
hullNumber: string | null;
lengthFt: string | null;
widthFt: string | null;
lengthM: string | null;
widthM: string | null;
status: string;
}
interface YachtListResponse {
data: OwnedYachtRow[];
}
interface CompanyOwnedYachtsTabProps {
companyId: string;
portSlug: string;
}
const STATUS_COLORS: Record<string, string> = {
active: 'bg-green-100 text-green-800 border-green-300',
retired: 'bg-gray-100 text-gray-800 border-gray-300',
sold_away: 'bg-amber-100 text-amber-800 border-amber-300',
};
const STATUS_LABELS: Record<string, string> = {
active: 'Active',
retired: 'Retired',
sold_away: 'Sold Away',
};
function formatDimensions(y: OwnedYachtRow): string | null {
if (y.lengthFt || y.widthFt) {
const length = y.lengthFt ?? '—';
const width = y.widthFt ?? '—';
return `${length} × ${width} ft`;
}
if (y.lengthM || y.widthM) {
const length = y.lengthM ?? '—';
const width = y.widthM ?? '—';
return `${length} × ${width} m`;
}
return null;
}
export function CompanyOwnedYachtsTab({ companyId, portSlug }: CompanyOwnedYachtsTabProps) {
const { data, isLoading } = useQuery<OwnedYachtRow[]>({
queryKey: ['companies', companyId, 'owned-yachts'],
queryFn: async () => {
const params = new URLSearchParams({
ownerType: 'company',
ownerId: companyId,
page: '1',
limit: '50',
includeArchived: 'false',
order: 'desc',
});
const res = await apiFetch<YachtListResponse>(`/api/v1/yachts?${params.toString()}`);
return res.data;
},
});
if (isLoading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
);
}
const yachts = data ?? [];
if (yachts.length === 0) {
return (
<EmptyState
title="No yachts owned"
description="Yachts owned by this company will appear here."
/>
);
}
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Dimensions</TableHead>
<TableHead>Hull Number</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{yachts.map((y) => {
const dims = formatDimensions(y);
const statusLabel = STATUS_LABELS[y.status] ?? y.status;
const statusColor =
STATUS_COLORS[y.status] ?? 'bg-muted text-muted-foreground border-muted';
return (
<TableRow key={y.id}>
<TableCell>
<Link
// eslint-disable-next-line @typescript-eslint/no-explicit-any
href={`/${portSlug}/yachts/${y.id}` as any}
className="font-medium text-primary hover:underline"
>
{y.name}
</Link>
</TableCell>
<TableCell>
{dims ? (
<span className="text-sm">{dims}</span>
) : (
<span className="text-muted-foreground"></span>
)}
</TableCell>
<TableCell>
{y.hullNumber ? (
<span className="text-sm">{y.hullNumber}</span>
) : (
<span className="text-muted-foreground"></span>
)}
</TableCell>
<TableCell>
<span
className={`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${statusColor}`}
>
{statusLabel}
</span>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
}