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:
@@ -14,6 +14,7 @@ import { TagBadge } from '@/components/shared/tag-badge';
|
||||
import { ListCard, ListCardAvatar, ListCardMeta } from '@/components/shared/list-card';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { BerthRow } from './berth-columns';
|
||||
import { mooringLetterDot } from './mooring-letter-tone';
|
||||
|
||||
const STATUS_VARIANTS: Record<string, string> = {
|
||||
available: 'bg-green-100 text-green-800 border-green-200',
|
||||
@@ -27,12 +28,6 @@ const STATUS_LABELS: Record<string, string> = {
|
||||
sold: 'Sold',
|
||||
};
|
||||
|
||||
const ACCENT_CLASS: Record<string, string> = {
|
||||
available: 'bg-emerald-400',
|
||||
under_offer: 'bg-amber-400',
|
||||
sold: 'bg-slate-400',
|
||||
};
|
||||
|
||||
function formatPrice(price: string, currency: string): string {
|
||||
try {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
@@ -57,7 +52,9 @@ export function BerthCard({ berth }: BerthCardProps) {
|
||||
const statusLabel = STATUS_LABELS[berth.status] ?? berth.status;
|
||||
const statusColor =
|
||||
STATUS_VARIANTS[berth.status] ?? 'bg-muted text-muted-foreground border-muted';
|
||||
const accentClass = ACCENT_CLASS[berth.status] ?? 'bg-slate-300';
|
||||
// Accent stripe groups visually by dock (A-row, B-row, ...). Status is
|
||||
// already conveyed by the pill below, so the stripe is dock-keyed.
|
||||
const accentClass = mooringLetterDot(berth.mooringNumber) ?? 'bg-slate-300';
|
||||
|
||||
// Dimensions string
|
||||
let dimText: string | null = null;
|
||||
|
||||
Reference in New Issue
Block a user