// Watchlist view — sanctions/PEP screening demo.
//
// Shows what a real screening result would look like: fuzzy match scores, the specific
// sanctions list + legal citation matched, and ownership-based ("50% Rule") matches where
// a business is blocked because a designated individual controls a large enough stake.
// Entities are demo fixtures (see watchlist-data.jsx) — not a live screening feed.
const { useState: useWlState, useMemo: useWlMemo, useEffect: useWlEffect } = React;
const WL_DISPOSITION_KEY = "mossad_watchlist_dispositions_v1";
const WL_STATUS_PILL = { escalated: "high", under_review: "med", cleared: "low" };
const WL_STATUS_LABEL = { escalated: "Escalated", under_review: "Under review", cleared: "Cleared" };
function wlScoreColor(v) {
return v >= 90 ? "var(--risk-high)"
: v >= 75 ? "oklch(56% 0.20 35)"
: v >= 50 ? "var(--risk-med)"
: "var(--risk-low)";
}
function loadDispositions() {
try {
const raw = localStorage.getItem(WL_DISPOSITION_KEY);
if (raw) return JSON.parse(raw);
} catch (e) {}
return {};
}
function saveDispositions(d) {
try { localStorage.setItem(WL_DISPOSITION_KEY, JSON.stringify(d)); } catch (e) {}
}
function WlMatchFactors({ factors }) {
const keys = [
{ k: "name", label: "Name" },
{ k: "identity", label: "ID / DOB" },
{ k: "nationality", label: "Nationality" },
{ k: "address", label: "Address" },
];
return (
{keys.map(({ k, label }) => {
const v = factors[k];
if (v == null) return null;
return (
);
})}
);
}
function WatchlistDetail({ entity, onBack, disposition, onSetDisposition }) {
const status = disposition || entity.status;
const isBusiness = entity.type === "business";
const relatedParties = isBusiness ? entity.controllingParties : entity.ownership;
const relatedLabel = isBusiness ? "Controlling parties" : "Entities linked by ownership";
return (
Back to watchlist
{entity.name}
{isBusiness ? "Business" : "Individual"}
{WL_STATUS_LABEL[status]}
{entity.aliases.length > 0 && (
Also known as: {entity.aliases.join(" · ")}
)}
{entity.notes}
Match score
{entity.score}
/ 100
Identity
{isBusiness ? (
<>
Jurisdiction {entity.jurisdiction}
Incorporated {entity.incorporated}
>
) : (
<>
Nationality {entity.nationality}
Date of birth {entity.dob}
>
)}
{entity.idNumbers.length > 0 && (
Identifiers
{entity.idNumbers.map((id, i) => (
{id.type}: {id.value}
))}
)}
Risk category {entity.riskCategory}
Sanctions listings
{entity.lists.map((l, i) => (
{l.authority}
{l.program}
{l.legalBasis}
Listed {l.dateListed}
))}
{relatedParties && relatedParties.length > 0 && (
{relatedLabel}
Entity
Relationship
Ownership
Notes
{relatedParties.map((p, i) => (
{p.name}
{p.relationship}
{p.pct}%
{isBusiness && p.pct >= 50 ? "Blocked under OFAC's 50% Rule" : isBusiness ? "Below 50% Rule threshold — discretionary flag" : ""}
))}
)}
Analyst disposition
onSetDisposition(entity.id, "escalated")}>Escalate to case
onSetDisposition(entity.id, "cleared")}>Clear as false positive
onSetDisposition(entity.id, "under_review")}>Mark under review
{disposition && (
onSetDisposition(entity.id, null)}>Reset to original
)}
);
}
function WatchlistView() {
const [dispositions, setDispositions] = useWlState(loadDispositions);
const [selected, setSelected] = useWlState(null);
const [typeFilter, setTypeFilter] = useWlState("all");
const [statusFilter, setStatusFilter] = useWlState("all");
const [query, setQuery] = useWlState("");
useWlEffect(() => { saveDispositions(dispositions); }, [dispositions]);
const entities = useWlMemo(() =>
WATCHLIST_ENTITIES.map(e => ({ ...e, status: dispositions[e.id] || e.status })),
[dispositions]
);
const setDisposition = (id, status) => {
setDispositions(d => {
const next = { ...d };
if (status) next[id] = status; else delete next[id];
return next;
});
};
const filtered = useWlMemo(() => {
const q = query.trim().toLowerCase();
return entities.filter(e => {
if (typeFilter !== "all" && e.type !== typeFilter) return false;
if (statusFilter !== "all" && e.status !== statusFilter) return false;
if (q && !e.name.toLowerCase().includes(q) && !e.aliases.some(a => a.toLowerCase().includes(q))) return false;
return true;
});
}, [entities, typeFilter, statusFilter, query]);
const stats = useWlMemo(() => ({
total: entities.length,
escalated: entities.filter(e => e.status === "escalated").length,
underReview: entities.filter(e => e.status === "under_review").length,
cleared: entities.filter(e => e.status === "cleared").length,
}), [entities]);
if (selected) {
const current = entities.find(e => e.id === selected.id) || selected;
return (
setSelected(null)}
disposition={dispositions[current.id]}
onSetDisposition={(id, status) => { setDisposition(id, status); }}
/>
);
}
return (
Watchlist
Illustrative sanctions-screening examples — fictional entities matched against real sanctions program citations (OFAC, UN, EU, UK OFSI),
including ownership-based ("50% Rule") matches where a business is blocked because a designated individual controls a large enough stake.
Not a live screening feed.
Monitored entities
{stats.total}
Escalated
{stats.escalated}
Under review
{stats.underReview}
setQuery(e.target.value)} />
{["all", "individual", "business"].map(t => (
setTypeFilter(t)} style={{ textTransform: "capitalize" }}>
{t === "all" ? "All types" : t === "individual" ? "Individuals" : "Businesses"}
))}
{["all", "escalated", "under_review", "cleared"].map(s => (
setStatusFilter(s)}>
{s === "all" ? "All statuses" : WL_STATUS_LABEL[s]}
))}
Entity
Type
Matched list
Score
Status
{filtered.map(e => (
setSelected(e)} style={{ cursor: "pointer" }}>
{e.name}
{e.aliases.length > 0 && (
{e.aliases.join(" · ")}
)}
{e.type === "business" ? "Business" : "Individual"}
{e.lists[0]?.authority}
{e.score}
{WL_STATUS_LABEL[e.status]}
))}
{filtered.length === 0 && (
No entities match this filter.
)}
);
}
Object.assign(window, { WatchlistView });