feat(uat-batch): Group C Berth list features (3 new ships + 1 verified)
C20–C23 from the 2026-05-21 plan.
Shipped now:
C21 Dimensions ft/m column toggle persisted to user prefs.
`TablePreferences.dimensionUnit` ('ft' | 'm') added to the user-
profiles JSONB. `useTablePreferences` returns `dimensionUnit` +
`setDimensionUnit` alongside hidden/density. New
`getBerthColumns(unit)` factory rewrites the dimensions /
nominalBoatSize / waterDepth cells when ft is requested
(waterDepth converts on-the-fly from the canonical meters
column at 3.2808 ft/m). Berth-list toolbar gains a small
ft/m toggle button next to the density toggle.
C22 ft/m switching on Berth Requirements rows.
`interest-tabs.tsx` Berth-requirements section now honours
`interest.desiredLengthUnit`. Labels flip to "(m)" when set;
value reads from `desired*M` columns; on save, both the chosen-
unit and the canonical counterpart columns are PATCHed (3.28084
ratio) so downstream surfaces (recommender, EOI merge fields)
stay in lockstep. `InterestPatchField` widened with `desired*M`
variants.
C23 Berth list bulk-edit affordance.
New `POST /api/v1/berths/bulk` (mirror of /interests/bulk):
discriminated union of `change_status` / `change_tenure_type` /
`add_tag` / `remove_tag` / `archive`, 500-id cap, per-row
failure reporting, single `berths.edit` permission gate
(no separate `archive` perm exists on berths today). Status
mutations route through `updateBerthStatus` so under-offer /
sold transitions still trigger the primary interest_berths
auto-link + the rules-engine evaluation.
BerthList toolbar wires `bulkActions` on the DataTable —
Change status (Select dialog), Change tenure (permanent /
fixed-term), Add tag, Remove tag, Archive (destructive +
confirmation). Each dialog uses the same `bulkMutation` so
toast + cache-invalidation behaviour is consistent across
actions.
Already shipped (verified):
C20 Berth list rates / pricing valid columns hidden by default —
already in `BERTH_DEFAULT_HIDDEN`.
Verified: tsc clean, vitest 1454/1454.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,12 +41,14 @@ export function useTablePreferences(entityType: string, defaultHidden: string[]
|
||||
const remoteEntry = meQuery.data?.data.preferences?.tablePreferences?.[entityType];
|
||||
const remoteHidden = remoteEntry?.hiddenColumns;
|
||||
const remoteDensity = remoteEntry?.density;
|
||||
const remoteDimensionUnit = remoteEntry?.dimensionUnit;
|
||||
// Local edits win over the server-loaded prefs. The render-phase
|
||||
// derivation below (`localHidden ?? remoteHidden ?? defaultHidden`)
|
||||
// replaces the prior useEffect(setLocalHidden, [remoteHidden]) sync
|
||||
// that the Compiler flagged as set-state-in-effect.
|
||||
const [localHidden, setLocalHidden] = useState<string[] | null>(null);
|
||||
const [localDensity, setLocalDensity] = useState<'comfortable' | 'compact' | null>(null);
|
||||
const [localDimensionUnit, setLocalDimensionUnit] = useState<'ft' | 'm' | null>(null);
|
||||
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
@@ -109,6 +111,14 @@ export function useTablePreferences(entityType: string, defaultHidden: string[]
|
||||
[flush],
|
||||
);
|
||||
|
||||
const setDimensionUnit = useCallback(
|
||||
(next: 'ft' | 'm') => {
|
||||
setLocalDimensionUnit(next);
|
||||
flush({ dimensionUnit: next });
|
||||
},
|
||||
[flush],
|
||||
);
|
||||
|
||||
// Cleanup pending timer on unmount so React doesn't warn about
|
||||
// setting state after the component is gone.
|
||||
useEffect(
|
||||
@@ -125,12 +135,17 @@ export function useTablePreferences(entityType: string, defaultHidden: string[]
|
||||
// the never-saved case.
|
||||
const resolved = localHidden ?? remoteHidden ?? defaultHidden;
|
||||
const density: 'comfortable' | 'compact' = localDensity ?? remoteDensity ?? 'comfortable';
|
||||
// Dimension unit: local optimistic → remote saved → 'ft' fallback (matches
|
||||
// the existing canonical-format-in-feet shape of the underlying columns).
|
||||
const dimensionUnit: 'ft' | 'm' = localDimensionUnit ?? remoteDimensionUnit ?? 'ft';
|
||||
|
||||
return {
|
||||
hidden: resolved,
|
||||
setHidden,
|
||||
density,
|
||||
setDensity,
|
||||
dimensionUnit,
|
||||
setDimensionUnit,
|
||||
isLoaded: !meQuery.isLoading,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user