import { motion, AnimatePresence } from "framer-motion"; import { ChevronLeft, ChevronRight, Car, Clock, Sparkles, Database, } from "lucide-react"; import { useState, useEffect, useRef } from "react"; import { DTC_FIXTURES, DTC_DB_TOTAL, formatCostRange, } from "@/lib/dtc-fixtures"; /** * Tier 1 (DB) fields — code, title, cost, labor — come from dtc-fixtures * (synced from backend/src/dtc_data.py). Narrative fields (vehicle, plain * English, drivable, action) are Tier 3 (what AI would generate at runtime) * and hardcoded here until the AI Key is wired up. */ const SCENARIOS: Record< keyof typeof DTC_FIXTURES, { vehicle: string; mileage: string; plainEnglish: string; severity: string; severityColor: string; drivable: string; action: string; } > = { P0420: { vehicle: "2018 Honda Civic 1.5L Turbo", mileage: "108,432 mi", plainEnglish: "Your catalytic converter is past its prime. Not urgent — you have 1–2 weeks — but past 80k miles on this engine it's almost expected.", severity: "Plan within 2 weeks", severityColor: "#F59E0B", drivable: "Yes, safely 1–2 weeks", action: "Independent mechanic is fine — no dealer needed.", }, P0301: { vehicle: "2020 Toyota Camry 2.5L", mileage: "64,100 mi", plainEnglish: "One of your 4 cylinders is firing inconsistently. Usually a spark plug or ignition coil on cylinder 1. Cheap to rule out before assuming anything bigger.", severity: "Easy fix", severityColor: "#10B981", drivable: "Drive gently until fixed", action: "Start with a $30 plug + 30 min labor. If it comes back, swap the coil.", }, P0171: { vehicle: "2015 Ford F-150 5.0L V8", mileage: "108,204 mi", plainEnglish: "Engine is getting too much air or not enough fuel. Usually a vacuum leak, dirty MAF sensor, or weak fuel pump — in that order of likelihood.", severity: "Service soon", severityColor: "#F59E0B", drivable: "Yes, but expect worse MPG", action: "Smoke test for a vacuum leak first (~$30 at any shop).", }, P0442: { vehicle: "2019 Chevy Equinox 1.5L", mileage: "72,800 mi", plainEnglish: "A small leak somewhere in your fuel vapor recovery system. 9 times out of 10 it's the gas cap — check whether it clicks when you tighten it.", severity: "Easy fix", severityColor: "#10B981", drivable: "Yes, completely safe", action: "Swap the gas cap first ($5). If it returns, check the purge hose.", }, P0700: { vehicle: "2017 Jeep Grand Cherokee 3.6L", mileage: "94,100 mi", plainEnglish: "Your transmission computer detected an internal fault. P0700 is only the trigger — the specific P07xx code it stored alongside is what you actually need to read next.", severity: "Urgent — diagnose now", severityColor: "#EF4444", drivable: "Drive to a shop, not daily", action: "Don't DIY. Dealer or a transmission specialist. Fluid change first if never serviced.", }, }; const CASES = (Object.keys(SCENARIOS) as Array).map( (code) => { const db = DTC_FIXTURES[code]; const s = SCENARIOS[code]; return { dtc: db.code, title: db.description_en, cost: formatCostRange(db.estimated_cost_min, db.estimated_cost_max), laborHours: db.labor_hours, ...s, }; }, ); const AUTO_INTERVAL_MS = 6000; export default function DTCCarousel() { const [idx, setIdx] = useState(0); const [paused, setPaused] = useState(false); const [direction, setDirection] = useState(1); const reducedMotion = useRef(false); useEffect(() => { const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); reducedMotion.current = mq.matches; }, []); useEffect(() => { if (paused) return; const timer = setInterval(() => { setDirection(1); setIdx((prev) => (prev + 1) % CASES.length); }, AUTO_INTERVAL_MS); return () => clearInterval(timer); }, [paused]); const current = CASES[idx]; const goTo = (next: number) => { setDirection(next > idx ? 1 : -1); setIdx((next + CASES.length) % CASES.length); }; const goPrev = () => goTo(idx - 1); const goNext = () => goTo(idx + 1); return (
{/* Header */} REAL DTC LOOKUPS

Five codes.
Five plain-English answers.

Type a DTC into OBDX. Here's exactly what you'd get back.

Costs + diagnostic steps pulled from a live{" "} {DTC_DB_TOTAL}-record OBD-II database
{/* Carousel container */} setPaused(true)} onMouseLeave={() => setPaused(false)} onTouchStart={() => setPaused(true)} > {/* Slide area */}
{/* INPUT card */}
INPUT
{current.dtc}
{current.title}
{current.vehicle}
{current.mileage}
{/* OUTPUT card */}
AI DIAGNOSIS
{current.severity}

“{current.plainEnglish}”

Cost estimate
{current.cost}
Can you drive?
{current.drivable}
First move
{current.action}
{/* Progress bar (auto-advance indicator) */}
{/* Controls row */}
{CASES.map((c, i) => (
{String(idx + 1).padStart(2, "0")} / {String(CASES.length).padStart(2, "0")}
{/* Status indicator */}
{paused ? "Paused — move mouse out to resume" : `Auto-advancing every ${AUTO_INTERVAL_MS / 1000}s · hover to pause`}
); }