story-research-zapwall/components/CreateAccountModalComponents.tsx

156 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export function RecoveryWarning() {
return (
<div className="bg-yellow-900/20 border border-yellow-400/50 rounded-lg p-4 mb-6">
<p className="text-yellow-400 font-semibold mb-2"> Important</p>
<p className="text-yellow-300/90 text-sm">
Ces <strong className="font-bold">4 mots-clés</strong> sont votre seule façon de récupérer votre compte.
<strong className="font-bold"> Ils ne seront jamais affichés à nouveau.</strong>
</p>
<p className="text-yellow-300/90 text-sm mt-2">
Ces mots-clés (dictionnaire BIP39) sont utilisés avec <strong>PBKDF2</strong> pour chiffrer une clé de chiffrement (KEK) stockée dans l&apos;API Credentials du navigateur. Cette KEK chiffre ensuite votre clé privée stockée dans IndexedDB (système à deux niveaux).
</p>
<p className="text-yellow-300/90 text-sm mt-2">
Notez-les dans un endroit sûr. Sans ces mots-clés, vous perdrez définitivement l&apos;accès à votre compte.
</p>
</div>
)
}
export function RecoveryPhraseDisplay({
recoveryPhrase,
copied,
onCopy,
}: {
recoveryPhrase: string[]
copied: boolean
onCopy: () => void
}) {
return (
<div className="bg-cyber-darker border border-neon-cyan/30 rounded-lg p-6 mb-6">
<div className="grid grid-cols-2 gap-4 mb-4">
{recoveryPhrase.map((word, index) => (
<div
key={index}
className="bg-cyber-dark border border-neon-cyan/30 rounded-lg p-3 text-center font-mono text-lg"
>
<span className="text-cyber-accent/70 text-sm mr-2">{index + 1}.</span>
<span className="font-semibold text-neon-cyan">{word}</span>
</div>
))}
</div>
<button
onClick={() => {
void onCopy()
}}
className="w-full py-2 px-4 bg-cyber-light border border-neon-cyan/30 hover:border-neon-cyan/50 hover:bg-cyber-dark text-cyber-accent hover:text-neon-cyan rounded-lg text-sm font-medium transition-colors"
>
{copied ? '✓ Copié!' : 'Copier les mots-clés'}
</button>
</div>
)
}
export function PublicKeyDisplay({ npub }: { npub: string }) {
return (
<div className="bg-neon-blue/10 border border-neon-blue/30 rounded-lg p-4 mb-6">
<p className="text-neon-blue font-semibold mb-2">Votre clé publique (npub)</p>
<p className="text-neon-cyan text-sm font-mono break-all">{npub}</p>
</div>
)
}
export function ImportKeyForm({
importKey,
setImportKey,
error,
}: {
importKey: string
setImportKey: (key: string) => void
error: string | null
}) {
return (
<>
<div className="mb-4">
<label htmlFor="importKey" className="block text-sm font-medium text-cyber-accent mb-2">
Clé privée (nsec ou hex)
</label>
<textarea
id="importKey"
value={importKey}
onChange={(e) => setImportKey(e.target.value)}
placeholder="nsec1..."
className="w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/30 rounded-lg font-mono text-sm text-neon-cyan"
rows={4}
/>
<p className="text-sm text-cyber-accent/70 mt-2">
Après l&apos;import, vous recevrez <strong>4 mots-clés de récupération</strong> (dictionnaire BIP39) pour sécuriser votre compte.
Ces mots-clés chiffrent une clé de chiffrement (KEK) stockée dans l&apos;API Credentials, qui chiffre ensuite votre clé privée.
</p>
</div>
{error && <p className="text-sm text-red-400 mb-4">{error}</p>}
</>
)
}
export function ImportStepButtons({ loading, onImport, onBack }: { loading: boolean; onImport: () => void; onBack: () => void }) {
return (
<div className="flex gap-4">
<button
onClick={onBack}
className="flex-1 py-2 px-4 bg-cyber-light border border-neon-cyan/30 hover:border-neon-cyan/50 hover:bg-cyber-dark text-cyber-accent hover:text-neon-cyan rounded-lg font-medium transition-colors"
>
Retour
</button>
<button
onClick={() => {
void onImport()
}}
disabled={loading}
className="flex-1 py-2 px-4 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan rounded-lg font-medium transition-all border border-neon-cyan/50 hover:shadow-glow-cyan disabled:opacity-50"
>
{loading ? 'Importation...' : 'Importer'}
</button>
</div>
)
}
export function ChooseStepButtons({
loading,
onGenerate,
onImport,
onClose,
}: {
loading: boolean
onGenerate: () => void
onImport: () => void
onClose: () => void
}) {
return (
<div className="flex flex-col gap-4">
<button
onClick={() => {
void onGenerate()
}}
disabled={loading}
className="w-full py-3 px-6 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan rounded-lg font-medium transition-all border border-neon-cyan/50 hover:shadow-glow-cyan disabled:opacity-50"
>
{loading ? 'Génération...' : 'Générer un nouveau compte'}
</button>
<button
onClick={onImport}
disabled={loading}
className="w-full py-3 px-6 bg-cyber-light border border-neon-cyan/30 hover:border-neon-cyan/50 hover:bg-cyber-dark text-cyber-accent hover:text-neon-cyan rounded-lg font-medium transition-colors disabled:opacity-50"
>
Importer une clé existante
</button>
<button
onClick={onClose}
className="w-full py-2 px-4 text-cyber-accent/70 hover:text-neon-cyan font-medium transition-colors"
>
Annuler
</button>
</div>
)
}