/* global React, PrimaryButton, ArchetypeScreen, DiagnosticScreen */ // Yomee — Profile Result Screen (DS-aligned) // Renders one of four profile screens (totalero, optimizador, escalador, // reiniciador) based on the user's debt + monthly payment. // // Surface = cream var(--yo-bg). Ink = var(--yo-ink) (#333). White is reserved // for the inner metric card (2px ink stroke, 28px radius, no shadow). // Typography: Geist Mono for display + numerals + buttons; Onest for body. // All visual properties go through DS tokens — no inline hex anywhere. const { useEffect: useEffectP } = React; // ──────────────────────────────────────────────── // Profile classification — pure function so it can be unit-tested. // payment_ratio = pago_mensual / deuda_total // >= 1.0 → totalero // >= 0.15 → optimizador (was: parcialero) // >= 0.01 → escalador (was: minimero) // == 0 → reiniciador // ──────────────────────────────────────────────── function classifyProfile(deudaTotal, pagoMensual) { if (!pagoMensual || pagoMensual <= 0) return "reiniciador"; if (!deudaTotal || deudaTotal <= 0) return "reiniciador"; const ratio = pagoMensual / deudaTotal; if (ratio >= 1.0) return "totalero"; if (ratio >= 0.15) return "optimizador"; if (ratio >= 0.01) return "escalador"; return "reiniciador"; } // ──────────────────────────────────────────────── // Payoff calculation (per spec) // tasa_mensual = 0.025 // meses = -ln(1 - tasa_mensual * deuda / pago) / ln(1 + tasa_mensual) // interes_total = (pago * meses) - deuda // unpayable when pago <= deuda * tasa_mensual // ──────────────────────────────────────────────── function calcPayoff(deudaTotal, pagoMensual) { const r = 0.025; const D = deudaTotal; const P = pagoMensual; if (P <= D * r) return { unpayable: true }; const months = Math.ceil(-Math.log(1 - (r * D) / P) / Math.log(1 + r)); const totalInterest = Math.max(0, Math.round(P * months - D)); return { unpayable: false, months, totalInterest }; } // Format months → "N meses" if N < 12, else "X años y Y meses". function formatMonths(months) { if (months <= 0) return "0 meses"; if (months < 12) return `${months} ${months === 1 ? "mes" : "meses"}`; const years = Math.floor(months / 12); const rem = months % 12; if (rem === 0) return `${years} ${years === 1 ? "año" : "años"}`; return `${years} ${years === 1 ? "año" : "años"} y ${rem} ${ rem === 1 ? "mes" : "meses" }`; } const fmtCurrency = (n) => "$" + Math.round(n).toLocaleString("es-MX"); // ──────────────────────────────────────────────── // Per-profile config — copy + accent tokens per spec. // archetypeColor MUST reference a DS token, never a literal hex. // ──────────────────────────────────────────────── const PROFILES = { totalero: { kind: "archetype", variant: "mascot-on-card", mascot: "assets/profiles/totalero.png", subtitle: "¡Excelente!", archetype: "Eres un Totalero", archetypeColor: "var(--profile-totalero)", headline: ( <> Pagas todo cada mes. Cero interés, cero estrés. ¿Sabes cuánto pagas en anualidades y cargos ocultos? ), cardBody: "Con tu radiografía podrías encontrar tarjetas con anualidades más bajas o mejores beneficios gratis.", cta: "CREAR MI RADIOGRAFÍA GRATIS →", }, optimizador: { kind: "diagnostic", mascot: "assets/profiles/optimizador.png", subtitle: "¡Vas bien!", archetype: "Eres un Optimizador", archetypeColor: "var(--profile-optimizador)", headline: ( <> Pagas más del mínimo, y eso cuenta. Pero los intereses siguen trabajando en tu contra cada mes. ), cta: "Armar mi plan →", }, escalador: { kind: "diagnostic", mascot: "assets/profiles/escalador.png", subtitle: "¡Atención!", archetype: "Eres un escalador", archetypeColor: "var(--profile-escalador)", headline: ( <> Pagar el mínimo puede costar años y miles en intereses. La buena noticia: con pequeños ajustes puedes salir mucho antes de lo que crees. ), cta: "Ver cuánto me está costando →", }, reiniciador: { kind: "archetype", variant: "mascot-on-card", mascot: "assets/profiles/reiniciador.png", subtitle: "¡Nuevo comienzo!", archetype: "Eres un reiniciador", archetypeColor: "var(--profile-reiniciador)", headline: ( <> Todos merecemos una segunda vuelta. Siempre se puede recuperar un buen historial crediticio. ), cardBody: "Te ayudamos a dar el primer paso para retomar el control de tus finanzas, sin juicios y a tu ritmo.", cta: "Empezar de nuevo →", }, }; // Gendered archetype labels — applied when gender === "female". const PROFILE_LABEL_F = { totalero: "Eres una Totalera", optimizador: "Eres una Optimizadora", escalador: "Eres una escaladora", reiniciador: "Eres una reiniciadora", }; function archetypeLabel(profileKey, gender, fallback) { if (gender === "female" && PROFILE_LABEL_F[profileKey]) { return PROFILE_LABEL_F[profileKey]; } return fallback; } // ──────────────────────────────────────────────── // Main screen — picks the right primitive (Archetype vs Diagnostic) and // passes the per-profile config + computed metric. // ──────────────────────────────────────────────── function ProfileResultScreen({ deudaTotal = 0, pagoMensual = 0, gender = null, forceProfile = null, onContinue, onBack, onClose, }) { const classified = classifyProfile(deudaTotal, pagoMensual); const profile = (forceProfile && PROFILES[forceProfile]) ? forceProfile : classified; const cfg = PROFILES[profile]; // When forcing a profile, synthesize plausible debt/payment so the // diagnostic metric still renders something sensible. const FORCED_NUMBERS = { optimizador: { d: 65000, p: 12000 }, escalador: { d: 80000, p: 2200 }, }; const useNumbers = forceProfile && FORCED_NUMBERS[forceProfile] ? FORCED_NUMBERS[forceProfile] : { d: deudaTotal, p: pagoMensual }; const payoff = calcPayoff(useNumbers.d, useNumbers.p); // Persist for the rest of the session. useEffectP(() => { try { localStorage.setItem("yomee_profile", profile); } catch (_) {} }, [profile]); const archetypeStr = archetypeLabel(profile, gender, cfg.archetype); const onCta = () => onContinue && onContinue(profile); if (cfg.kind === "archetype") { return ( ); } // Diagnostic (optimizador / escalador) const metric = !payoff.unpayable ? formatMonths(payoff.months) : ""; const interesTotal = !payoff.unpayable ? fmtCurrency(payoff.totalInterest) : ""; return ( ); } Object.assign(window, { ProfileResultScreen, classifyProfile, calcPayoff, formatMonths, });