import React, { useState, useRef, useEffect } from 'react'; interface Props { onUnlock: (pk: string) => void; } export default function LockScreen({ onUnlock }: Props) { const [pin, setPin] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [bio, setBio] = useState(false); const ref = useRef(null); useEffect(() => { ref.current?.focus(); if (window.solvox) window.solvox.auth.biometricAvailable().then(b => { setBio(b); if (b) doBio(); }); }, []); const doBio = async () => { if (!window.solvox) return; setLoading(true); const r = await window.solvox.auth.biometric('Unlock SolVox'); if (r.success) { const pk = await window.solvox.wallet.getPublicKey(); if (pk) onUnlock(pk); } else setError(r.error || 'Failed'); setLoading(false); }; const submit = async (e: React.FormEvent) => { e.preventDefault(); if (pin.length < 6) return setError('PIN must be at least 6 digits'); setLoading(true); setError(''); try { if (window.solvox) { const r = await window.solvox.auth.unlock(pin); if (r.success) { const pk = await window.solvox.wallet.getPublicKey(); if (pk) onUnlock(pk); } else setError(r.remainingAttempts !== undefined ? `${r.error} (${r.remainingAttempts} left)` : r.error || 'Failed'); } else onUnlock('Dev' + Date.now()); } catch (e: any) { setError(e.message); } setLoading(false); setPin(''); }; const dots = Array.from({ length: 8 }, (_, i) => i < pin.length); return (
{/* Logo */}
SV

SolVox

Voice-First AI Wallet

{/* PIN Dots */}
{dots.map((f, i) => (
))}
setPin(e.target.value.replace(/\D/g, ''))} maxLength={8} className="sr-only" disabled={loading} />
ref.current?.focus()} className="bg-surface-soft rounded-xl p-4 text-center cursor-text mb-4 border border-hairline hover:border-primary/30 transition-colors">
{pin ? '●'.repeat(pin.length) : Tap to enter PIN}
{error &&
{error}
}
{bio && }
Encrypted locally · No cloud · QVAC on-device
); }