--- description: Entities with latitude/longitude must pick coords on OSM LocationMap in forms and render LocationMap on detail pages globs: apps/web/src/apps/main/modules/**/*.{ts,tsx} alwaysApply: false --- # Location maps (lat / lng) If an entity, DTO, or Zod schema has `latitude` and `longitude`, it is a **location entity**. Do not ship lat/lng as number fields alone. Canonical component: `LocationMap` from `@repo/ui/map` (OpenStreetMap / Leaflet). Do not add Google Maps, Mapbox, or a second Leaflet wrapper. Line geometry (`routeGeometry`) uses `RouteMap`, not `LocationMap`. ## Form (required) Full-width `LocationMap` **above** the lat/lng inputs. Clicking the map writes both fields. Keep `FieldNumberInput` so values can still be typed. ```tsx // ✅ GOOD { formControl.setValue('latitude', point.latitude, { shouldDirty: true, shouldValidate: true }); formControl.setValue('longitude', point.longitude, { shouldDirty: true, shouldValidate: true }); }} /> // ❌ BAD — lat/lng inputs with no map picker ``` Layout: map is full width (form-layout compound field). Lat/lng stay a two-column pair under the map. Copy `customers` / `branches` `form-location.tsx`. ## Detail (required) Render `LocationMap` **without** `onChange` (read-only). Pass `emptyLabel` when coords are missing. Keep `FieldValue` for the numeric pair under the map. ```tsx // ✅ GOOD // ❌ BAD — coordinates as text only ``` Copy `customers` / `branches` `detail-location.tsx`. ## i18n and validation - Helper / empty copy: `common:map.pickLocation`, `common:map.noLocation` - Labels: `common:fields.latitude`, `common:fields.longitude` - Keep existing Zod lat/lng range checks (`optionalLatitudeSchema` / `optionalLongitudeSchema`)