SPB Git forge

spb/ka-maps

Public
6commits 1branches 0releases
448.0 KBsize
maindefault branch
29 days agolast push
TypeScript 87.7% CSS 12.3%
5.0 KB

# Ka Maps — Synchronisation liste ↔ carte (le modèle Groupe-KA)

Référence du module « recherche synchronisée » introduit avec Lou-Ka (frontend/src/search/MapSearch.tsx), conçu pour être décliné tel quel sur immo-ka, resto-ka, sorti-ka et servir de contrat à l'app iOS KA.

# Le principe : une seule vérité partagée

La liste et la carte sont deux vues du même état de recherche :

text
État = { filtres, zone (bbox visible OU polygone dessiné), tri, page }

Chaque changement d'état déclenche UNE requête vers l'endpoint unifié (/api/search chez Lou-Ka) qui renvoie dans la même réponse :

Champ Rôle
total compteur partagé — affiché en tête de liste, égal PAR CONSTRUCTION au nombre de points carte
listings la page de liste demandée (objets complets)
points TOUS les points carte au format compact [uid, lng, lat, prix, verdict], triés comme la liste
unpositioned annonces filtrées sans coordonnées (affichées honnêtement, jamais silencieusement perdues)

Corollaires structurels (pas des efforts de synchronisation, des invariants) :

  • compteur liste = nombre de marqueurs, dans 100 % des cas ;
  • index d'un uid dans points ÷ page_size = sa page de liste → un clic sur n'importe quel marqueur peut TOUJOURS faire défiler la liste vers l'annonce, même si elle est sur une autre page ;
  • aucune requête périmée ne peut écraser une récente (numéro de séquence + AbortController ; le serveur n'est jamais la source du tri d'arrivée).

# Répartition des rôles

Ka Maps (framework) fournit :

  • KaMap.fitBounds(bbox) / fitToProperties() — recadrages animés marqués programmés ;
  • moveend { byUser } — distinction geste utilisateur / mouvement du code, c'est la clé du « respect de l'intention » : seuls les gestes verrouillent la vue (userLocked) et déclenchent la recherche par zone ;
  • sélection & survol bidirectionnels par feature-state GPU (select(uid, "map"|"app"), setHovered, événements select/hover) ;
  • outil polygone intégré (startDraw, clearDrawnPolygon, setDrawnPolygon, événement draw) + <DrawControl/> ;
  • fourchette de prix des clusters au survol (clusterHover, accumulateurs valueMin/valueMax) ;
  • état « vu » (setSeenIds) — pastilles atténuées des annonces consultées ;
  • utilitaires : bboxOfProperties, pointInPolygon, bboxToString, cameraToParams/cameraFromParams.

L'app possède : l'état de recherche, la requête unifiée, l'URL, la liste, le carrousel mobile et le langage visuel des cartes/mini-fiches.

# La machine d'états côté app (copier ce comportement)

  1. Arrivée sans caméra dans l'URL : requête sans zone → fitBounds animé sur les résultats (byUser: false, ne verrouille pas la vue).
  2. Arrivée avec caméra (lien partagé) : la zone visible restaurée devient la contrainte spatiale de la première requête ; vue considérée verrouillée.
  3. Geste utilisateur (byUser: true) : verrouille la vue ; si « Rechercher quand je déplace la carte » (défaut : coché) → nouvelle requête avec la bbox (debounce ~250 ms après la fin du geste) ; sinon marquer la zone divergée et montrer « Rechercher dans cette zone ».
  4. Filtre modifié : page 1 ; si la vue n'est PAS verrouillée → requête sans zone + fitBounds ; si verrouillée → requête dans la zone courante et bouton discret « Recadrer sur les résultats ».
  5. Polygone dessiné : remplace la bbox (il EST la zone), devient une puce retirable, encodé dans l'URL (zone=lng,lat;…), fitBounds sur son contenu.
  6. Tri/page : même requête ; un changement de page passe include=liste (les points, identiques, ne sont pas retéléchargés).
  7. URL : caméra (lat/lng/zoom) + tri + page + zone + move=0 via replaceState — partager le lien reproduit la recherche à l'identique.

# Miroirs (latence < 100 ms)

  • survol carte d'annonce → setHovered(uid, "app") (feature-state, aucun re-rendu carte) ;
  • survol marqueur → événement hover → classe CSS sur la carte d'annonce + indicateur « ▲/▼ annonce hors écran » si elle n'est pas visible ;
  • clic marqueur → select → page ajustée au besoin → défilement animé + pulsation ;
  • clic annonce → select(uid, "app") → recentrage doux (uniquement si hors champ) + mini-fiche ; Cmd/Ctrl-clic ou 2ᵉ clic → navigation vers la fiche.

# Mobile

Bascule Liste ↔ Carte sans perte (état dans l'URL). En vue carte : carrousel horizontal scroll-snap en bas, alimenté par la MÊME page de liste ; balayage → sélection du marqueur (select, origin "app"), marqueur tapé → défilement du carrousel. Un seul état, deux projections.

# Anti-régression

  • E2E : lou-ka/scripts/test-sync.mjs (25 vérifications, critères 1-9).
  • Unitaires framework : ka-maps/tests/drawGeo.test.ts (+ suites existantes).
  • API : lou-ka/tests/test_search.py (règle d'or, tris, polygone, bornes).