import { useEffect, useState } from 'react'; import { ShieldCheck, UserPlus, UserMinus, RefreshCw, AlertCircle, CheckCircle, Clock, Users, Settings, Mail, Wallet, Info, AlertTriangle, } from 'lucide-react'; import { useRecoveryStore, Guardian, RecoveryRequest, getGuardianStatusColor, getRequestStatusColor, } from '../../store/recovery'; import { LoadingSpinner } from '../../components/LoadingStates'; /** * Setup Recovery Modal */ function SetupRecoveryModal({ onClose }: { onClose: () => void }) { const { setupRecovery, isLoading } = useRecoveryStore(); const [threshold, setThreshold] = useState(2); const [delaySecs, setDelaySecs] = useState(86400); // 24 hours const [error, setError] = useState(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); try { await setupRecovery(threshold, delaySecs); onClose(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to setup recovery'); } }; return (

Setup Social Recovery

setThreshold(parseInt(e.target.value) || 1)} className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white" />

Number of guardians required to approve recovery

Delay before recovery completes (gives time to cancel if fraudulent)

{error && (
{error}
)}
); } /** * Add Guardian Modal */ function AddGuardianModal({ onClose }: { onClose: () => void }) { const { addGuardian, isLoading } = useRecoveryStore(); const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [address, setAddress] = useState(''); const [error, setError] = useState(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); if (!name.trim()) { setError('Guardian name is required'); return; } try { await addGuardian(name.trim(), email.trim() || undefined, address.trim() || undefined); onClose(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to add guardian'); } }; return (

Add Guardian

setName(e.target.value)} placeholder="e.g., Mom, Best Friend" className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white" />
setEmail(e.target.value)} placeholder="guardian@example.com" className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white" />

For sending recovery notifications

setAddress(e.target.value)} placeholder="synor1..." className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white" />

If they have a Synor wallet

{error && (
{error}
)}
); } /** * Guardian Card */ function GuardianCard({ guardian }: { guardian: Guardian }) { const { removeGuardian, isLoading } = useRecoveryStore(); const [showConfirm, setShowConfirm] = useState(false); const handleRemove = async () => { try { await removeGuardian(guardian.id); } catch (err) { // Error handled by store } }; return (

{guardian.name}

{guardian.status}
{!showConfirm ? ( ) : (
)}
{guardian.email && (
{guardian.email}
)} {guardian.address && (
{guardian.address.slice(0, 20)}...
)}
Added {new Date(guardian.addedAt * 1000).toLocaleDateString()}
); } /** * Recovery Request Card */ function RecoveryRequestCard({ request }: { request: RecoveryRequest }) { const { cancelRecovery, isLoading } = useRecoveryStore(); const handleCancel = async () => { try { await cancelRecovery(request.id); } catch (err) { // Error handled by store } }; const progress = (request.approvals.length / request.requiredApprovals) * 100; return (
{request.status.toUpperCase()}

ID: {request.id}

{request.status === 'pending' && ( )}
{/* Approval progress */}
Approvals {request.approvals.length} / {request.requiredApprovals}

Expires: {new Date(request.expiresAt * 1000).toLocaleString()}

); } /** * Main Recovery Dashboard */ export default function RecoveryDashboard() { const { config, requests, isLoading, error, fetchConfig, fetchRequests, disableRecovery, } = useRecoveryStore(); const [showSetupModal, setShowSetupModal] = useState(false); const [showAddGuardian, setShowAddGuardian] = useState(false); useEffect(() => { fetchConfig(); fetchRequests(); }, [fetchConfig, fetchRequests]); return (
{/* Header */}

Social Recovery

Recover your wallet using trusted guardians

{error && (
{error}
)} {/* Not Setup State */} {!config && !isLoading && (

Social Recovery Not Configured

Set up social recovery to allow trusted friends or family members to help you recover access to your wallet if you lose your keys.

)} {/* Configured State */} {config && ( <> {/* Status Card */}
{config.enabled ? ( ) : ( )}

{config.enabled ? 'Recovery Enabled' : 'Recovery Disabled'}

{config.threshold} of {config.totalGuardians} guardians required

Recovery Delay

{config.recoveryDelaySecs >= 86400 ? `${Math.floor(config.recoveryDelaySecs / 86400)} days` : `${Math.floor(config.recoveryDelaySecs / 3600)} hours`}

{config.enabled && ( )}
{/* Guardians Section */}

Guardians ({config.guardians.length})

{config.guardians.length === 0 ? (

No guardians added yet

Add trusted contacts to enable recovery

) : (
{config.guardians.map((guardian) => ( ))}
)} {config.guardians.length > 0 && config.guardians.length < config.threshold && (
You need at least {config.threshold} guardians for recovery to work
)}
{/* Recovery Requests Section */} {requests.length > 0 && (

Recovery Requests

{requests.map((request) => ( ))}
)} )} {/* Info Box */}

How Social Recovery Works

  1. Add trusted friends or family as guardians
  2. If you lose access, initiate a recovery request
  3. Guardians approve the request (threshold required)
  4. After the delay period, recovery completes
  5. You can cancel fraudulent requests during the delay
{/* Modals */} {showSetupModal && setShowSetupModal(false)} />} {showAddGuardian && setShowAddGuardian(false)} />}
); }