fix(session): dismiss expiry warning toast when signed out or extended
The one-shot heads-up toast used duration:Infinity with no id, so it lingered after auto sign-out (when the banner unmounts) and its Extend button 403'd on the expired token. Give the toast a stable id and dismiss it when the banner leaves the warn window or unmounts, matching the MissionReminderToasts pattern.
This commit is contained in:
parent
975a08195a
commit
1e1fc33b6a
1 changed files with 22 additions and 0 deletions
|
|
@ -16,6 +16,13 @@ import {
|
||||||
} from "@/lib/session/countdown";
|
} from "@/lib/session/countdown";
|
||||||
import { SESSION_EXTENDED_EVENT } from "@/hooks/useGameTick";
|
import { SESSION_EXTENDED_EVENT } from "@/hooks/useGameTick";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stable id for the one-shot "session expiring" heads-up toast. A fixed id lets
|
||||||
|
* us dismiss it deterministically (e.g. on sign-out) instead of relying on the
|
||||||
|
* opaque id returned by `toast.info`. Mirrors MissionReminderToasts.
|
||||||
|
*/
|
||||||
|
const SESSION_EXPIRY_TOAST_ID = "session-expiry-warning";
|
||||||
|
|
||||||
interface SessionExpiryBannerProps {
|
interface SessionExpiryBannerProps {
|
||||||
/** Absolute expiry (ms since epoch), server-computed from the JWT `exp`. */
|
/** Absolute expiry (ms since epoch), server-computed from the JWT `exp`. */
|
||||||
sessionExp: number | null;
|
sessionExp: number | null;
|
||||||
|
|
@ -70,6 +77,7 @@ export function SessionExpiryBanner({
|
||||||
toastFiredRef.current = true;
|
toastFiredRef.current = true;
|
||||||
const minutes = Math.round(warnMs / 60_000);
|
const minutes = Math.round(warnMs / 60_000);
|
||||||
toast.info(`Your session expires in about ${minutes} min.`, {
|
toast.info(`Your session expires in about ${minutes} min.`, {
|
||||||
|
id: SESSION_EXPIRY_TOAST_ID,
|
||||||
action: {
|
action: {
|
||||||
label: "Extend",
|
label: "Extend",
|
||||||
onClick: () => void extendSession(),
|
onClick: () => void extendSession(),
|
||||||
|
|
@ -83,6 +91,20 @@ export function SessionExpiryBanner({
|
||||||
if (phase === "warn") fireToast();
|
if (phase === "warn") fireToast();
|
||||||
}, [phase, warnMs, fireToast]);
|
}, [phase, warnMs, fireToast]);
|
||||||
|
|
||||||
|
// The heads-up toast is only relevant while we're in the warn window. Dismiss it
|
||||||
|
// when the user extends (phase leaves "warn") or dismisses the banner, and again
|
||||||
|
// on unmount (sign-out swaps the shell for the landing page) — otherwise the
|
||||||
|
// duration:Infinity toast lingers for a signed-out user and its Extend button 403s.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!visible) toast.dismiss(SESSION_EXPIRY_TOAST_ID);
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
toast.dismiss(SESSION_EXPIRY_TOAST_ID);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const extendSession = useCallback(async () => {
|
const extendSession = useCallback(async () => {
|
||||||
setExtending(true);
|
setExtending(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue