/* fraud-ui.jsx β Reusable UI components for Acme Bank Fraud Scoring */
const ACME = {
primary: '#0D7C4A', primaryDark: '#065F3A', primaryBg: '#ECFDF5',
bg: '#F3F4F6', card: '#FFFFFF', border: '#E5E7EB',
text: '#111827', muted: '#6B7280', subtle: '#9CA3AF',
success: '#059669', warning: '#D97706', danger: '#DC2626', neutral: '#6B7280',
font: "'Plus Jakarta Sans', sans-serif",
};
const SEVERITY_STYLES = {
critical: { bg: '#FEE2E2', color: '#991B1B', dot: '#EF4444' },
high: { bg: '#FEF3C7', color: '#92400E', dot: '#F59E0B' },
medium: { bg: '#DBEAFE', color: '#1E40AF', dot: '#3B82F6' },
low: { bg: '#D1FAE5', color: '#065F46', dot: '#10B981' },
};
const RISK_STYLES = {
critical: { bg: '#FEE2E2', color: '#991B1B' },
high: { bg: '#FEF3C7', color: '#92400E' },
medium: { bg: '#DBEAFE', color: '#1E40AF' },
low: { bg: '#D1FAE5', color: '#065F46' },
};
const STATUS_STYLES = {
open: { bg: '#FEE2E2', color: '#991B1B', label: 'Open' },
investigating: { bg: '#FEF3C7', color: '#92400E', label: 'Investigating' },
resolved: { bg: '#D1FAE5', color: '#065F46', label: 'Resolved' },
cleared: { bg: '#D1FAE5', color: '#065F46', label: 'Cleared' },
flagged: { bg: '#FEE2E2', color: '#991B1B', label: 'Flagged' },
};
const REGION_CONFIG = {
NA: { label: 'North America', flag: 'πΊπΈ', color: '#3B82F6', bg: '#EFF6FF', navBg: '#EFF6FF', stripe: '#3B82F6' },
EU: { label: 'Europe', flag: 'πͺπΊ', color: '#8B5CF6', bg: '#F5F3FF', navBg: '#F5F3FF', stripe: '#8B5CF6' },
APAC: { label: 'Asia-Pacific', flag: 'π', color: '#F97316', bg: '#FFF7ED', navBg: '#FFF7ED', stripe: '#F97316' },
};
/* βββ Region Stripe β accent bar at top of page βββ */
const RegionStripe = ({ region }) => {
const cfg = REGION_CONFIG[region];
if (!cfg) return null;
return (
);
};
/* βββ Top Nav βββ */
const NAV_TABS = ['Dashboard', 'Alerts', 'Transactions', 'Rules', 'Settings'];
const FraudNav = ({ activeTab, onTabClick, version, mobile, demoRegion }) => {
const regionCfg = REGION_CONFIG[demoRegion];
const accentColor = regionCfg ? regionCfg.color : ACME.primary;
return (
onTabClick && onTabClick('Dashboard')}>
{!mobile &&
acmebank}
{(mobile ? NAV_TABS.slice(0, 3) : NAV_TABS).map((t) => {
const active = t === activeTab;
return (
onTabClick && onTabClick(t)} style={{ padding: mobile ? '0 8px' : '0 14px', height: 56, display: 'flex', alignItems: 'center', fontSize: mobile ? 13 : 14, fontWeight: active ? 600 : 500, color: active ? accentColor : ACME.muted, borderBottom: active ? '2px solid ' + accentColor : '2px solid transparent', cursor: 'pointer', fontFamily: ACME.font, flexShrink: 0, whiteSpace: 'nowrap' }}>{t}
);
})}
{regionCfg && !mobile && (
{regionCfg.label}
)}
{version && !mobile && (
v{version}
)}
{!mobile && (
<>
PS
Priya Sharma
Fraud Operations
>
)}
);
};
/* βββ KPI Card βββ */
const KpiCard = ({ label, value, sub, subColor, icon, accent, mobile }) => (
{label}
{value}
{sub && !mobile &&
{sub}
}
{icon && !mobile && (
{icon}
)}
);
/* βββ Badge βββ */
const Badge = ({ label, styles }) => (
);
/* βββ Risk Score Bar βββ */
const RiskScoreBar = ({ score }) => {
const pct = Math.round(score * 100);
const color = score >= 0.85 ? '#EF4444' : score >= 0.65 ? '#F59E0B' : score >= 0.4 ? '#3B82F6' : '#10B981';
return (
);
};
/* βββ Section Header βββ */
const SectionHeader = ({ title, subtitle, action }) => (
{title}
{subtitle &&
{subtitle}
}
{action && (
{action}
)}
);
/* βββ Time Formatter βββ */
const formatTime = (ts) => {
const d = new Date(ts);
return d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
};
const formatTimeAgo = (ts) => {
const seconds = Math.floor((Date.now() - ts) / 1000);
if (seconds < 60) return `${seconds}s ago`;
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
return `${Math.floor(seconds / 3600)}h ago`;
};
// Responsive hook β detects mobile viewports (β€768px)
function useIsMobile(breakpoint = 768) {
const [isMobile, setIsMobile] = React.useState(
() => window.innerWidth <= breakpoint
);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${breakpoint}px)`);
const handler = (e) => setIsMobile(e.matches);
mql.addEventListener('change', handler);
return () => mql.removeEventListener('change', handler);
}, [breakpoint]);
return isMobile;
}
window.ACME = ACME;
window.REGION_CONFIG = REGION_CONFIG;
window.RegionStripe = RegionStripe;
window.useIsMobile = useIsMobile;
window.SEVERITY_STYLES = SEVERITY_STYLES;
window.RISK_STYLES = RISK_STYLES;
window.STATUS_STYLES = STATUS_STYLES;
window.FraudNav = FraudNav;
window.KpiCard = KpiCard;
window.Badge = Badge;
window.RiskScoreBar = RiskScoreBar;
window.SectionHeader = SectionHeader;
window.formatTime = formatTime;
window.formatTimeAgo = formatTimeAgo;