diff --git a/src/app/providers.tsx b/src/app/providers.tsx index c777ca0..6ec5de4 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -6,7 +6,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ThemeProvider } from '@/contexts/ThemeContext'; import { AuthRateLimitProvider } from '@/contexts/AuthRateLimitContext'; import { RuntimeConfigProvider } from '@/contexts/RuntimeConfigContext'; -import { PrivacyModal } from '@/components/PrivacyModal'; import { AuthLoader } from '@/components/auth/AuthLoader'; interface ProvidersProps { @@ -38,10 +37,7 @@ export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAu > - <> - {children} - {authEnabled && } - + {children} diff --git a/src/components/PrivacyModal.tsx b/src/components/PrivacyModal.tsx index 5909cbc..30bb6f5 100644 --- a/src/components/PrivacyModal.tsx +++ b/src/components/PrivacyModal.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Fragment, useState, useEffect, useCallback } from 'react'; +import { Fragment, useState, useEffect } from 'react'; import { Dialog, DialogPanel, @@ -9,10 +9,12 @@ import { TransitionChild, Button, } from '@headlessui/react'; -import { updateAppConfig, getAppConfig } from '@/lib/client/dexie'; +import { updateAppConfig } from '@/lib/client/dexie'; interface PrivacyModalProps { + isOpen: boolean; onAccept?: () => void; + onDismiss?: () => void; } function PrivacyModalBody({ origin }: { origin: string }) { @@ -38,32 +40,23 @@ function PrivacyModalBody({ origin }: { origin: string }) { ); } -export function PrivacyModal({ onAccept }: PrivacyModalProps) { - const [isOpen, setIsOpen] = useState(false); +export function PrivacyModal({ isOpen, onAccept, onDismiss }: PrivacyModalProps) { const [origin, setOrigin] = useState(''); const [agreed, setAgreed] = useState(false); - const checkPrivacyAccepted = useCallback(async () => { - const config = await getAppConfig(); - if (!config?.privacyAccepted) { - setIsOpen(true); - } - }, []); - - useEffect(() => { - checkPrivacyAccepted().catch((err) => { - console.error('Privacy acceptance check failed:', err); - }); - }, [checkPrivacyAccepted]); - useEffect(() => { if (typeof window === 'undefined') return; setOrigin(window.location.origin); }, []); + useEffect(() => { + if (isOpen) { + setAgreed(false); + } + }, [isOpen]); + const handleAccept = async () => { await updateAppConfig({ privacyAccepted: true }); - setIsOpen(false); if (typeof window !== 'undefined') { window.dispatchEvent(new Event('openreader:privacyAccepted')); } @@ -72,7 +65,7 @@ export function PrivacyModal({ onAccept }: PrivacyModalProps) { return ( - { }}> + { })}> (null); + const [activeBlockingModal, setActiveBlockingModal] = useState<'privacy' | 'claim' | 'migration' | null>(null); const [claimableCounts, setClaimableCounts] = useState(EMPTY_CLAIM_COUNTS); const [migrationCounts, setMigrationCounts] = useState<{ localCount: number; missingCount: number }>({ localCount: 0, @@ -144,12 +145,14 @@ export function OnboardingFlowProvider({ children }: { children: ReactNode }) { } runningAdvanceRef.current = true; try { - if (activeBlockingModal) { - return; - } - const local = await readLocalOnboardingSnapshot(); if (authEnabled && !local.privacyAccepted) { + setActiveBlockingModal('privacy'); + return; + } + if (activeBlockingModal === 'privacy') { + setActiveBlockingModal(null); + } else if (activeBlockingModal) { return; } @@ -237,6 +240,11 @@ export function OnboardingFlowProvider({ children }: { children: ReactNode }) { void advanceFlow(); }, [advanceFlow]); + const handlePrivacyAccepted = useCallback(() => { + setActiveBlockingModal(null); + void advanceFlow(); + }, [advanceFlow]); + useEffect(() => { void advanceFlow(); }, [advanceFlow, authEnabled, isAnonymous, userId]); @@ -280,6 +288,13 @@ export function OnboardingFlowProvider({ children }: { children: ReactNode }) { return ( {children} + {authEnabled && ( + { }} + /> + )} {authEnabled && (