/* global React */ /* ============================= SITTING ============================= */ function SittingPage({ date, nav }) { const D = window.PT_DATA; const sitting = D.SITTINGS.find(s => s.date === date) || D.SITTINGS[D.SITTINGS.length - 1]; const speeches = D.SPEECHES.filter(s => s.sittingId === sitting.id); // group by debate const byDebate = {}; speeches.forEach(s => { (byDebate[s.debate] = byDebate[s.debate] || []).push(s); }); const debateOrder = Object.keys(byDebate); // topic counts for this sitting const topicCount = {}; speeches.forEach(s => s.topics.forEach(t => topicCount[t.slug] = (topicCount[t.slug] || 0) + 1)); const topTopics = Object.entries(topicCount).sort((a,b)=>b[1]-a[1]).slice(0, 6).map(([slug, n]) => ({ topic: D.TOPICS.find(t=>t.slug===slug), n })); const idx = D.SITTINGS.findIndex(s => s.id === sitting.id); const prev = D.SITTINGS[idx - 1]; const next = D.SITTINGS[idx + 1]; return (
{e.preventDefault();nav('sittings');}}>← all sittings
{prev && {e.preventDefault();nav('sitting',{date:prev.date});}}>← {fmtDate(prev.date)}} {prev && next && ·} {next && {e.preventDefault();nav('sitting',{date:next.date});}}>{fmtDate(next.date)} →}
Sitting record · {sitting.session}

{fmtDateLong(sitting.date)}

{speeches.length}
Speeches
{new Set(speeches.map(s => s.mp.id)).size}
Members spoke
Top topics today
{topTopics.map(x => ( {e.preventDefault();nav('topic',{slug:x.topic.slug});}} className="tag-topic"> {x.topic.short} {x.n} ))}
{/* Agenda / debates */}

Order of business

{debateOrder.length} items
{debateOrder.map((dbt, i) => (
{String(i+1).padStart(2,'0')}

{dbt}

{byDebate[dbt].length} speeches
{byDebate[dbt].slice(0, 4).map(s => )} {byDebate[dbt].length > 4 && ( + {byDebate[dbt].length - 4} more speeches )}
))}
); } /* ============================= SPEECH ============================= */ function SpeechPage({ id, nav }) { const D = window.PT_DATA; const speech = D.SPEECHES.find(s => s.id === Number(id)) || D.SPEECHES[0]; const sitting = D.SITTINGS.find(s => s.id === speech.sittingId); // fake but plausible full text const fullText = `Mr. Speaker, I rise today to speak on a matter of urgent public interest. ${speech.summary} The House will recall that the relevant Minister undertook, in response to my question on the 14th of February, to provide a written reply within fourteen days. That reply has not been forthcoming. The position of the Hon. Member opposite, with respect, fails to take into account the most recent data published by the Department of Census and Statistics. I would draw the attention of the House to page twelve of the most recent Bulletin, which sets out in clear terms the trend I have described. Mr. Speaker, I move accordingly that this House takes note of the serious concerns raised by the constituents of my district, and calls upon the Honourable Minister to lay before Parliament, within fourteen sitting days, a comprehensive statement of the government's position and the steps it proposes to take. I thank you, Mr. Speaker.`; // adjacent speeches in same sitting const sittingSpeeches = D.SPEECHES.filter(s => s.sittingId === speech.sittingId); const idxIn = sittingSpeeches.findIndex(s => s.id === speech.id); const prev = sittingSpeeches[idxIn - 1]; const next = sittingSpeeches[idxIn + 1]; return (
{e.preventDefault();nav('sitting',{date:sitting.date});}}>← {fmtDate(sitting.date)} sitting
{speech.debate} · Speech #{speech.speechOrder}

“{speech.summary}”

{e.preventDefault();nav('mp',{id:speech.mp.id});}} className="serif" style={{ fontSize: 20, fontWeight: 600 }}> {speech.mp.name} · {speech.mp.district} · {fmtDate(sitting.date)}
{speech.topics.map(t => nav('topic', { slug: tt.slug })} />)}
{/* AI summary banner */}
AI Summary

{speech.summary}

{/* Full text */}
Verbatim Hansard
{fullText.split('\n\n').map((p, i) => (

{i === 0 ? ¶ 01 : ¶ {String(i+1).padStart(2,'0')}} {p}

))}
{/* Footer: provenance + prev/next */}
); } Object.assign(window, { SittingPage, SpeechPage });