Vrai-Prix — l'évaluation du vrai prix des propriétés résidentielles au Québec.
TypeScript 90.2%
JavaScript 3.5%
Python 3.4%
CSS 1.9%
HTML 0.6%
1"use client";2// Auteur : Simon-Pierre Boucher — contact@spboucher.ai3// Projet : Groupe Ka / Ka Maps (intégration Vrai-Prix)4// components/KaCarte.tsx : Vrai-Prix Maps — recherche par carte propulsée5// par le framework partagé Ka Maps (moteur Mapbox GL, style Standard 3D par6// défaut + bouton 2D). Remplace l'ancienne carte Leaflet/OSM : pastilles de7// VALEURS ESTIMÉES 2026 (grappes + moyennes), chargement piloté par le8// viewport (annulation, cache), aperçu React, bilingue FR/EN.9// À charger via next/dynamic({ ssr: false }) — Mapbox GL est navigateur-seul.1011import { useState } from "react";12import { useRouter } from "next/navigation";13import "mapbox-gl/dist/mapbox-gl.css";14import "@groupe-ka/ka-maps/styles.css";15import type { MapProperty } from "@groupe-ka/ka-maps";16import { formatFullPrice } from "@groupe-ka/ka-maps";17import {18 KaBrandBadge,19 KaMapView,20 LoadingIndicator,21 LocateControl,22 PropertyPreview,23 Tilt3DControl,24} from "@groupe-ka/ka-maps/react";25import { useLang } from "@/components/LangContext";26import {27 MAPBOX_TOKEN,28 MIN_ZOOM_FETCH,29 vraiPrixMapAdapter,30 vraiPrixMapTheme,31} from "@/lib/kamaps";3233const DEFAULT_CENTER = { lat: 45.5421, lng: -73.6646 }; // Montréal3435/** Aperçu d'une unité d'évaluation — valeur estimée, jamais un prix. */36function PreviewCard({ p, fr, close }: { p: MapProperty; fr: boolean; close: () => void }) {37 const router = useRouter();38 return (39 <div className="vpm-pop">40 <div className="klabel">{fr ? "Estimation 2026" : "2026 estimate"}</div>41 <div className="vpm-pop-value">42 {p.estimatedValue != null ? formatFullPrice(p.estimatedValue) : "—"}43 </div>44 <div className="vpm-pop-addr">{p.address}</div>45 <div className="vpm-pop-meta">46 {[p.city, p.propertyType].filter(Boolean).join(" · ")}47 </div>48 <button49 type="button"50 className="vpm-pop-cta"51 onClick={() => {52 close();53 router.push(p.originalUrl ?? "/");54 }}55 >56 {fr ? "Voir l'estimation complète →" : "See full estimate →"}57 </button>58 </div>59 );60}6162export default function KaCarte() {63 const { lang } = useLang();64 const fr = lang === "fr";65 const [zoom, setZoom] = useState(13);66 const [count, setCount] = useState<number | null>(null);6768 const zoomedOut = zoom < MIN_ZOOM_FETCH;6970 return (71 <div className="vpm-wrap">72 <KaMapView73 theme={vraiPrixMapTheme}74 adapter={vraiPrixMapAdapter}75 mapboxToken={MAPBOX_TOKEN}76 center={DEFAULT_CENTER}77 zoom={13.5}78 pitch={50}79 searchMode="auto"80 cluster={{ maxZoom: 15, radius: 44, valueClamp: [40_000, 5_000_000] }}81 onMoveEnd={(_c, z) => setZoom(z)}82 onData={(c) => setCount(c)}83 >84 <KaBrandBadge />85 <Tilt3DControl />86 <LocateControl label={fr ? "Me localiser" : "Locate me"} />87 <LoadingIndicator label={fr ? "Mise à jour des estimations…" : "Updating estimates…"} />88 <PropertyPreview89 render={(p, close) => <PreviewCard p={p} fr={fr} close={close} />}90 />91 <div className="vpm-chip" role="status">92 {zoomedOut93 ? fr94 ? "Zoomez pour voir les valeurs estimées"95 : "Zoom in to see estimated values"96 : count != null97 ? fr98 ? `${count.toLocaleString("fr-CA")} propriétés affichées`99 : `${count.toLocaleString("en-CA")} properties shown`100 : fr101 ? "Chargement…"102 : "Loading…"}103 </div>104 </KaMapView>105 </div>106 );107}108