// ----------------------------------------------------------------------------- // Lou-Ka — Location court terme // components/CtMapView.tsx : carte des hébergements court terme (Ka Maps), // pilotée par le viewport via /api/ct/listings.geojson — chargée paresseusement. // ----------------------------------------------------------------------------- import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import "mapbox-gl/dist/mapbox-gl.css"; import "@groupe-ka/ka-maps/styles.css"; import type { MapProperty } from "@groupe-ka/ka-maps"; import { cameraFromParams, cameraToParams } from "@groupe-ka/ka-maps"; import { KaBrandBadge, KaMapView, LoadingIndicator, PropertyPreview, ResultCount, SearchAreaControl, Tilt3DControl, } from "@groupe-ka/ka-maps/react"; import { CtFilters, ctSourceName } from "../ctapi"; import { louKaMapTheme } from "../kamaps/theme"; import { ctMapAdapter } from "../kamaps/ctAdapter"; import { MAPBOX_TOKEN } from "../kamaps/config"; const QUEBEC_CENTER = { lat: 46.82, lng: -71.25 }; function PreviewCard({ p }: { p: MapProperty }) { const navigate = useNavigate(); const extra = (p.extra ?? {}) as { title?: string | null; priceLabel?: string | null; capacity?: number | null; bedrooms?: number | null; rating?: number | null; source?: string; }; const prix = p.price != null ? `${p.price.toLocaleString("fr-CA", { maximumFractionDigits: 0 })} $` : extra.priceLabel || "Prix sur demande"; const meta = [ p.propertyType, extra.capacity ? `${extra.capacity} pers.` : "", extra.bedrooms ? `${extra.bedrooms} ch.` : "", extra.rating != null ? `★ ${extra.rating.toLocaleString("fr-CA", { maximumFractionDigits: 1 })}` : "", ].filter(Boolean).join(" · "); return (
{p.thumbnailUrl ? ( ) : ( )}
{prix} {p.price != null ? " /nuit" : ""}
{extra.title ?? p.address ?? ""}
{meta}
{ctSourceName(extra.source ?? "")}
{ e.preventDefault(); navigate(p.originalUrl ?? "/court-terme"); }} > Voir la fiche →
); } export default function CtMapView({ filters }: { filters: CtFilters }) { const initialCamera = useMemo(() => { const cam = cameraFromParams(new URLSearchParams(window.location.search)); return cam ?? { ...QUEBEC_CENTER, zoom: 6.2 }; }, []); const onMoveEnd = useCallback((center: { lat: number; lng: number }, zoom: number) => { const url = new URL(window.location.href); url.search = cameraToParams({ ...center, zoom }, url.searchParams).toString(); window.history.replaceState(null, "", url); }, []); const mapFilters = useMemo( () => Object.fromEntries(Object.entries(filters).filter(([, v]) => v)), [filters], ); return (
} />
); }