// H2Learn — Match Detail screen // Three layouts: Side-by-side · Narrative · Signal dashboard (function() { const D = window.H2Data; const { useState } = React; const MatchScreen = () => { const [layout, setLayout] = useState('side'); const [matchId, setMatchId] = useState('m_01'); const match = D.MATCHES.find(m => m.id === matchId) || D.MATCHES[0]; const a = D.byId(match.a), b = D.byId(match.b); const ka = D.kindOf(match.a), kb = D.kindOf(match.b); const meta = window.RelMeta[match.type] || window.RelMeta.Similarity; return (
{/* breadcrumb */}
Dashboard Network Match · {a?.name} × {b?.name}
{/* === HEADER === */}
{match.curated && Curator-reviewed} 0.9 ? 'high' : match.confidence > 0.75 ? 'med' : 'low'}> Confidence {Math.round(match.confidence*100)}%

{a?.name} × {b?.name}

{a?.role || a?.type} · {a?.org} {b?.role || b?.type} · {b?.org}

{match.summary}

Send signal
location.hash='network'} style={{justifyContent:'center'}}>Open in network
{/* layout switcher */}
Match view
Switch match:
{/* === Body — pick layout === */} {layout === 'side' && } {layout === 'narrative' && } {layout === 'signals' && } {/* === Path preview · footer === */}
Connection in network

Why these two are linked through the graph

location.hash='network'}>Open shortest path
Send introduction Save for later Compare profiles Request curator review Dismiss
); }; // ============ Side-by-side layout ============ const SideLayout = ({match, a, b, ka, kb}) => (
); const EntityPanel = ({e, kind, side, match, other}) => { const isPerson = kind === 'person'; const sharedDomains = (e.domains || []).filter(d => (other.domains || []).includes(d)); const sharedMethods = (e.methods || []).filter(m => (other.methods || []).includes(m)); return (
Entity {side}
{e.name}
{e.role || e.type} · {e.org}
{e.fingerprint && (
Top expertise
)} {e.domains && (
Domains
{e.domains.slice(0,6).map(d => ( {sharedDomains.includes(d) && } {d} ))}
)} {e.methods && (
Methods
{e.methods.map(m => ( {sharedMethods.includes(m) && } {m} ))}
)} {e.needs && e.needs.length > 0 && (
Needs
{e.needs.map((n,i) => { const compl = (other.offers || []).some(o => o.toLowerCase().includes(n.toLowerCase().split(' ')[0]) || n.toLowerCase().includes(o.toLowerCase().split(' ')[0])); return (
{n} {compl && Match}
); })}
)} {e.offers && e.offers.length > 0 && (
Offers
{e.offers.map((o,i) => { const compl = (other.needs || []).some(n => n.toLowerCase().includes(o.toLowerCase().split(' ')[0]) || o.toLowerCase().includes(n.toLowerCase().split(' ')[0])); return (
{o} {compl && Match}
); })}
)} {e.bottlenecks && (
Bottlenecks
{e.bottlenecks.map((b,i) => (
{b.label} · severity {b.severity}/5
))}
)} {e.evidence && (
{e.evidence} evidence anchors attached
)}
); }; const WhyPanel = ({match}) => (
Why this match

Six contributing signals

{match.signals.map((s, i) => ( ))}
Plain-English summary

{match.summary}

location.hash='algorithms'} size="sm" style={{justifyContent:'center'}}>How matching works
); const SignalRow = ({s, expanded:initial=false}) => { const [open, setOpen] = useState(initial); return (
setOpen(!open)}>
{s.name}
w {Math.round(s.weight*100)}% {s.score}%
{open && (
{s.expl}
source · {s.source}
)}
); }; // ============ Narrative layout ============ const NarrativeLayout = ({match, a, b}) => (
Score breakdown
Weighted contribution per signal
{match.signals.map((s,i) => (
{s.name} {s.score}%
))}
Confidence
How sure the system is about this match
· 6 distinct signals contributing
· 3 of 5 backed by evidence anchors
· {match.curated ? 'Curator-reviewed' : 'System-generated'}
Match metadata
); const NarrativeStep = ({n, title, body, chip, chipVariant}) => (
{n}

{title}

{chip}

{body}

); const Meta = ({k, v}) => (
{k} {v}
); // ============ Signal dashboard layout ============ const SignalsLayout = ({match, a, b, ka, kb}) => (
Source
{a.name}
{a.role || a.type}
{a.fingerprint &&
} {a.methods && (
Methods
{a.methods.map(m => {m})}
)}

Signal contribution

total weight {match.signals.reduce((s,x) => s+x.weight, 0).toFixed(2)}
{match.signals.map((s, i) => (
{s.name}
{s.score}%
w {s.weight.toFixed(2)}
))}
Composite score
{match.score}%
Confidence
{Math.round(match.confidence*100)}%
Algorithm family
{match.type}
Audit trail
Every signal traces back to questionnaire data
{match.signals.map((s,i) => ( ))}
Signal Source data Score Weight
{s.name} {s.source} {s.score}% {s.weight.toFixed(2)}
Target
{b.name}
{b.role || b.type}
{b.needs && (
Needs
{b.needs.map(n => {n})}
)} {b.bottlenecks && (
Bottlenecks
{b.bottlenecks.map((bn,i) =>
{bn.label} · sev {bn.severity}/5
)}
)}
); const PathStrip = ({a, ka, b, kb}) => (
{[ {l: a.name, i: a.initials, k: ka}, {l: 'PEM', i: 'P', k: 'domain'}, {l: 'LCA method', i: 'L', k: 'method'}, {l: 'TRL 5 · pilot', i: 'P5', k: 'project'}, {l: b.name, i: b.initials, k: kb}, ].map((step, i, arr) => (
{step.l}
{i < arr.length - 1 && }
))}
); Object.assign(window, { MatchScreen }); })();