diff --git a/src/components/berths/berth-tabs.tsx b/src/components/berths/berth-tabs.tsx index b2c4747..c3fba85 100644 --- a/src/components/berths/berth-tabs.tsx +++ b/src/components/berths/berth-tabs.tsx @@ -321,14 +321,6 @@ function OverviewTab({ berth }: { berth: BerthData }) { ); } -function StubTab({ label }: { label: string }) { - return ( -
-

{label} coming soon

-
- ); -} - export function buildBerthTabs(berth: BerthData): DetailTab[] { return [ { @@ -351,16 +343,9 @@ export function buildBerthTabs(berth: BerthData): DetailTab[] { label: 'Documents', content: , }, - { - id: 'waiting-list', - label: 'Waiting List', - content: , - }, - { - id: 'maintenance', - label: 'Maintenance Log', - content: , - }, + // Waiting List + Maintenance Log tabs were stubs ("coming soon") + // visible to every operator. Hidden here until the + // berth_waiting_list / berth_maintenance_log feature surfaces ship. { id: 'activity', label: 'Activity', diff --git a/src/components/clients/client-reservations-tab.tsx b/src/components/clients/client-reservations-tab.tsx index f4cb2ef..d852f98 100644 --- a/src/components/clients/client-reservations-tab.tsx +++ b/src/components/clients/client-reservations-tab.tsx @@ -1,6 +1,11 @@ 'use client'; +import { useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; + import { ReservationList, type ReservationRow } from '@/components/reservations/reservation-list'; +import { Button } from '@/components/ui/button'; +import { apiFetch } from '@/lib/api/client'; interface ClientReservationsTabProps { clientId: string; @@ -14,14 +19,21 @@ interface ClientReservationsTabProps { }>; } +interface ReservationListResponse { + data: ReservationRow[]; + pagination?: { total: number }; +} + export function ClientReservationsTab({ clientId, activeReservations, }: ClientReservationsTabProps) { - const rows: ReservationRow[] = activeReservations.map((r) => ({ + const [showHistory, setShowHistory] = useState(false); + + const activeRows: ReservationRow[] = activeReservations.map((r) => ({ id: r.id, berthId: r.berthId, - portId: '', // not rendered by ReservationList + portId: '', clientId, yachtId: r.yachtId, status: r.status as ReservationRow['status'], @@ -33,19 +45,73 @@ export function ClientReservationsTab({ createdAt: '', })); + // Lazy-load history (ended + cancelled). Two parallel queries because + // the API takes one status at a time; combining once both resolve. + const endedQuery = useQuery({ + queryKey: ['reservations', { clientId, status: 'ended' }], + queryFn: () => + apiFetch( + `/api/v1/berth-reservations?clientId=${encodeURIComponent(clientId)}&status=ended&pageSize=50`, + ), + enabled: showHistory, + }); + const cancelledQuery = useQuery({ + queryKey: ['reservations', { clientId, status: 'cancelled' }], + queryFn: () => + apiFetch( + `/api/v1/berth-reservations?clientId=${encodeURIComponent(clientId)}&status=cancelled&pageSize=50`, + ), + enabled: showHistory, + }); + + const historyRows: ReservationRow[] = [ + ...(endedQuery.data?.data ?? []), + ...(cancelledQuery.data?.data ?? []), + ].sort((a, b) => (a.startDate < b.startDate ? 1 : -1)); + + const isHistoryLoading = showHistory && (endedQuery.isLoading || cancelledQuery.isLoading); + return ( -
+
-

Active reservations

-

- Showing currently active reservations. History is coming soon. -

+
+

Active reservations

+
+ +
+ +
+
+

History

+ +
+ {showHistory ? ( + isHistoryLoading ? ( +

Loading…

+ ) : ( + + ) + ) : ( +

+ Click “Show history” to load ended and cancelled reservations. +

+ )}
-
); } diff --git a/src/components/clients/client-tabs.tsx b/src/components/clients/client-tabs.tsx index 05b4243..719b6c2 100644 --- a/src/components/clients/client-tabs.tsx +++ b/src/components/clients/client-tabs.tsx @@ -14,6 +14,7 @@ import { ClientPipelineSummary } from '@/components/clients/client-pipeline-summ import { ClientYachtsTab } from '@/components/clients/client-yachts-tab'; import { ClientCompaniesTab } from '@/components/clients/client-companies-tab'; import { ClientReservationsTab } from '@/components/clients/client-reservations-tab'; +import { ClientFilesTab } from '@/components/clients/client-files-tab'; import { ContactsEditor } from '@/components/clients/contacts-editor'; import { AddressesEditor, type Address } from '@/components/shared/addresses-editor'; import { EntityActivityFeed } from '@/components/shared/entity-activity-feed'; @@ -271,11 +272,7 @@ export function getClientTabs({ clientId, currentUserId, client }: ClientTabsOpt { id: 'files', label: 'Files', - content: ( -
-

File attachments coming soon.

-
- ), + content: , }, { id: 'activity', diff --git a/src/components/companies/company-tabs.tsx b/src/components/companies/company-tabs.tsx index 59b147b..551820f 100644 --- a/src/components/companies/company-tabs.tsx +++ b/src/components/companies/company-tabs.tsx @@ -3,7 +3,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import type { DetailTab } from '@/components/shared/detail-layout'; -import { EmptyState } from '@/components/shared/empty-state'; import { InlineEditableField } from '@/components/shared/inline-editable-field'; import { InlineCountryField } from '@/components/shared/inline-country-field'; import { SubdivisionCombobox } from '@/components/shared/subdivision-combobox'; @@ -227,11 +226,9 @@ export function getCompanyTabs({ /> ), }, - { - id: 'documents', - label: 'Documents', - content: , - }, + // The Documents tab was a "Coming soon" stub. Hidden until the + // /api/v1/files endpoint accepts a companyId filter (the schema + // supports it; the validator doesn't). { id: 'notes', label: 'Notes',