'use client'; import { Fragment, useState, useEffect, useCallback } from 'react'; import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild, Button, } from '@headlessui/react'; import { useAuthSession } from '@/hooks/useAuthSession'; import { useRouter } from 'next/navigation'; import toast from 'react-hot-toast'; type ClaimableCounts = { documents: number; audiobooks: number; preferences: number; progress: number; }; function toClaimableCounts(value: unknown): ClaimableCounts { const rec = (value && typeof value === 'object') ? (value as Record) : {}; return { documents: Number(rec.documents ?? 0), audiobooks: Number(rec.audiobooks ?? 0), preferences: Number(rec.preferences ?? 0), progress: Number(rec.progress ?? 0), }; } export default function ClaimDataModal() { const { data: sessionData } = useAuthSession(); const router = useRouter(); const [isOpen, setIsOpen] = useState(false); const [hasChecked, setHasChecked] = useState(false); const [isClaiming, setIsClaiming] = useState(false); const [claimableCounts, setClaimableCounts] = useState({ documents: 0, audiobooks: 0, preferences: 0, progress: 0, }); const user = sessionData?.user; const checkClaimableData = useCallback(async () => { setHasChecked(true); try { const res = await fetch('/api/user/claim', { method: 'GET', }); if (res.ok) { const data = await res.json(); const counts = toClaimableCounts(data); setClaimableCounts(counts); if (counts.documents + counts.audiobooks + counts.preferences + counts.progress > 0) { setIsOpen(true); } } } catch (e) { console.error(e); } }, []); useEffect(() => { // Only check once per session if user is logged in (non-anonymous) if (user && !user.isAnonymous && !hasChecked) { checkClaimableData(); } }, [user, hasChecked, checkClaimableData]); const handleClaim = async () => { setIsClaiming(true); try { const res = await fetch('/api/user/claim', { method: 'POST', }); if (res.ok) { const data = await res.json(); const claimed = toClaimableCounts(data?.claimed); toast.success( `Successfully claimed ${claimed.documents} documents, ` + `${claimed.audiobooks} audiobooks, ` + `${claimed.preferences} preference set(s), and ` + `${claimed.progress} reading progress record(s)!`, ); setIsOpen(false); router.refresh(); return; } const data = await res.json().catch(() => null) as { error?: string } | null; toast.error(data?.error || 'Failed to claim data.'); } catch { toast.error('Failed to claim data.'); } finally { setIsClaiming(false); } }; const handleDismiss = () => { // Close the modal for this session - will reappear on next page load/refresh setIsOpen(false); // Keep hasChecked = true so useEffect doesn't re-trigger in this session }; return (
Existing Data Found

We found existing anonymous data from before auth was enabled. Claim it now to attach it to your account.

Claimable data
  • {claimableCounts.documents} document(s)
  • {claimableCounts.audiobooks} audiobook(s)
  • {claimableCounts.preferences} preference set(s)
  • {claimableCounts.progress} reading progress record(s)

⚠️ First user to claim this data will own it and revoke access for anyone else.

); }