export default class BoundingBox { x1: number = null; x2: number = null; y1: number = null; y2: number = null; /** * QA_AT-11: round a GPS coordinate to 6 decimal places (~11 cm precision). * Single source of truth for client-side coordinate rounding — shared by * `GpsInput` (map right-click / typed-blur paths) and `GpsBoundingBoxInput` * (typed-blur path) so a coordinate stored from ANY path is normalised to 6 * decimals IMMEDIATELY, not only at server persist time. * * Mirrors the server-side `GpsHelper.roundCoord` exactly (numeric rounding, * not string truncation) — `null` / `undefined` pass through unchanged. */ static roundCoord(value: number | null | undefined): number | null { if (value == null) { return null; } return Math.round(value * 1e6) / 1e6; } /** * QA_AT-8: build a ~3 km square bbox centred on a GPS point. Used by * the Resort modal's auto-fill (and Reset-bbox-from-GPS button) plus * the dummy-resort seed so both call sites stay in lock-step. * * - half-width = 0.042 longitude degrees (~3 km at SK/CZ latitudes) * - half-height = 0.031 latitude degrees (~3.4 km) */ static fromGpsPoint(latitude: number, longitude: number): BoundingBox { const bbox = new BoundingBox(); bbox.x1 = longitude - 0.042; bbox.x2 = longitude + 0.042; bbox.y1 = latitude - 0.031; bbox.y2 = latitude + 0.031; return bbox; } /** * QA_AT-8: shared bbox save-time validation predicate used by every modal * that surfaces a `GpsBoundingBoxInput` (Resort + Location today; future * consumers go through the same helper). Returns the list of localised * error strings the caller should render inline. * * Rules: * - all four corners must be set OR all four must be null (mixed → * `gpsBboxIncompleteError`). * - `x1 < x2` (west longitude < east longitude); otherwise * `gpsBboxWestEastError`. * - `y1 < y2` (south latitude < north latitude); otherwise * `gpsBboxSouthNorthError`. * * Callers pass the already-localised strings from their `resources` so the * helper stays in `_common/` (no i18n coupling). * * Extracted from the previously-duplicated `validateBbox()` methods on * `ResortManagementModal` + `LocationManagementModal` + the qa-at-8 spec * mirror — per `feedback_no_parallel_code_path.md`. */ static validate(bbox: BoundingBox | null | undefined, resources: { gpsBboxIncompleteError: string; gpsBboxWestEastError: string; gpsBboxSouthNorthError: string; }): string[] { const errors: string[] = []; if (!bbox) { return errors; } const corners = [ bbox.x1, bbox.x2, bbox.y1, bbox.y2, ]; const filled = corners.filter(v => v != null).length; if (filled > 0 && filled < 4) { errors.push(resources.gpsBboxIncompleteError); return errors; } if (filled === 0) { return errors; } if (bbox.x1 >= bbox.x2) { errors.push(resources.gpsBboxWestEastError); } if (bbox.y1 >= bbox.y2) { errors.push(resources.gpsBboxSouthNorthError); } return errors; } }