import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { ArrowLeft, ArrowRight, AlertTriangle, FolderHeart } from "lucide-react"; import MappingRow from "./MappingRow"; import TransactionPreviewPanel from "./TransactionPreviewPanel"; import type { MigrationPlan, MappingRow as MappingRowType, } from "../../services/categoryMappingService"; interface StepSimulateProps { plan: MigrationPlan; unresolved: number; selectedRowV2Id: number | null; transactionCountByV2Id: Map; onResolveRow: (v2CategoryId: number, v1TargetId: number, v1TargetName: string) => void; onSelectRow: (v2CategoryId: number | null) => void; onNext: () => void; onBack: () => void; } /** * Step 2 — Simulate (dry-run): a 3-column table (v2 | confidence | v1 target), * a preview side panel per selected row, and a blocking guard on the "next" * button until every row is resolved. No DB writes happen here — the plan is * mutated in memory via the reducer. */ export default function StepSimulate({ plan, unresolved, selectedRowV2Id, transactionCountByV2Id, onResolveRow, onSelectRow, onNext, onBack, }: StepSimulateProps) { const { t } = useTranslation(); const selectedRow = useMemo(() => { if (selectedRowV2Id === null) return null; return ( plan.rows.find((r) => r.v2CategoryId === selectedRowV2Id) ?? plan.preserved.find((r) => r.v2CategoryId === selectedRowV2Id) ?? null ); }, [plan.rows, plan.preserved, selectedRowV2Id]); const canContinue = unresolved === 0; return (

{t("categoriesSeed.migration.simulate.title")}

{t("categoriesSeed.migration.simulate.subtitle")}

{/* Stats summary */}
{t("categoriesSeed.migration.simulate.stats.total")}
{plan.stats.total}
{t("categoriesSeed.migration.simulate.confidence.high")}
{plan.stats.high}
{t("categoriesSeed.migration.simulate.confidence.medium")}
{plan.stats.medium}
{t("categoriesSeed.migration.simulate.confidence.low")}
{plan.stats.low}
{t("categoriesSeed.migration.simulate.confidence.none")}
{plan.stats.none}
{/* Unresolved warning banner */} {unresolved > 0 && (

{t("categoriesSeed.migration.simulate.unresolvedWarning", { count: unresolved, })}

)} {/* Header row */}
    {plan.rows.map((row) => (
  • ))}
{/* Preserved categories block */} {plan.preserved.length > 0 && (

{t("categoriesSeed.migration.simulate.preserved.title", { count: plan.preserved.length, })}

{t("categoriesSeed.migration.simulate.preserved.body")}

    {plan.preserved.map((row) => (
  • {row.v2CategoryName} {t("categoriesSeed.migration.simulate.preserved.txCount", { count: transactionCountByV2Id.get(row.v2CategoryId) ?? 0, })}
  • ))}
)} {/* Nav */}
{/* Side panel with tx preview */} {selectedRow !== null && ( onSelectRow(null)} /> )}
); }