// Vrai-Prix — méthode du coût : marqueurs de provenance (● observé ◐ calculé ○ indexé ◇ référence/hypothèse · AI), // badges de couche (OBSERVÉ · INFÉRÉ PAR IA · CALCULÉ · PRIX SOURCÉ · HYPOTHÈSE) et origine des caractéristiques. "use client"; import type { AttributeSource, Layer, PriceKind } from "@/lib/cost/types"; export function kindGlyph(kind: PriceKind | null | undefined): string { switch (kind) { case "observed": case "official": return "●"; case "derived": return "◐"; case "indexed": return "○"; case "reference": case "assumption": return "◇"; default: return "·"; } } export function kindLabel(kind: PriceKind | null | undefined, fr: boolean): string { switch (kind) { case "observed": return fr ? "Observé directement" : "Directly observed"; case "official": return fr ? "Publication officielle" : "Official publication"; case "derived": return fr ? "Calculé depuis composants" : "Computed from components"; case "indexed": return fr ? "Indexé" : "Indexed"; case "reference": return fr ? "Référence interne (hypothèse)" : "Internal reference (assumption)"; case "assumption": return fr ? "Hypothèse" : "Assumption"; default: return fr ? "Donnée non disponible" : "Data not available"; } } export function kindTooltip(p: { kind: PriceKind | null | undefined; source?: string | null; observedAt?: string | null; note?: string | null }, fr: boolean): string { const d = p.observedAt ? fmtDate(p.observedAt, fr) : null; switch (p.kind) { case "observed": return fr ? `Observé directement chez ${p.source ?? "un fournisseur"}${d ? ` le ${d}` : ""}.` : `Directly observed at ${p.source ?? "a supplier"}${d ? ` on ${d}` : ""}.`; case "official": return fr ? `Taux publié par ${p.source ?? "une source officielle"}${d ? ` (en vigueur le ${d})` : ""}.` : `Rate published by ${p.source ?? "an official source"}${d ? ` (effective ${d})` : ""}.`; case "indexed": return p.note ?? (fr ? "Observation ancienne actualisée avec un indice Statistique Canada." : "Older observation updated with a Statistics Canada index."); case "derived": return fr ? "Calculé à partir de composants eux-mêmes sourcés." : "Computed from components that are themselves sourced."; case "reference": return fr ? "Prix de référence interne — hypothèse documentée, non observé." : "Internal reference price — documented assumption, not observed."; case "assumption": return p.note ?? (fr ? "Hypothèse documentée (productivité, pourcentage)." : "Documented assumption (productivity, percentage)."); default: return fr ? "Donnée non disponible." : "Data not available."; } } export function fmtDate(iso: string | null | undefined, fr: boolean): string { if (!iso) return "—"; const d = new Date(iso.length <= 10 ? `${iso}T12:00:00` : iso); if (Number.isNaN(d.getTime())) return iso; return d.toLocaleDateString(fr ? "fr-CA" : "en-CA", { year: "numeric", month: "long", day: "numeric" }); } /** Icône de provenance avec infobulle native (title). */ export function KindIcon({ kind, fr, source, observedAt, note, className = "" }: { kind: PriceKind | null | undefined; fr: boolean; source?: string | null; observedAt?: string | null; note?: string | null; className?: string }) { const tone = kind === "observed" || kind === "official" ? "text-ink" : kind === "indexed" || kind === "derived" ? "text-accent" : "text-[var(--amber)]"; return ( {kindGlyph(kind)} ); } /** Légende des icônes de provenance. */ export function KindLegend({ fr }: { fr: boolean }) { const rows: [PriceKind, string][] = [["observed", fr ? "Observé directement" : "Observed directly"], ["derived", fr ? "Calculé depuis composants" : "Computed from components"], ["indexed", fr ? "Indexé (StatCan)" : "Indexed (StatCan)"], ["reference", fr ? "Référence interne · hypothèse" : "Internal reference · assumption"]]; return (