Files
prowler/ui/lib/tours/use-tour-completion.ts
Alan Buscaglia 49309b43d3 feat(ui): UI onboarding system (#11430)
Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
2026-06-15 13:53:48 +02:00

37 lines
1.4 KiB
TypeScript

"use client";
import { useSyncExternalStore } from "react";
import { localStorageAdapter } from "./store/local-storage-adapter";
import type { TourCompletionRecord, TourId } from "./tour-types";
// Subscribes to cross-tab storage events only; same-tab writes manage their own state.
function subscribe(callback: () => void): () => void {
if (typeof window === "undefined") return () => {};
window.addEventListener("storage", callback);
return () => window.removeEventListener("storage", callback);
}
// `localStorageAdapter.get` re-parses JSON each call; cache by serialized form to keep snapshot reference-stable.
const recordCache = new Map<string, TourCompletionRecord | null>();
const serializedCache = new Map<string, string | null>();
// Server snapshot is `null` (no localStorage), avoiding hydration mismatch.
export function useTourCompletion(
tour: TourId | null,
): TourCompletionRecord | null {
const getSnapshot = (): TourCompletionRecord | null => {
if (!tour) return null;
const cacheKey = `${tour.id}.v${tour.version}`;
const record = localStorageAdapter.get(tour);
const serialized = record ? JSON.stringify(record) : null;
if (serializedCache.get(cacheKey) !== serialized) {
serializedCache.set(cacheKey, serialized);
recordCache.set(cacheKey, record);
}
return recordCache.get(cacheKey) ?? null;
};
return useSyncExternalStore(subscribe, getSnapshot, () => null);
}