fix(yachts): ft↔m round-trip is lossless (4dp + canonical helpers)
Three copies of the imperial/metric conversion logic existed:
- src/components/yachts/yacht-dimensions.ts (canonical, used by
read-side `formatYachtDimensionsBothUnits`)
- src/components/yachts/yacht-form.tsx (create/edit sheet —
local `ftToM`/`mToFt` with 2dp precision)
- src/components/yachts/yacht-tabs.tsx (detail-tab inline
edit — local arithmetic with 2dp precision)
The 2dp rounding lost precision on the round-trip: `1 ft → 0.30 m →
0.98 ft`. Whenever a rep entered ft, then later touched the m field,
the ft column silently shifted off. Same for sub-meter draft values.
Consolidate both surfaces onto `feetToMeters` / `metersToFeet` from
yacht-dimensions.ts and bump display precision to 4dp. After
trimZero strips trailing zeros the rendered string stays clean
("3.81" not "3.8100") but the round-trip now lands back on the
original value:
1 ft → 0.3048 m → 1 ft
12.5 ft → 3.81 m → 12.5 ft
50 ft → 15.24 m → 50 ft
0.5 m → 1.6404 ft → 0.5 m
New unit test (`tests/unit/yacht-dimensions.test.ts`) covers the
helpers + the form-shape round-trip, including the canonical
12.5 ft ↔ 3.81 m case from the UAT bug report.
29/29 new tests pass; full vitest 1448/1448.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import { EntityActivityFeed } from '@/components/shared/entity-activity-feed';
|
||||
import { ReservationList, type ReservationRow } from '@/components/reservations/reservation-list';
|
||||
import { RemindersInline } from '@/components/reminders/reminders-inline';
|
||||
import { YachtOwnershipHistory } from '@/components/yachts/yacht-ownership-history';
|
||||
import { feetToMeters, metersToFeet } from '@/components/yachts/yacht-dimensions';
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import { stageLabel } from '@/lib/constants';
|
||||
|
||||
@@ -131,12 +132,13 @@ function OverviewTab({
|
||||
await mutation.mutateAsync({ [primaryField]: next });
|
||||
return;
|
||||
}
|
||||
const FT_PER_M = 3.28084;
|
||||
const converted = isFt ? n / FT_PER_M : n * FT_PER_M;
|
||||
const convertedStr = converted
|
||||
.toFixed(2)
|
||||
.replace(/\.0+$/, '')
|
||||
.replace(/(\.\d)0$/, '$1');
|
||||
// Delegate the math to the canonical helpers in yacht-dimensions.ts
|
||||
// so this surface, the create-form, and the read-side formatter all
|
||||
// round-trip identically. 4dp precision keeps `1 ft → 0.3048 m →
|
||||
// 1.0000 ft` (after trimZero → "1"); 2dp lost data on small values.
|
||||
const converted = isFt ? feetToMeters(next) : metersToFeet(next);
|
||||
const convertedStr =
|
||||
converted === null ? '' : converted.toFixed(4).replace(/0+$/, '').replace(/\.$/, '');
|
||||
await mutation.mutateAsync({
|
||||
[primaryField]: next,
|
||||
[counterpart]: convertedStr,
|
||||
|
||||
Reference in New Issue
Block a user