spb/vrai-prix-ios Public
App iOS native de Vrai-Prix — estimation immobilière transparente pour le Québec (SwiftUI, MapKit, Swift Charts)
Swift 100%
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// Modèles Codable — miroir des types de l'API Vrai-Prix (src/lib/estimator.ts, engine.ts).3import Foundation45// MARK: - Recherche d'adresse (/api/search)67struct SearchResponse: Decodable {8 let results: [SearchResult]9}1011struct SearchResult: Decodable, Identifiable, Hashable {12 let id: String13 let adresse: String?14 let apt: String?15 let municipalite: String?16 let typeProp: String?17}1819// MARK: - Estimation (/api/estimate)2021struct UnitEstimate: Decodable {22 let unit: PropertyUnit?23 let result: EstimateResult24}2526struct PropertyUnit: Decodable {27 let id: String28 let adresse: String?29 let municipalite: String?30 let typeProp: String31 let cubfLibelle: String?32 let anneeConstruction: Int?33 let aireEtagesM2: Double?34 let superficieTerrainM2: Double?35 let nbLogements: Int?36 let valeurRole: Double?37 let lat: Double38 let lng: Double39 let history: [HistoryPoint]40 let specs: UnitSpecs41}4243struct HistoryPoint: Decodable, Identifiable {44 let year: Int45 let value: Double?46 var id: Int { year }47}4849struct UnitSpecs: Decodable {50 let cubf: Int?51 let cubfLibelle: String?52 let anneeEstimee: String?53 let frontTerrainM: Double?54 let nbEtages: Int?55 let nbLocauxNonResid: Int?56 let nbChambresLocatives: Int?57 let lienPhysique: String?58 let genreConstruction: String?59 let matricule: String?60 let uniteVoisinage: String?61 let nAdresses: Int?62 let datCondMarche: String?63 let valeurTerrain: Double?64 let valeurBatiment: Double?65 let valeurAnterieure: Double?66 let arrond: String?67 let apt: String?68}6970struct EstimateResult: Decodable {71 let estimate: Double72 let low: Double73 let high: Double74 let confidencePct: Double75 let confidenceLevel: String // A | B | C | D76 let modelEstimate: Double?77 let compsEstimate: Double?78 let modelWeight: Double79 let comps: [AdjustedComp]80 let nCompsUsed: Int81 let compsDispersionPct: Double?82}8384struct AdjustedComp: Decodable, Identifiable {85 let id: String86 let date: String // YYYY-MM-DD87 let amount: Double88 let lat: Double89 let lng: Double90 let propertyType: String?91 let yearBuilt: Int?92 let floorArea: Double?93 let street: String?94 let city: String?95 let distanceM: Double96 let monthsAgo: Double97 let adjTime: Double98 let adjArea: Double99 let adjAge: Double100 let adjustedPrice: Double101 let weight: Double102}103104// MARK: - Recherche par carte (/api/nearby)105106struct NearbyResponse: Decodable {107 let results: [NearbyUnit]108}109110struct NearbyUnit: Decodable, Identifiable, Hashable {111 let id: String112 let adresse: String?113 let apt: String?114 let municipalite: String?115 let typeProp: String116 let lat: Double117 let lng: Double118 let est2026: Double?119120 /// Pour réutiliser EstimateLoaderView (même écran que la recherche texte).121 var asSearchResult: SearchResult {122 SearchResult(id: id, adresse: adresse, apt: apt, municipalite: municipalite, typeProp: typeProp)123 }124}125126/// Erreur renvoyée par l'API ({"error": "..."}).127struct APIErrorPayload: Decodable {128 let error: String129}130131/// Libellés français des types de propriété (mêmes clés que le moteur).132enum PropType: String, CaseIterable, Identifiable {133 case unifamilial134 case plex135 case condoOuMulti = "condo_ou_multi"136 case chalet137 case maisonMobile = "maison_mobile"138 case terrain139140 var id: String { rawValue }141142 var label: String {143 switch self {144 case .unifamilial: return "Unifamiliale"145 case .plex: return "Plex"146 case .condoOuMulti: return "Condo / multi"147 case .chalet: return "Chalet"148 case .maisonMobile: return "Maison mobile"149 case .terrain: return "Terrain"150 }151 }152153 static func label(for raw: String?) -> String {154 guard let raw, let t = PropType(rawValue: raw) else { return raw ?? "—" }155 return t.label156 }157}158