// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // Projet : Groupe Ka / Ka Maps (intégration Vrai-Prix) // lib/kamaps.ts : thème Vrai-Prix Maps + adaptateur /api/nearby. // La carte affiche des VALEURS ESTIMÉES (jamais des prix demandés) : // pastilles encre à liseré rouge #ff5148, sélection rouge — le langage // visuel du site (encre #141814, « lime » rouge, bordeaux #9e2a25). import type { BoundsQuery, BoundsQueryResult, KaDataAdapter, KaMapTheme, MapProperty, } from "@groupe-ka/ka-maps"; const INK = "#141814"; const RED = "#ff5148"; // --lime (nom hérité) const BORDEAUX = "#9e2a25"; // --green (nom hérité) export const MAPBOX_TOKEN: string = process.env.NEXT_PUBLIC_MAPBOX_TOKEN ?? "pk.eyJ1Ijoic3Bib3VjaGVyIiwiYSI6ImNtc3Fyb3k4djAwOTgyenB3dWt6NHBjc2kifQ.poqLf0ADy3lIh28O-pFI2Q"; /** Zoom minimal de chargement : sous ce niveau, on invite à zoomer. */ export const MIN_ZOOM_FETCH = 12; export const TYPE_FR: Record = { unifamilial: "Unifamiliale", condo_ou_multi: "Condo / multi", plex: "Plex", chalet: "Chalet", terrain: "Terrain", maison_mobile: "Maison mobile", autre: "Autre", }; export const vraiPrixMapTheme: KaMapTheme = { id: "vrai-prix", productName: "Vrai-Prix Maps", accent: RED, onAccent: "#ffffff", fontFamily: "var(--font-inter), system-ui, sans-serif", markers: { sale: { background: INK, text: "#ffffff", halo: RED, selectedBackground: RED, selectedText: "#ffffff", }, // Valeurs estimées : pastille encre, liseré rouge — visuellement // distinctes d'un prix demandé (jamais présentées comme une annonce). valuation: { background: INK, text: "#ffffff", halo: RED, selectedBackground: RED, selectedText: "#ffffff", }, }, cluster: { background: BORDEAUX, text: "#ffffff", border: "rgba(255,81,72,0.5)", }, supportsDark: false, }; interface NearbyUnit { id: string; adresse: string | null; apt: string | null; municipalite: string | null; typeProp: string | null; lat: number; lng: number; est2026: number | null; } function toMapProperty(u: NearbyUnit): MapProperty { return { id: u.id, appSource: "vrai-prix", latitude: u.lat, longitude: u.lng, kind: "valuation", estimatedValue: u.est2026 ?? undefined, propertyType: u.typeProp ? TYPE_FR[u.typeProp] ?? u.typeProp : undefined, address: u.apt ? `${u.adresse} app. ${u.apt}` : u.adresse ?? undefined, city: u.municipalite ?? undefined, originalUrl: `/estimation/${u.id}`, extra: { typeProp: u.typeProp }, }; } /** Adaptateur viewport→données : /api/nearby (contrat partagé avec iOS). */ export const vraiPrixMapAdapter: KaDataAdapter = { id: "vrai-prix-nearby", appSource: "vrai-prix", async fetchInBounds(query: BoundsQuery): Promise { if (query.zoom < MIN_ZOOM_FETCH) return { properties: [] }; const { bbox } = query; const lat = (bbox.north + bbox.south) / 2; const lng = (bbox.east + bbox.west) / 2; const halfLat = Math.abs(bbox.north - lat); const halfLng = Math.abs(bbox.east - lng); const params = new URLSearchParams({ lat: lat.toFixed(6), lng: lng.toFixed(6), halfLat: halfLat.toFixed(6), halfLng: halfLng.toFixed(6), limit: "1500", }); const res = await fetch(`/api/nearby?${params}`, { signal: query.signal }); if (!res.ok) throw new Error(`Carte : API ${res.status}`); const data = (await res.json()) as { results: NearbyUnit[] }; return { properties: data.results.map(toMapProperty) }; }, };