Problem
Supabase session handling is reimplemented in seven places, each slightly differently:
src/hooks/useWebsiteSessionState.ts
src/app/auth/callback/authUtils.ts
src/app/(site)/prospect/[id]/useProspectPage.ts
src/app/(site)/prospects/useSavedProspectsPage.ts
src/app/(site)/payment-success/paymentUtils.ts
src/components/Pricing/useUserPlan.ts
src/components/Pricing/usePricingBoxState.ts
Only three of them (useWebsiteSessionState, useSavedProspectsPage, usePricingBoxState) subscribe to onAuthStateChange. The rest call getSession() once and keep the result. usePricingBoxState additionally attaches its own focus and visibilitychange listeners to re-read the session, which no other consumer does.
Why it matters
The user-visible symptom is inconsistent state: sign out in one tab and the pricing box updates while the prospect page keeps showing a stale access token until a reload, and useUserPlan keeps showing the paid plan. Any component that reads the session once is holding a token that can expire underneath it, and there is no shared refresh, so several components each independently hit Supabase for the same session.
Suggested approach
- Add a single
SessionProvider (a React context) mounted in src/app/providers.tsx, which already exists and is the natural home. It owns exactly one getSession() plus one onAuthStateChange subscription, and exposes { session, user, accessToken, loading }.
- Replace all seven call sites with
useSession().
- Move the
focus and visibilitychange revalidation out of usePricingBoxState and into the provider, so every consumer benefits instead of one.
- Delete
useWebsiteSessionState if it becomes a thin wrapper, or keep it as a re-export.
Done when
- Exactly one
onAuthStateChange subscription exists in the app.
- Signing out in one tab updates every consumer without a reload.
- No component stores its own copy of the access token in state.
If you want to take this on, comment on the issue to claim it and it will be assigned. Please keep to a maximum of 2 open claims per person at a time so other contributors get a chance.
Problem
Supabase session handling is reimplemented in seven places, each slightly differently:
src/hooks/useWebsiteSessionState.tssrc/app/auth/callback/authUtils.tssrc/app/(site)/prospect/[id]/useProspectPage.tssrc/app/(site)/prospects/useSavedProspectsPage.tssrc/app/(site)/payment-success/paymentUtils.tssrc/components/Pricing/useUserPlan.tssrc/components/Pricing/usePricingBoxState.tsOnly three of them (
useWebsiteSessionState,useSavedProspectsPage,usePricingBoxState) subscribe toonAuthStateChange. The rest callgetSession()once and keep the result.usePricingBoxStateadditionally attaches its ownfocusandvisibilitychangelisteners to re-read the session, which no other consumer does.Why it matters
The user-visible symptom is inconsistent state: sign out in one tab and the pricing box updates while the prospect page keeps showing a stale access token until a reload, and
useUserPlankeeps showing the paid plan. Any component that reads the session once is holding a token that can expire underneath it, and there is no shared refresh, so several components each independently hit Supabase for the same session.Suggested approach
SessionProvider(a React context) mounted insrc/app/providers.tsx, which already exists and is the natural home. It owns exactly onegetSession()plus oneonAuthStateChangesubscription, and exposes{ session, user, accessToken, loading }.useSession().focusandvisibilitychangerevalidation out ofusePricingBoxStateand into the provider, so every consumer benefits instead of one.useWebsiteSessionStateif it becomes a thin wrapper, or keep it as a re-export.Done when
onAuthStateChangesubscription exists in the app.If you want to take this on, comment on the issue to claim it and it will be assigned. Please keep to a maximum of 2 open claims per person at a time so other contributors get a chance.