diff --git a/src/app/brampton/vote/2026/pledge/[slug]/SharedPledgeClient.tsx b/src/app/brampton/vote/2026/pledge/[slug]/SharedPledgeClient.tsx index 7a3c1cd..844e8ec 100644 --- a/src/app/brampton/vote/2026/pledge/[slug]/SharedPledgeClient.tsx +++ b/src/app/brampton/vote/2026/pledge/[slug]/SharedPledgeClient.tsx @@ -42,29 +42,33 @@ export default function SharedPledgeClient({ name }: { name: string }) { } return ( -
+ /* On small screens the copy would sit on top of the stamp, so the three + bands flow vertically instead; from md up they overlay it again. */ +
{/* ── The stamp, full bleed ────────────────────────────── */} -
+
{/* ── Overlaid header ──────────────────────────────────── */} -
+
-

{ELECTION.eyebrow}

-

+

+ {ELECTION.eyebrow} +

+

{name} pledged to vote.

{/* ── Share + join in ────────────────────────────────── */} -
-

+

+

{ELECTION.cityLabel} votes {ELECTION.voteDayLabel}

Pledge to vote too @@ -90,15 +94,15 @@ export default function SharedPledgeClient({ name }: { name: string }) {
{/* ── Overlaid footer ──────────────────────────────────── */} -
+
Back to the election tracker -

+

Drag the stamp around · Polls open {ELECTION.pollHoursLabel}

diff --git a/src/app/toronto/vote/2026/pledge/[slug]/SharedPledgeClient.tsx b/src/app/toronto/vote/2026/pledge/[slug]/SharedPledgeClient.tsx index ed0efe0..51eac4d 100644 --- a/src/app/toronto/vote/2026/pledge/[slug]/SharedPledgeClient.tsx +++ b/src/app/toronto/vote/2026/pledge/[slug]/SharedPledgeClient.tsx @@ -40,31 +40,33 @@ export default function SharedPledgeClient({ name }: { name: string }) { return (
-
+ {/* On small screens the copy would sit on top of the stamp, so the three + bands flow vertically instead; from md up they overlay it again. */} +
{/* ── The stamp, full bleed ──────────────────────────── */} -
+
{/* ── Overlaid header ────────────────────────────────── */} -
+
-

+

Municipal Election · City of Toronto

-

+

{name} pledged to vote.

{/* ── Share + join in ──────────────────────────────── */} -
-

+

+

Toronto votes Monday, October 26

Pledge to vote too @@ -90,15 +92,15 @@ export default function SharedPledgeClient({ name }: { name: string }) {
{/* ── Overlaid footer ────────────────────────────────── */} -
+
Back to the election tracker -

+

Drag the stamp around · Polls open 10:00 a.m. – 8:00 p.m.

diff --git a/src/components/elections/PledgeButton.tsx b/src/components/elections/PledgeButton.tsx index a973247..0be9d90 100644 --- a/src/components/elections/PledgeButton.tsx +++ b/src/components/elections/PledgeButton.tsx @@ -34,6 +34,7 @@ export function PledgeButton({ }) { const config = getElection(election); const router = useRouter(); + const [open, setOpen] = useState(false); const [firstName, setFirstName] = useState(""); const [lastName, setLastName] = useState(""); const [email, setEmail] = useState(""); @@ -83,8 +84,7 @@ export function PledgeButton({ // No pledge recorded. Either the postal code couldn't be judged — say so // and let them fix it, since they may well live here — or they're outside // the jurisdiction, in which case they're subscribed but not pledged, and - // the landing page explains and invites them to explore. Keep the button - // disabled while we navigate. + // the landing page explains and invites them to explore. if (data.outsideRegion) { if (data.unverifiedPostalCode) { setError( @@ -97,6 +97,12 @@ export function PledgeButton({ source, election: config.slug, }); + // Close this modal ourselves and drop the loading state: the redirect + // is often to the page we're already on (the landing page owns the + // ResidencyModal), so this component isn't unmounted by the navigation + // and would otherwise sit disabled on "Recording…" forever. + setLoading(false); + setOpen(false); router.push(`${config.basePath}?residency=outside`); return; } @@ -116,12 +122,19 @@ export function PledgeButton({ return ( { - if (open) + open={open} + onOpenChange={(next) => { + setOpen(next); + if (next) { posthog.capture("pledge_modal_opened", { source, election: config.slug, }); + } else { + // never reopen onto a stale "Recording…" button or an old error + setLoading(false); + setError(null); + } }} > {children}