From 72ab7180cfedfa852dc8439d86bc1221e3eb5fc0 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 9 May 2026 04:16:42 +0200 Subject: [PATCH] feat(public-berths): expose booleans, metric variants, timestamps Bring the public berth feed to verbatim NocoDB parity (all fields except Price, which is held pending an explicit policy decision per the audit follow-ups Q4). Adds: - Berth Approved (boolean) - Water Depth (number) - Width Is Minimum / Water Depth Is Minimum (boolean) - Length / Width / Draft / Water Depth / Nominal Boat Size (Metric) - CreatedAt / UpdatedAt (ISO strings, useful for cache invalidation) Booleans pass through as nullable to preserve NocoDB's tri-state checkbox semantics (true / false / unset). Test fixtures cover the new fields end-to-end including the null-passthrough case. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/services/public-berths.ts | 22 +++++++++++++++++++ tests/unit/services/public-berths.test.ts | 26 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/lib/services/public-berths.ts b/src/lib/services/public-berths.ts index 066b510b..5ac18b2f 100644 --- a/src/lib/services/public-berths.ts +++ b/src/lib/services/public-berths.ts @@ -48,6 +48,17 @@ export interface PublicBerth { 'Bollard Capacity': string | null; 'Nominal Boat Size': number | null; Access: string | null; + 'Berth Approved': boolean | null; + 'Water Depth': number | null; + 'Width Is Minimum': boolean | null; + 'Water Depth Is Minimum': boolean | null; + 'Length (Metric)': number | null; + 'Width (Metric)': number | null; + 'Draft (Metric)': number | null; + 'Water Depth (Metric)': number | null; + 'Nominal Boat Size (Metric)': number | null; + CreatedAt: string; + UpdatedAt: string; 'Map Data'?: PublicMapData; } @@ -126,6 +137,17 @@ export function toPublicBerth( 'Bollard Capacity': toString(berth.bollardCapacity), 'Nominal Boat Size': toNumber(berth.nominalBoatSize), Access: toString(berth.access), + 'Berth Approved': berth.berthApproved, + 'Water Depth': toNumber(berth.waterDepth), + 'Width Is Minimum': berth.widthIsMinimum, + 'Water Depth Is Minimum': berth.waterDepthIsMinimum, + 'Length (Metric)': toNumber(berth.lengthM), + 'Width (Metric)': toNumber(berth.widthM), + 'Draft (Metric)': toNumber(berth.draftM), + 'Water Depth (Metric)': toNumber(berth.waterDepthM), + 'Nominal Boat Size (Metric)': toNumber(berth.nominalBoatSizeM), + CreatedAt: berth.createdAt.toISOString(), + UpdatedAt: berth.updatedAt.toISOString(), ...(mapMapData(mapData) ? { 'Map Data': mapMapData(mapData)! } : {}), }; } diff --git a/tests/unit/services/public-berths.test.ts b/tests/unit/services/public-berths.test.ts index 1a8e816c..a4ff9bd6 100644 --- a/tests/unit/services/public-berths.test.ts +++ b/tests/unit/services/public-berths.test.ts @@ -105,6 +105,32 @@ describe('toPublicBerth', () => { expect(out.Access).toBe('Car (3t) to Vessel'); }); + it('exposes booleans + metric variants + timestamps for verbatim NocoDB parity', () => { + const out = toPublicBerth(makeBerth(), null, false); + expect(out['Berth Approved']).toBe(false); + expect(out['Water Depth']).toBe(16.08); + expect(out['Width Is Minimum']).toBe(false); + expect(out['Water Depth Is Minimum']).toBe(false); + expect(out['Length (Metric)']).toBe(63); + expect(out['Width (Metric)']).toBe(14.19); + expect(out['Draft (Metric)']).toBe(4.42); + expect(out['Water Depth (Metric)']).toBe(4.9); + expect(out['Nominal Boat Size (Metric)']).toBe(60.96); + expect(out.CreatedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/); + expect(out.UpdatedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/); + }); + + it('preserves null booleans (NocoDB checkbox-tri-state parity)', () => { + const out = toPublicBerth( + makeBerth({ berthApproved: null, widthIsMinimum: null, waterDepthIsMinimum: null }), + null, + false, + ); + expect(out['Berth Approved']).toBeNull(); + expect(out['Width Is Minimum']).toBeNull(); + expect(out['Water Depth Is Minimum']).toBeNull(); + }); + it('inlines map data when present', () => { const out = toPublicBerth(makeBerth(), makeMapData(), false); expect(out['Map Data']).toEqual({