import { useState, useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { ArrowLeft, Copy, Check, AlertTriangle, Clock } from 'lucide-react'; import { useWalletStore } from '../store/wallet'; /** Seconds before mnemonic is automatically cleared from display */ const MNEMONIC_DISPLAY_TIMEOUT = 60; /** Seconds before clipboard is automatically cleared after copying */ const CLIPBOARD_CLEAR_TIMEOUT = 30; type Step = 'password' | 'mnemonic' | 'verify'; export default function CreateWallet() { const navigate = useNavigate(); const { createWallet } = useWalletStore(); const [step, setStep] = useState('password'); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [mnemonic, setMnemonic] = useState(''); const [copied, setCopied] = useState(false); const [verifyWord, setVerifyWord] = useState(''); const [verifyIndex, setVerifyIndex] = useState(0); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [mnemonicHidden, setMnemonicHidden] = useState(false); const [countdown, setCountdown] = useState(MNEMONIC_DISPLAY_TIMEOUT); const [clipboardTimer, setClipboardTimer] = useState(null); /** * Clear the mnemonic from state for security */ const clearMnemonic = useCallback(() => { setMnemonic(''); setMnemonicHidden(true); }, []); /** * Auto-clear mnemonic after timeout when viewing recovery phrase */ useEffect(() => { if (step !== 'mnemonic' || !mnemonic || mnemonicHidden) return; // Countdown timer const interval = setInterval(() => { setCountdown((prev) => { if (prev <= 1) { clearMnemonic(); return 0; } return prev - 1; }); }, 1000); return () => clearInterval(interval); }, [step, mnemonic, mnemonicHidden, clearMnemonic]); /** * Reset countdown when entering mnemonic step */ useEffect(() => { if (step === 'mnemonic' && mnemonic && !mnemonicHidden) { setCountdown(MNEMONIC_DISPLAY_TIMEOUT); } }, [step, mnemonic, mnemonicHidden]); /** * Clear sensitive state on unmount */ useEffect(() => { return () => { // Clear password and mnemonic from state on unmount setPassword(''); setConfirmPassword(''); setMnemonic(''); setVerifyWord(''); }; }, []); const handleCreateWallet = async () => { if (password !== confirmPassword) { setError('Passwords do not match'); return; } if (password.length < 8) { setError('Password must be at least 8 characters'); return; } setLoading(true); setError(''); try { const result = await createWallet(password); setMnemonic(result.mnemonic); // Random word to verify (1-24) setVerifyIndex(Math.floor(Math.random() * 24)); setStep('mnemonic'); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create wallet'); } finally { setLoading(false); } }; const handleCopyMnemonic = async () => { await navigator.clipboard.writeText(mnemonic); setCopied(true); setTimeout(() => setCopied(false), 2000); // Clear any existing clipboard timer if (clipboardTimer) { clearTimeout(clipboardTimer); } // Auto-clear clipboard after timeout for security const timer = window.setTimeout(async () => { try { // Clear clipboard by writing empty string await navigator.clipboard.writeText(''); setClipboardTimer(null); } catch { // Clipboard API may fail if window not focused } }, CLIPBOARD_CLEAR_TIMEOUT * 1000); setClipboardTimer(timer); }; const handleVerify = () => { const words = mnemonic.split(' '); if (verifyWord.toLowerCase().trim() === words[verifyIndex]) { navigate('/dashboard'); } else { setError(`Incorrect word. Please check word #${verifyIndex + 1}`); } }; const words = mnemonic.split(' '); return (
{/* Back button */} {step === 'password' && (

Create Password

This password will encrypt your wallet. You'll need it every time you open the app.

setPassword(e.target.value)} className="input" placeholder="Enter password (min 8 characters)" />
setConfirmPassword(e.target.value)} className="input" placeholder="Confirm password" />
{error && (

{error}

)}
)} {step === 'mnemonic' && (

Recovery Phrase

Write down these 24 words in order. This is the ONLY way to recover your wallet if you lose access.

{/* Security countdown timer */} {!mnemonicHidden && (
Auto-hiding in {countdown}s for security
)} {mnemonicHidden ? ( /* Mnemonic has been auto-cleared */

Recovery phrase hidden for security

If you haven't saved it, go back and create a new wallet.

) : ( /* Show mnemonic words */
{words.map((word, i) => (
{i + 1}. {word}
))}
)} {!mnemonicHidden && ( <>

Never share your recovery phrase. Anyone with these words can steal your funds.

)}
)} {step === 'verify' && (

Verify Recovery Phrase

Enter word #{verifyIndex + 1} from your recovery phrase to verify you've saved it correctly.

setVerifyWord(e.target.value)} className="input" placeholder={`Enter word #${verifyIndex + 1}`} autoFocus />
{error && (

{error}

)}
)}
); }