Files
pn-new-crm/src/components/berths/berth-reservations-tab.tsx
2026-04-24 14:22:06 +02:00

91 lines
3.3 KiB
TypeScript

'use client';
import { useState } from 'react';
import { useParams } from 'next/navigation';
import { useQuery } from '@tanstack/react-query';
import { Plus } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { PermissionGate } from '@/components/shared/permission-gate';
import { EmptyState } from '@/components/shared/empty-state';
import { ReservationList, type ReservationRow } from '@/components/reservations/reservation-list';
import { BerthReserveDialog } from '@/components/reservations/berth-reserve-dialog';
import { useRealtimeInvalidation } from '@/hooks/use-realtime-invalidation';
import { apiFetch } from '@/lib/api/client';
interface BerthReservationsTabProps {
berthId: string;
}
export function BerthReservationsTab({ berthId }: BerthReservationsTabProps) {
const routeParams = useParams<{ portSlug: string }>();
const portSlug = routeParams?.portSlug ?? '';
const [reserveOpen, setReserveOpen] = useState(false);
const { data, isLoading } = useQuery<{ data: ReservationRow[]; pagination?: unknown }>({
queryKey: ['berths', berthId, 'reservations'],
queryFn: () =>
apiFetch(
`/api/v1/berths/${berthId}/reservations?page=1&limit=50&order=desc&includeArchived=false`,
),
});
useRealtimeInvalidation({
'berth_reservation:created': [['berths', berthId, 'reservations']],
'berth_reservation:activated': [['berths', berthId, 'reservations']],
'berth_reservation:ended': [['berths', berthId, 'reservations']],
'berth_reservation:cancelled': [['berths', berthId, 'reservations']],
});
const reservations = data?.data ?? [];
const active = reservations.find((r) => r.status === 'active');
const history = reservations.filter((r) => r.status !== 'active');
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold">Reservations</h3>
<PermissionGate resource="reservations" action="create">
<Button size="sm" onClick={() => setReserveOpen(true)}>
<Plus className="mr-1.5 h-4 w-4" />
Reserve this berth
</Button>
</PermissionGate>
</div>
{/* Active reservation card */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium">Active reservation</CardTitle>
</CardHeader>
<CardContent>
{active ? (
<ReservationList reservations={[active]} portSlug={portSlug} />
) : (
<p className="text-sm text-muted-foreground">No active reservation.</p>
)}
</CardContent>
</Card>
{/* History */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium">History</CardTitle>
</CardHeader>
<CardContent>
{isLoading ? (
<p className="text-sm text-muted-foreground">Loading</p>
) : history.length === 0 ? (
<EmptyState title="No past reservations" description="Nothing here yet." />
) : (
<ReservationList reservations={history} portSlug={portSlug} />
)}
</CardContent>
</Card>
<BerthReserveDialog open={reserveOpen} onOpenChange={setReserveOpen} berthId={berthId} />
</div>
);
}