// App shell — sidebar, topbar, view routing, tweaks panel, auth gate.
const { useState: useAppState, useEffect: useAppEffect, useMemo: useAppMemo, useRef: useAppRef, Component } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"theme": "light",
"density": "regular",
"accent": "#2563eb",
"rowEmphasis": "hairline"
}/*EDITMODE-END*/;
const ACCENT_PRESETS = {
"#2563eb": { l: 48, c: 0.16, h: 252, name: "Indigo (default)" },
"#0f766e": { l: 48, c: 0.12, h: 190, name: "Teal" },
"#7c3aed": { l: 48, c: 0.18, h: 290, name: "Violet" },
"#111827": { l: 22, c: 0.008, h: 260, name: "Monochrome" },
};
function applyAccent(hex, theme) {
const p = ACCENT_PRESETS[hex] || ACCENT_PRESETS["#2563eb"];
const root = document.documentElement;
const dark = theme === "dark";
const l = dark ? (p.h === 260 && p.c < 0.02 ? 96 : Math.min(p.l + 22, 78)) : p.l;
const l2 = dark ? Math.min(l + 6, 88) : p.l + 6;
const tintL = dark ? 26 : 95;
const tintC = dark ? p.c * 0.4 : p.c * 0.25;
root.style.setProperty("--accent", `oklch(${l}% ${p.c} ${p.h})`);
root.style.setProperty("--accent-2", `oklch(${l2}% ${p.c} ${p.h})`);
root.style.setProperty("--accent-tint", `oklch(${tintL}% ${tintC} ${p.h})`);
}
// Marks a nav label / page title as backed by fixture data rather than the live API,
// so it reads visually distinct from the (differently-colored) real data around it.
function DemoTag() {
return (
Demo
);
}
function SoonTag() {
return (
Soon
);
}
function LoginScreen({ onLogin, error, onReset }) {
const [email, setEmail] = useAppState("admin@mossad.io");
const [password, setPassword] = useAppState("admin");
const [busy, setBusy] = useAppState(false);
const [err, setErr] = useAppState(error);
const submit = async (e) => {
e.preventDefault();
setBusy(true);
setErr(null);
try {
await onLogin(email, password);
} catch (e) {
let msg = e.message;
if (e.message === "UNAUTHORIZED") msg = "Invalid email or password";
setErr(msg);
} finally {
setBusy(false);
}
};
const resetSession = () => {
if (onReset) onReset();
setErr(null);
};
return (
Sign in
Transaction monitoring workspace
{err && (
{err}
)}
Reset session
Default: admin@mossad.io / admin
);
}
function Sidebar({ view, setView, sidebarOpen, setSidebarOpen, data }) {
const NavItem = ({ id, icon, label, count, dot, active, demo, soon }) => (
setView(id)}
disabled={soon}>
{icon}
{label}{demo && }{soon && }
{count != null && {count} }
{dot && }
);
return (
);
}
function AiAssistChat({ onClose }) {
const [messages, setMessages] = useAppState(() => [
{ role: "bot", text: "Hi! I can answer questions about Mossad from the docs. Ask me anything." },
]);
const [input, setInput] = useAppState("");
const send = (e) => {
e.preventDefault();
const text = input.trim();
if (!text) return;
setMessages(m => [
...m,
{ role: "user", text },
{ role: "bot", text: "I hear you want to use the AI capabilities big dawg. It's better than Sloppy Jo's AI Slop and will take some time to develop." },
]);
setInput("");
};
return (
AI Assist
{messages.map((m, i) => (
{m.text}
))}
);
}
function computeSearchResults(data, query) {
const q = query.trim().toLowerCase();
if (!q) return null;
const alerts = (data?.alerts || []).filter(a =>
(a.external_id || "").toLowerCase().includes(q) ||
(a.subject || "").toLowerCase().includes(q) ||
(a.typology || "").toLowerCase().includes(q) ||
(a.customerId || "").toLowerCase().includes(q)
).slice(0, 5);
const cases = (data?.cases || []).filter(c =>
(c.id || "").toLowerCase().includes(q) ||
(c.title || "").toLowerCase().includes(q) ||
(c.entity || "").toLowerCase().includes(q) ||
(c.customerId || "").toLowerCase().includes(q)
).slice(0, 5);
const customers = (data?.customers || []).filter(c =>
(c.customer_id || "").toLowerCase().includes(q)
).slice(0, 5);
const transactions = (data?.transactions || []).filter(t =>
(t.external_id || "").toLowerCase().includes(q) ||
(t.originator_id || "").toLowerCase().includes(q) ||
(t.beneficiary_id || "").toLowerCase().includes(q)
).slice(0, 5);
const sars = (data?.sars || []).filter(s =>
(s.external_id || "").toLowerCase().includes(q) ||
(s.suspicious_activity_description || "").toLowerCase().includes(q)
).slice(0, 5);
const total = alerts.length + cases.length + customers.length + transactions.length + sars.length;
return { alerts, cases, customers, transactions, sars, total };
}
function GlobalSearch({ data, onOpenAlert, onOpenCase, onNavigate }) {
const [query, setQuery] = useAppState("");
const [open, setOpen] = useAppState(false);
const inputRef = useAppRef(null);
useAppEffect(() => {
const onKey = (e) => {
const meta = e.metaKey || e.ctrlKey;
if (meta && e.key.toLowerCase() === "k") {
e.preventDefault();
inputRef.current?.focus();
setOpen(true);
} else if (e.key === "Escape" && document.activeElement === inputRef.current) {
setOpen(false);
inputRef.current?.blur();
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);
const results = useAppMemo(() => computeSearchResults(data, query), [data, query]);
const select = (fn) => {
fn();
setOpen(false);
setQuery("");
};
return (
{ setQuery(e.target.value); setOpen(true); }}
onFocus={() => { if (query) setOpen(true); }}
/>
{query ? (
e.preventDefault()}
onClick={() => { setQuery(""); inputRef.current?.focus(); }} title="Clear">
) : (
⌘K
)}
{open && results && (
e.preventDefault()}>
{results.total === 0 &&
No matches for "{query}"
}
{results.alerts.length > 0 && (
<>
Alerts
{results.alerts.map(a => (
select(() => onOpenAlert(a))}>
{a.external_id}
{a.subject} · {a.typology}
))}
>
)}
{results.cases.length > 0 && (
<>
Cases
{results.cases.map(c => (
select(() => onOpenCase(c))}>
{c.id}
{c.title}
))}
>
)}
{results.customers.length > 0 && (
<>
Customers
{results.customers.map(c => (
select(() => onNavigate("customers", { query: c.customer_id }))}>
{c.customer_id}
{c.transaction_count} txns
))}
>
)}
{results.transactions.length > 0 && (
<>
Transactions
{results.transactions.map(t => (
select(() => onNavigate("txns", { query: t.external_id }))}>
{t.external_id}
${Number(t.amount).toLocaleString()} {t.currency}
))}
>
)}
{results.sars.length > 0 && (
<>
SARs
{results.sars.map(s => (
select(() => onNavigate("sars", { id: s.id }))}>
{s.external_id}
{(s.suspicious_activity_description || "").slice(0, 40)}
))}
>
)}
)}
);
}
function TopBar({ view, currentAlert, onCloseCase, theme, onToggleTheme, onLogout, data, onOpenAlert, onOpenCase, onNavigate }) {
const [aiOpen, setAiOpen] = useAppState(false);
const titles = {
alerts: { title: "Alerts", crumb: ["Workspace", "Alerts"] },
"my-cases":{ title: "My cases", crumb: ["Workspace", "My cases"] },
sars: { title: "SAR drafts", crumb: ["Workspace", "SAR drafts"] },
watchlist: { title: "Watchlist", crumb: ["Workspace", "Watchlist"], demo: true },
customers: { title: "Customers", crumb: ["Investigate", "Customers"] },
agents: { title: "Agents", crumb: ["Investigate", "Agents"], demo: true },
ratings: { title: "Risk ratings", crumb: ["Investigate", "Risk ratings"], demo: true },
periodic: { title: "Periodic review", crumb: ["Investigate", "Periodic review"], demo: true },
txns: { title: "Transactions", crumb: ["Investigate", "Transactions"] },
rules: { title: "Rule Settings", crumb: ["Investigate", "Rule Settings"] },
analytics: { title: "Analytics", crumb: ["Insights", "Analytics"] },
tenants: { title: "Tenants", crumb: ["Insights", "Tenants"] },
reports: { title: "Reports", crumb: ["Insights", "Reports"] },
settings: { title: "Settings", crumb: ["Settings"] },
}[view] || { title: view, crumb: [view] };
return (
{titles.crumb.map((c, i) => (
{i > 0 && }
{i === titles.crumb.length - 1 && !currentAlert
? {c}{titles.demo && }
:
{c}
}
))}
{currentAlert && (
<>
{currentAlert.external_id}
>
)}
{theme === "dark" ? : }
setAiOpen(o => !o)}>
AI Assist
{aiOpen &&
setAiOpen(false)} />}
Sign out
);
}
function PlaceholderView({ icon, title, msg }) {
return (
);
}
function AppShell() {
const data = useData();
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
const [view, setView] = useAppState("alerts");
const [currentAlert, setCurrentAlert] = useAppState(null);
const [currentCase, setCurrentCase] = useAppState(null);
const [sidebarOpen, setSidebarOpen] = useAppState(true);
const [searchNav, setSearchNav] = useAppState(null);
const handleSearchNavigate = (targetView, payload) => {
setView(targetView);
setSearchNav({ view: targetView, token: Date.now(), ...payload });
};
if (typeof document !== "undefined") {
document.documentElement.dataset.theme = t.theme;
document.documentElement.dataset.density = t.density;
}
useAppEffect(() => {
applyAccent(t.accent, t.theme);
}, [t.theme, t.accent]);
useAppEffect(() => { setCurrentAlert(null); setCurrentCase(null); }, [view]);
const renderView = () => {
if (currentAlert) {
return (
setCurrentAlert(null)}
backLabel={currentCase ? "Back to case" : "Back to queue"}
data={data}
/>
);
}
if (currentCase) {
return (
setCurrentCase(null)}
onOpenAlert={(a) => setCurrentAlert(a)}
data={data}
/>
);
}
switch (view) {
case "alerts":
return (
setCurrentAlert(a)}
rowStyle={t.rowEmphasis}
/>
);
case "analytics":
return ;
case "tenants":
return ;
case "ratings":
return {}} />;
case "periodic":
return ;
case "my-cases":
return setCurrentCase(c)} />;
case "sars":
return ;
case "watchlist":
return ;
case "customers":
return ;
case "agents":
return ;
case "txns":
return ;
case "rules":
return ;
case "reports":
return } title="Scheduled reports"
msg="Regulatory reports, MIS summaries, and team performance — generated daily, weekly, or on demand." />;
case "settings":
return } title="Settings"
msg="Org thresholds, escalation paths, integrations, and audit log retention." />;
default:
return null;
}
};
return (
{ setCurrentAlert(null); setView(id); }}
sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} data={data} />
setCurrentAlert(null)}
theme={t.theme}
onToggleTheme={() => setTweak("theme", t.theme === "dark" ? "light" : "dark")}
onLogout={data.logout}
data={data}
onOpenAlert={(a) => setCurrentAlert(a)}
onOpenCase={(c) => setCurrentCase(c)}
onNavigate={handleSearchNavigate} />
{data.loading && (
Syncing with backend…
)}
{data.error && (
{data.error}
Sign out
)}
{renderView()}
setTweak("theme", v)} />
setTweak("density", v)} />
setTweak("accent", v)} />
setTweak("rowEmphasis", v)} />
);
}
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: null };
}
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) {
return (
Something went wrong
{this.state.error.stack || this.state.error.message || String(this.state.error)}
{ window.mossadApi && window.mossadApi.logout(); location.reload(); }}>
Reset and reload
);
}
return this.props.children;
}
}
function App() {
const data = useData();
if (!data.isAuthenticated) {
return ;
}
return ;
}
function Root() {
return (
);
}
// Row treatment via injected stylesheet (driven by data-row attr on body)
function applyRowEmphasis(mode) {
document.body.dataset.row = mode;
}
const rowStyle = document.createElement("style");
rowStyle.textContent = `
body[data-row="zebra"] .tbl tbody tr:nth-child(even) { background: var(--bg-2); }
body[data-row="zebra"] .tbl tbody tr:hover { background: var(--bg-3); }
body[data-row="card"] .tbl { border-spacing: 0 4px; border-collapse: separate; }
body[data-row="card"] .tbl tbody tr { background: var(--bg-2); }
body[data-row="card"] .tbl tbody td { border-bottom: 0; }
body[data-row="card"] .tbl tbody td:first-child { border-top-left-radius: 6px; border-bottom-left-radius: 6px; }
body[data-row="card"] .tbl tbody td:last-child { border-top-right-radius: 6px; border-bottom-right-radius: 6px; }
body[data-row="card"] .tbl thead th { background: transparent; }
`;
document.head.appendChild(rowStyle);
ReactDOM.createRoot(document.getElementById("root")).render( );
window.addEventListener("tweakchange", (e) => {
if (e.detail && e.detail.rowEmphasis) applyRowEmphasis(e.detail.rowEmphasis);
});
applyRowEmphasis(TWEAK_DEFAULTS.rowEmphasis);