siftlode/frontend/src/lib/onboarding.ts

36 lines
1.9 KiB
TypeScript
Raw Normal View History

// Onboarding wizard visibility, kept stable across the OAuth redirect round-trip.
//
// Granting a YouTube scope navigates away to Google's consent screen and back, which
// fully reloads the SPA — so we can't hold the wizard's progress in React state. Instead
// we derive the current step from the granted scopes (me.can_read / me.can_write) and use
// two storage flags to decide whether to auto-open:
//
// ONBOARD_ACTIVE (sessionStorage) — set while the user is mid-flow (e.g. just clicked
// "Connect"); makes the wizard reopen after the
// redirect so they land on the next step.
// ONBOARD_DISMISSED (localStorage) — set when the user skips the essential read step;
// suppresses the auto-popup on future logins (they
// can still reopen it from Settings → Account).
export const ONBOARD_ACTIVE = "subfeed.onboarding.active";
export const ONBOARD_DISMISSED = "subfeed.onboarding.dismissed";
export function shouldAutoOpenOnboarding(me: { can_read: boolean; is_demo?: boolean }): boolean {
// The shared demo account can never connect YouTube, so never nudge it to.
if (me.is_demo) return false;
if (sessionStorage.getItem(ONBOARD_ACTIVE)) return true;
return !me.can_read && !localStorage.getItem(ONBOARD_DISMISSED);
}
/** Mark a grant as in progress, then send the user to Google's consent screen. */
export function beginGrant(access: "read" | "write"): void {
sessionStorage.setItem(ONBOARD_ACTIVE, "1");
window.location.href = `/auth/upgrade?access=${access}`;
}
/** Leave the wizard. `dismiss` suppresses the future auto-popup (used when read is skipped). */
export function endOnboarding(dismiss: boolean): void {
sessionStorage.removeItem(ONBOARD_ACTIVE);
if (dismiss) localStorage.setItem(ONBOARD_DISMISSED, "1");
}