/* global React, PrimaryButton */
// Yomee — Analyzing Screen
// Transitional screen that sits between Upload and the Dashboard / Confidence
// Gate. Simulates the back-end work in two phases so the user understands
// what's happening AND that we don't keep their files:
// 1) "Analizando tus estados de cuenta…"
// 2) "Eliminando tus archivos de forma segura…"
// After both phases complete, calls onDone() so the Router can advance to
// the next screen (review or radiografía).
//
// Total duration ≈ 5s of work (varied per step so the rhythm feels human
// rather than metronomic) + ~1.6s confetti hold before the Router advances.
// Pocopin mascot (pocopin-4.png) is the focal element with a soft floating
// loop while work is in progress, and a small bounce on completion.
const { useState: useAnalyzingState, useEffect: useAnalyzingEffect } = React;
// ────────────────────────────────────────────────
// Step definitions — order matters; each duration is the visible "in
// progress" time before the row flips to its done state.
// ────────────────────────────────────────────────
const ANALYZING_STEPS = [
{
key: "analyze",
inProgress: "Analizando tus estados de cuenta",
done: "Análisis completo",
duration: 1900,
},
{
key: "delete",
inProgress: "Eliminando tus archivos de forma segura",
done: "Archivos eliminados",
duration: 1300,
},
{
key: "build",
inProgress: "Creando tu radiografía",
done: "Radiografía lista",
duration: 1800,
},
];
// Confetti hold time — how long the celebration plays before the Router
// advances. Long enough for users to register the moment, short enough to
// stay snappy.
const CONFETTI_HOLD_MS = 1600;
// Tiny in-row spinner — same visual language as the upload area's spinner
// so this screen feels like a continuation of that interaction.
function StepSpinner({ size = 20 }) {
return (
);
}
// Filled mint check — matches the success indicator on file rows.
function StepCheck({ size = 22 }) {
return (
);
}
// Empty placeholder dot for steps that haven't started yet.
function StepPending({ size = 20 }) {
return (
);
}
// ────────────────────────────────────────────────
// Confetti — lightweight CSS-only burst. Generates ~36 colored chips that
// fall from the top with random horizontal drift, rotation and delay.
// Colors are pulled from the brand palette so the burst feels on-system.
// ────────────────────────────────────────────────
const CONFETTI_COLORS = [
"var(--yo-mint-700)",
"var(--yo-forest-500)",
"var(--yo-orange-soft)",
"var(--yo-coral)",
"var(--yo-yellow)",
"var(--yo-lavender)",
];
function Confetti({ count = 36 }) {
const pieces = React.useMemo(() => {
return Array.from({ length: count }, (_, i) => {
const left = Math.random() * 100;
const delay = Math.random() * 350;
const duration = 1200 + Math.random() * 900;
const drift = (Math.random() - 0.5) * 120;
const rot = Math.random() * 720 - 360;
const size = 6 + Math.random() * 6;
const color =
CONFETTI_COLORS[Math.floor(Math.random() * CONFETTI_COLORS.length)];
const isCircle = Math.random() < 0.3;
return { left, delay, duration, drift, rot, size, color, isCircle, i };
});
}, [count]);
return (
{pieces.map((p) => (
))}
);
}
function StepRow({ status, label }) {
const isDone = status === "done";
const isActive = status === "active";
return (
{isDone ? (
) : isActive ? (
) : (
)}
{label}
);
}
// ────────────────────────────────────────────────
// Main screen
// ────────────────────────────────────────────────
function AnalyzingScreen({ fileCount = 0, onDone }) {
// 0..ANALYZING_STEPS.length — number of steps that have completed.
const [completed, setCompleted] = useAnalyzingState(0);
const [allDone, setAllDone] = useAnalyzingState(false);
// Drives the confetti overlay. Flips on as soon as the last step finishes
// and stays on until the Router advances away from this screen.
const [showConfetti, setShowConfetti] = useAnalyzingState(false);
useAnalyzingEffect(() => {
let cancelled = false;
const timeouts = [];
let elapsed = 0;
ANALYZING_STEPS.forEach((step, i) => {
elapsed += step.duration;
const t = setTimeout(() => {
if (cancelled) return;
setCompleted(i + 1);
if (i === ANALYZING_STEPS.length - 1) {
setAllDone(true);
setShowConfetti(true);
// Navigation no longer happens automatically — the user must press
// the CONTINUAR button below, which becomes enabled once allDone
// flips. This acts as a stopper before the dashboard so users can
// register the completion moment on their own time.
}
}, elapsed);
timeouts.push(t);
});
return () => {
cancelled = true;
timeouts.forEach((t) => clearTimeout(t));
};
}, []);
const currentStep = completed; // index of the step that's currently active
const headline = allDone
? "¡Listo!"
: currentStep === 0
? "Estamos analizando tus archivos"
: currentStep === 1
? "Protegiendo tu información"
: "Construyendo tu radiografía";
const subhead = allDone
? "Tu radiografía está lista"
: currentStep === 0
? "Pocopin está leyendo cada movimiento de tus estados de cuenta"
: currentStep === 1
? "Borramos tus archivos en cuanto terminamos. No los guardamos."
: "Estamos uniendo todo para mostrarte tu situación real";
return (
{/* Content — vertically centered, with a slight top bias so the mascot
sits higher than dead-center which feels more "active". */}
{/* Mascot — soft floating loop while work is in progress, gentle
pop-in on mount and a celebratory bounce on completion. */}
{/* Soft halo ring behind the mascot — pulses while loading. */}
{/* Headline */}
{headline}
{subhead}
{/* File count chip — only when meaningful (≥ 1). */}
{fileCount > 0 && !allDone && (
{fileCount === 1
? "1 estado de cuenta"
: `${fileCount} estados de cuenta`}
)}
{/* Step list */}
{ANALYZING_STEPS.map((step, i) => {
let status = "pending";
if (i < completed) status = "done";
else if (i === completed) status = "active";
const label =
status === "done" ? step.done : step.inProgress + (status === "active" ? "…" : "");
return ;
})}
{/* Privacy note — reinforces the "we don't keep your files" promise. */}
Tus archivos se eliminan de forma permanente una vez procesados
{/* CONTINUAR stopper — disabled while the simulation is running, enabled
once all steps complete. Matches the Start Screen primary CTA style
(PrimaryButton, primary variant). */}
onDone && onDone()}
disabled={!allDone}
>
CONTINUAR
{/* Celebratory confetti — plays once all 3 steps finish, before the
Router advances. Fixed-overlay so it spans the full screen. */}
{showConfetti &&
}
);
}
Object.assign(window, { AnalyzingScreen, ANALYZING_STEPS });