161 lines
4.8 KiB
TypeScript
161 lines
4.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, createContext, useContext, useCallback, useMemo } from "react";
|
|
import { AgeGate } from "@/components/AgeGate";
|
|
import { Nav } from "@/components/Nav";
|
|
import { MobileHeader } from "@/components/MobileHeader";
|
|
import { IdVerificationModal } from "@/components/IdVerificationModal";
|
|
import { SiteFooter } from "@/components/SiteFooter";
|
|
import { AuthProvider, useAuth } from "@/lib/auth/context";
|
|
import {
|
|
requiresIdVerification,
|
|
getUserState,
|
|
isIdVerified,
|
|
} from "@/lib/id-verification";
|
|
import {
|
|
getAccessCapabilities,
|
|
shouldBlurExplicit,
|
|
type AccessCapabilities,
|
|
} from "@/lib/access-tier";
|
|
|
|
const ActiveCountContext = createContext<(n: number) => void>(() => {});
|
|
const VanillaModeContext = createContext(false);
|
|
const OpenIdVerificationContext = createContext<() => void>(() => {});
|
|
|
|
interface AccessContextValue {
|
|
capabilities: AccessCapabilities;
|
|
blurExplicit: boolean;
|
|
}
|
|
|
|
const AccessContext = createContext<AccessContextValue>({
|
|
capabilities: getAccessCapabilities(false),
|
|
blurExplicit: true,
|
|
});
|
|
|
|
export function useSetActiveCount() {
|
|
return useContext(ActiveCountContext);
|
|
}
|
|
|
|
export function useVanillaMode() {
|
|
return useContext(VanillaModeContext);
|
|
}
|
|
|
|
export function useOpenIdVerification() {
|
|
return useContext(OpenIdVerificationContext);
|
|
}
|
|
|
|
export function useAccess() {
|
|
return useContext(AccessContext);
|
|
}
|
|
|
|
/** @deprecated use useAccess().blurExplicit */
|
|
export function useIdBlur() {
|
|
return useContext(AccessContext).blurExplicit;
|
|
}
|
|
|
|
interface ProvidersProps {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
function InnerProviders({ children }: ProvidersProps) {
|
|
const { user, profile } = useAuth();
|
|
const [vanillaMode, setVanillaMode] = useState(false);
|
|
const [activeCount, setActiveCount] = useState(0);
|
|
const [idModalOpen, setIdModalOpen] = useState(false);
|
|
|
|
const isLoggedIn = !!user;
|
|
const capabilities = useMemo(
|
|
() => getAccessCapabilities(isLoggedIn, profile?.id_verified),
|
|
[isLoggedIn, profile?.id_verified]
|
|
);
|
|
const blurExplicit = useMemo(
|
|
() => shouldBlurExplicit(isLoggedIn, profile?.id_verified) || vanillaMode,
|
|
[isLoggedIn, profile?.id_verified, vanillaMode]
|
|
);
|
|
|
|
useEffect(() => {
|
|
setVanillaMode(localStorage.getItem("eg_vanilla_mode") === "true");
|
|
|
|
const state = getUserState();
|
|
if (
|
|
isLoggedIn &&
|
|
requiresIdVerification(state) &&
|
|
!isIdVerified(profile?.id_verified) &&
|
|
localStorage.getItem("eg_id_verification_prompted") !== "true"
|
|
) {
|
|
const timer = setTimeout(() => setIdModalOpen(true), 2000);
|
|
return () => clearTimeout(timer);
|
|
}
|
|
}, [isLoggedIn, profile?.id_verified]);
|
|
|
|
const handleVanillaToggle = (v: boolean) => {
|
|
setVanillaMode(v);
|
|
localStorage.setItem("eg_vanilla_mode", String(v));
|
|
};
|
|
|
|
const handleIdVerified = useCallback(() => {
|
|
localStorage.setItem("eg_id_verification_prompted", "true");
|
|
}, []);
|
|
|
|
const openIdVerification = useCallback(() => {
|
|
setIdModalOpen(true);
|
|
}, []);
|
|
|
|
return (
|
|
<VanillaModeContext.Provider value={vanillaMode}>
|
|
<AccessContext.Provider value={{ capabilities, blurExplicit }}>
|
|
<OpenIdVerificationContext.Provider value={openIdVerification}>
|
|
<Nav
|
|
vanillaMode={vanillaMode}
|
|
onVanillaToggle={handleVanillaToggle}
|
|
activeCount={activeCount}
|
|
onIdVerifyClick={openIdVerification}
|
|
idBlur={blurExplicit && isLoggedIn}
|
|
isGuest={!isLoggedIn}
|
|
/>
|
|
<MobileHeader
|
|
vanillaMode={vanillaMode}
|
|
onVanillaToggle={handleVanillaToggle}
|
|
activeCount={activeCount}
|
|
isGuest={!isLoggedIn}
|
|
/>
|
|
<main className="md:pt-14 pt-12 pb-16 md:pb-0 min-h-screen min-h-[100dvh] flex flex-col">
|
|
<ActiveCountContext.Provider value={setActiveCount}>
|
|
<div className="flex-1 flex flex-col">{children}</div>
|
|
<SiteFooter />
|
|
</ActiveCountContext.Provider>
|
|
</main>
|
|
<IdVerificationModal
|
|
open={idModalOpen}
|
|
onClose={() => {
|
|
setIdModalOpen(false);
|
|
localStorage.setItem("eg_id_verification_prompted", "true");
|
|
}}
|
|
onVerified={handleIdVerified}
|
|
/>
|
|
</OpenIdVerificationContext.Provider>
|
|
</AccessContext.Provider>
|
|
</VanillaModeContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function Providers({ children }: ProvidersProps) {
|
|
const [verified, setVerified] = useState(false);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
setVerified(localStorage.getItem("eg_age_verified") === "true");
|
|
}, []);
|
|
|
|
if (!mounted) return null;
|
|
|
|
return (
|
|
<>
|
|
{!verified && <AgeGate onVerified={() => setVerified(true)} />}
|
|
<AuthProvider>
|
|
<InnerProviders>{children}</InnerProviders>
|
|
</AuthProvider>
|
|
</>
|
|
);
|
|
} |