File size: 1,718 Bytes
3201ca6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import React from "react";
/**
* localStorage key persisting whether the welcome onboarding flow has
* been completed (or skipped). Once present, the modal won't auto-show
* again on subsequent visits.
*/
export const ONBOARDING_COMPLETED_STORAGE_KEY = "openhands-onboarded";
function readCompletedFromStorage(): boolean {
if (typeof window === "undefined") return true;
try {
return (
window.localStorage.getItem(ONBOARDING_COMPLETED_STORAGE_KEY) !== null
);
} catch {
// Inaccessible localStorage (private mode, SSR, …) — assume the
// user has already onboarded so we don't loop on every render.
return true;
}
}
/**
* Tracks whether the welcome onboarding modal has been completed.
* The hook returns the current `isCompleted` flag plus an imperative
* `markCompleted()` callback. State is mirrored to localStorage and
* synced across tabs via the `storage` event.
*/
export function useOnboardingCompletion() {
const [isCompleted, setIsCompleted] = React.useState<boolean>(() =>
readCompletedFromStorage(),
);
React.useEffect(() => {
const handleStorage = (event: StorageEvent) => {
if (event.key !== ONBOARDING_COMPLETED_STORAGE_KEY) return;
setIsCompleted(readCompletedFromStorage());
};
window.addEventListener("storage", handleStorage);
return () => window.removeEventListener("storage", handleStorage);
}, []);
const markCompleted = React.useCallback(() => {
try {
window.localStorage.setItem(ONBOARDING_COMPLETED_STORAGE_KEY, "1");
} catch {
// best-effort; we still flip the in-memory flag below.
}
setIsCompleted(true);
}, []);
return { isCompleted, markCompleted } as const;
}
|