feat(berths): NocoDB-aligned dropdown enums + dual-unit auto-fill

Pull verbatim SingleSelect choices from NocoDB Berths via MCP and lock
them into BERTH_*_OPTIONS / _TYPES in lib/constants.ts: Side Pontoon
(10 values), Mooring Type (5), Cleat Type (2), Cleat Capacity (2),
Bollard Type (2), Bollard Capacity (2), Access (5), Area (A–E), Bow
Facing (4-value UX-only constraint over a SingleLineText). Power
Capacity / Voltage stay numeric inputs (NocoDB stores Number).

Add `toSelectOptions()` mapper for shadcn `<Select>` `{value,label}`
pairs.

Wire every berth dropdown — both the modal form and the inline-edit
detail tabs — to `<Select>`. Inline `EditableSpec` gains
`selectOptions` for the variant and `linkedUnit { field, multiplier }`
to auto-patch the metric column on save (× 0.3048 for ft→m on length,
width, draft, nominal boat size, water depth).

Promote nominal boat size + tenure type from read-only `<SpecRow>` to
`<EditableSpec>` so reps can edit them. Tenure type currently uses the
validator's `'permanent' | 'fixed_term'` set; will swap to per-port
configurable list once Vocabularies admin lands (Wave 5).

Mobile berth cards: replace status-coloured stripe with
`mooringLetterDot()` so it groups by dock letter; status conveyed by
the existing pill below. Berth detail header: "{Letter} Dock" chip
instead of bare "A" / "B" text. Berth area filter: `<Select>` over
A/B/C/D/E (renamed to "Dock"). Documents tab gets a one-paragraph
explainer disambiguating the spec PDF from deal documents (Interests
tab).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 04:10:24 +02:00
parent 4d6a293534
commit e13232e2ad
7 changed files with 129 additions and 33 deletions

View File

@@ -27,6 +27,7 @@ import { Textarea } from '@/components/ui/textarea';
import { DetailHeaderStrip } from '@/components/shared/detail-header-strip';
import { PermissionGate } from '@/components/shared/permission-gate';
import { BerthForm } from './berth-form';
import { mooringLetterDot } from './mooring-letter-tone';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import { updateBerthStatusSchema, type UpdateBerthStatusInput } from '@/lib/validators/berths';
@@ -193,7 +194,15 @@ export function BerthDetailHeader({ berth }: BerthDetailHeaderProps) {
{STATUS_LABELS[berth.status] ?? berth.status}
</span>
</div>
{berth.area && <p className="text-muted-foreground mt-1">{berth.area}</p>}
{berth.area && (
<div className="mt-2">
<span
className={`inline-flex items-center gap-1.5 rounded-full px-3 py-0.5 text-xs font-semibold uppercase tracking-wide text-white ${mooringLetterDot(berth.mooringNumber) ?? 'bg-slate-400'}`}
>
{berth.area} Dock
</span>
</div>
)}
</div>
<div className="flex flex-wrap items-center gap-2 sm:shrink-0">