import { useState, useRef, useMemo } from 'react' import { nostrAuthService } from '@/lib/nostrAuth' import { getWordSuggestions } from '@/lib/keyManagementBIP39' interface UnlockAccountModalProps { onSuccess: () => void onClose: () => void } function WordInputWithAutocomplete({ index, value, onChange, onFocus, onBlur, }: { index: number value: string onChange: (value: string) => void onFocus: () => void onBlur: () => void }): React.ReactElement { const [showSuggestions, setShowSuggestions] = useState(false) const [selectedIndex, setSelectedIndex] = useState(-1) const inputRef = useRef(null) const suggestionsRef = useRef(null) const suggestions = useMemo((): string[] => { if (value.length === 0) { return [] } return getWordSuggestions(value, 5) }, [value]) const handleChange = (event: React.ChangeEvent): void => { const newValue = event.target.value.trim().toLowerCase() setSelectedIndex(-1) if (newValue.length === 0) { setShowSuggestions(false) } onChange(newValue) } const handleKeyDown = (event: React.KeyboardEvent): void => { if (event.key === 'ArrowDown') { event.preventDefault() setSelectedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : prev)) } else if (event.key === 'ArrowUp') { event.preventDefault() setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1)) } else if (event.key === 'Enter' && selectedIndex >= 0 && suggestions[selectedIndex]) { event.preventDefault() onChange(suggestions[selectedIndex] ?? '') setShowSuggestions(false) inputRef.current?.blur() } else if (event.key === 'Escape') { setShowSuggestions(false) inputRef.current?.blur() } } const handleSuggestionClick = (suggestion: string): void => { onChange(suggestion) setShowSuggestions(false) inputRef.current?.blur() } return (
{ // Delay to allow click on suggestion setTimeout(() => { setShowSuggestions(false) onBlur() }, 200) }} className="w-full px-3 py-2 border border-gray-300 rounded-lg font-mono text-lg text-center" autoComplete="off" autoCapitalize="off" autoCorrect="off" spellCheck="false" /> {showSuggestions && suggestions.length > 0 && (
{suggestions.map((suggestion, idx) => ( ))}
)}
) } function WordInputs({ words, onWordChange, }: { words: string[] onWordChange: (index: number, value: string) => void }): React.ReactElement { const [, setFocusedIndex] = useState(null) return (
{words.map((word, index) => ( onWordChange(index, value)} onFocus={() => setFocusedIndex(index)} onBlur={() => setFocusedIndex(null)} /> ))}
) } function useUnlockAccount(words: string[], setWords: (words: string[]) => void, setError: (error: string | null) => void): { handleWordChange: (index: number, value: string) => void handlePaste: () => void } { const handleWordChange = (index: number, value: string): void => { const newWords = [...words] newWords[index] = value.trim().toLowerCase() setWords(newWords) setError(null) } const handlePasteAsync = async (): Promise => { try { const text = await navigator.clipboard.readText() const pastedWords = text.trim().split(/\s+/).slice(0, 4) if (pastedWords.length === 4) { setWords(pastedWords.map((w) => w.toLowerCase())) setError(null) } } catch { // Ignore clipboard errors } } const handlePaste = (): void => { void handlePasteAsync() } return { handleWordChange, handlePaste } } function UnlockAccountButtons({ loading, words, onUnlock, onClose, }: { loading: boolean words: string[] onUnlock: () => void onClose: () => void }): React.ReactElement { return (
) } function UnlockAccountForm({ words, handleWordChange, handlePaste, }: { words: string[] handleWordChange: (index: number, value: string) => void handlePaste: () => void }): React.ReactElement { return (
) } export function UnlockAccountModal({ onSuccess, onClose }: UnlockAccountModalProps): React.ReactElement { const [words, setWords] = useState(['', '', '', '']) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const { handleWordChange, handlePaste } = useUnlockAccount(words, setWords, setError) const handleUnlock = async (): Promise => { if (words.some((word) => !word)) { setError('Veuillez remplir tous les mots-clés') return } setLoading(true) setError(null) try { await nostrAuthService.unlockAccount(words) onSuccess() onClose() } catch (unlockError) { setError(unlockError instanceof Error ? unlockError.message : 'Échec du déverrouillage. Vérifiez vos mots-clés.') } finally { setLoading(false) } } const onUnlock = (): void => { void handleUnlock() } return (

Déverrouiller votre compte

Entrez vos 4 mots-clés de récupération (dictionnaire BIP39) pour déverrouiller votre compte. Ces mots déchiffrent la clé de chiffrement (KEK) stockée dans l'API Credentials, qui déchiffre ensuite votre clé privée.

{error &&

{error}

}
) }