"use client"; import { useState, useEffect, useCallback } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Shield, AlertTriangle, CheckCircle, RefreshCw, TrendingUp, Clock, Zap, Eye, XCircle, Activity, Sparkles, ChevronDown, ChevronUp, Loader2, } from "lucide-react"; import { aiApi } from "@/lib/api"; import { useAuthStore } from "@/lib/stores/authStore"; interface FraudAlert { id: string; fraud_log_id?: string; risk_score: number; details: string; status?: string; transaction_id?: string; merchant?: string; amount?: number; timestamp?: string; } interface FraudData { total_alerts: number; pending_reviews: number; alerts: FraudAlert[]; } interface FraudExplanation { ai_explanation: string; raw_reasons: string[]; amount_vs_avg: number; user_avg_amount: number; } function Skeleton({ className }: { className?: string }) { return
; } function RiskBadge({ score }: { score: number }) { const level = score >= 70 ? { label: "High Risk", color: "text-red-400", bg: "bg-red-500/10 border-red-500/20" } : score >= 40 ? { label: "Suspicious", color: "text-amber-400", bg: "bg-amber-500/10 border-amber-500/20" } : { label: "Low Risk", color: "text-emerald-400", bg: "bg-emerald-500/10 border-emerald-500/20" }; return ( {level.label} ); } function RiskBar({ score }: { score: number }) { const color = score >= 70 ? "#ef4444" : score >= 40 ? "#f59e0b" : "#10b981"; return (
{score}
); } function AlertRow({ alert, index }: { alert: FraudAlert; index: number }) { const [expanded, setExpanded] = useState(false); const [explanation, setExplanation] = useState(null); const [loadingExpl, setLoadingExpl] = useState(false); const loadExplanation = async () => { const logId = alert.fraud_log_id || alert.id; if (!logId || explanation) { setExpanded(!expanded); return; } setExpanded(true); setLoadingExpl(true); try { const res = await aiApi.fraudExplain(logId); setExplanation(res); } catch { setExplanation({ ai_explanation: alert.details || "Suspicious activity detected based on transaction patterns.", raw_reasons: typeof alert.details === "string" ? alert.details.split("; ") : [], amount_vs_avg: 0, user_avg_amount: 0, }); } finally { setLoadingExpl(false); } }; return ( = 70 ? "bg-red-500/2" : ""}`}>
= 70 ? "bg-red-500/10 border-red-500/20" : alert.risk_score >= 40 ? "bg-amber-500/10 border-amber-500/20" : "bg-emerald-500/10 border-emerald-500/20"}`}> {alert.risk_score >= 70 ? : alert.risk_score >= 40 ? : }

{alert.merchant || `Transaction ${(alert.transaction_id || alert.id).slice(0, 8)}...`}

{alert.status && {alert.status}}

{typeof alert.details === "string" ? alert.details : Array.isArray(alert.details) ? (alert.details as string[]).join(" · ") : "Suspicious activity detected"}

{alert.amount != null &&

${Math.abs(alert.amount).toFixed(2)}

}
{expanded ? : }
{expanded && (

AI Fraud Explanation

{loadingExpl ? (
Analyzing transaction patterns...
) : explanation ? (

{explanation.ai_explanation}

{explanation.raw_reasons.length > 0 && (

Detection signals:

{explanation.raw_reasons.map((r, i) => (

{r}

))}
)} {explanation.amount_vs_avg > 0 && (

This transaction

${alert.amount?.toFixed(2)}

vs

Your average

${explanation.user_avg_amount.toFixed(2)}

{explanation.amount_vs_avg.toFixed(1)}× average
)}
) : null}
)} ); } const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.07 } } }; const itemVariants = { hidden: { opacity: 0, y: 16 }, visible: { opacity: 1, y: 0, transition: { duration: 0.4 } } }; export default function SecurityPage() { const { user } = useAuthStore(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [filter, setFilter] = useState<"all" | "high" | "pending">("all"); const load = useCallback(async () => { setLoading(true); setError(null); try { const res = await aiApi.fraudAnalysis(user?.user_id); const raw = res as unknown as Record; const alerts: FraudAlert[] = (raw.alerts as FraudAlert[]) || []; setData({ total_alerts: (raw.total_alerts as number) ?? alerts.length, pending_reviews: (raw.pending_reviews as number) ?? alerts.filter((a) => a.status === "pending").length, alerts }); } catch (err) { setError((err as Error).message); } finally { setLoading(false); } }, [user?.user_id]); useEffect(() => { load(); }, [load]); const alerts = data?.alerts || []; const filtered = alerts.filter((a) => filter === "high" ? a.risk_score >= 70 : filter === "pending" ? a.status === "pending" || !a.status : true); const highRiskCount = alerts.filter((a) => a.risk_score >= 70).length; const suspiciousCount = alerts.filter((a) => a.risk_score >= 40 && a.risk_score < 70).length; const safeCount = alerts.filter((a) => a.risk_score < 40).length; const avgScore = alerts.length ? Math.round(alerts.reduce((s, a) => s + a.risk_score, 0) / alerts.length) : 0; return (

Security Center

AI-powered fraud detection · Click any alert for a full AI explanation

{error && (

Could not load fraud data — {error}

)}

AI Fraud Shield Active

Click any flagged transaction to get a full AI explanation of exactly why it was flagged.

Live
{[ { label: "Total Alerts", value: loading ? "—" : String(data?.total_alerts ?? 0), icon: Activity, color: "text-blue-400", border: "border-blue-500/20", bg: "from-blue-500/10 to-blue-500/5" }, { label: "High Risk", value: loading ? "—" : String(highRiskCount), icon: XCircle, color: "text-red-400", border: "border-red-500/20", bg: "from-red-500/10 to-red-500/5" }, { label: "Suspicious", value: loading ? "—" : String(suspiciousCount), icon: AlertTriangle, color: "text-amber-400", border: "border-amber-500/20", bg: "from-amber-500/10 to-amber-500/5" }, { label: "Avg Risk Score", value: loading ? "—" : `${avgScore}/100`, icon: TrendingUp, color: "text-purple-400", border: "border-purple-500/20", bg: "from-purple-500/10 to-purple-500/5" }, ].map((stat) => (

{stat.label}

{stat.value}

))}

Active Detection Rules

{[ { icon: TrendingUp, label: "Amount Spike Detection", desc: "Flags transactions 3.5× above your average" }, { icon: Clock, label: "Late-Night Monitoring", desc: "Alerts on activity between 11PM – 4AM" }, { icon: Zap, label: "Rapid Transaction Guard", desc: "Detects multiple transactions within 3 minutes" }, { icon: Eye, label: "Duplicate Payment Check", desc: "Catches same merchant + amount within 10 minutes" }, ].map((rule) => (

{rule.label}

ON

{rule.desc}

))}

Fraud Alerts

{loading ? "Loading..." : `${filtered.length} alert${filtered.length !== 1 ? "s" : ""} · Click any row for AI explanation`}

{(["all", "high", "pending"] as const).map((f) => ( ))}
{loading ? (
{[1,2,3].map((i) => )}
) : filtered.length === 0 ? (

{alerts.length === 0 ? "No fraud alerts detected" : "No alerts match this filter"}

{alerts.length === 0 ? "All transactions look clean. AI Shield is monitoring in real-time." : "Try a different filter."}

) : (
{filtered.map((alert, i) => )}
)}
{!loading && safeCount > 0 && (

{safeCount} transaction{safeCount !== 1 ? "s" : ""} verified safe{" "}— risk score below threshold.

)} ); }