Immo-Ka — agrégateur des propriétés à vendre au Québec (73 connecteurs, ~40 000 annonces, React+FastAPI)
Python 47.5%
HTML 27.9%
TypeScript 15.5%
CSS 7.2%
JavaScript 2%
1// -----------------------------------------------------------------------------2// Author: Simon-Pierre Boucher3// Contact: contact@spboucher.ai4// Project: Groupe Ka / Ka Maps (Immo-Ka integration)5// kamaps/adapter.ts : adaptateur Immo-Ka → MapProperty. Le drapeau6// « highlight » marque les prix sous l'estimation Vrai-Prix (bonne affaire),7// même règle que l'ancienne carte : price ≤ vp×0,95 et ≥ vp×0,5.8// -----------------------------------------------------------------------------9import type {10 BoundsQuery,11 BoundsQueryResult,12 KaDataAdapter,13 MapProperty,14} from "@groupe-ka/ka-maps";15import { bboxToString } from "@groupe-ka/ka-maps";16import type { ListingFilters } from "../api";1718interface ImmoKaFeatureProps {19 uid: string;20 title: string | null;21 address: string | null;22 price: number | null;23 price_label: string | null;24 property_type: string | null;25 bedrooms: number | null;26 bathrooms: number | null;27 source: string;28 city: string | null;29 sector: string | null;30 image: string | null;31 vp: number | null;32}3334interface ImmoKaFC {35 type: "FeatureCollection";36 features: {37 geometry: { coordinates: [number, number] };38 properties: ImmoKaFeatureProps;39 }[];40 totalGeocoded?: number;41 totalMatching?: number;42}4344function toMapProperty(45 coords: [number, number],46 p: ImmoKaFeatureProps,47): MapProperty {48 const deal =49 p.price != null && p.vp != null && p.price <= p.vp * 0.95 && p.price >= p.vp * 0.5;50 return {51 id: p.uid,52 appSource: "immo-ka",53 longitude: coords[0],54 latitude: coords[1],55 kind: "listing",56 listingType: "sale",57 price: p.price ?? undefined,58 estimatedValue: p.vp ?? undefined,59 propertyType: p.property_type ?? undefined,60 bedrooms: p.bedrooms ?? undefined,61 bathrooms: p.bathrooms ?? undefined,62 address: p.address ?? p.title ?? undefined,63 city: p.city ?? undefined,64 region: p.sector ?? undefined,65 thumbnailUrl: p.image ?? undefined,66 originalUrl: `/propriete/${encodeURIComponent(p.uid)}`,67 highlight: deal,68 extra: {69 title: p.title,70 priceLabel: p.price_label,71 source: p.source,72 vp: p.vp,73 },74 };75}7677/** Adaptateur viewport→données pour la carte Immo-Ka. */78export const immoKaMapAdapter: KaDataAdapter = {79 id: "immo-ka-listings",80 appSource: "immo-ka",81 async fetchInBounds(query: BoundsQuery): Promise<BoundsQueryResult> {82 const params = new URLSearchParams();83 const filters = (query.filters ?? {}) as Partial<ListingFilters>;84 for (const [k, v] of Object.entries(filters)) {85 if (v && k !== "sort") params.set(k, String(v));86 }87 params.set("bbox", bboxToString(query.bbox));88 params.set("limit", "3000");8990 const res = await fetch(`/api/listings.geojson?${params}`, {91 signal: query.signal,92 });93 if (!res.ok) throw new Error(`Carte : API ${res.status}`);94 const data = (await res.json()) as ImmoKaFC;9596 return {97 properties: data.features.map((f) =>98 toMapProperty(f.geometry.coordinates, f.properties),99 ),100 totalCount: data.totalMatching,101 };102 },103};104