157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
|
|
'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>
|
|||
|
|
);
|
|||
|
|
}
|