story-research-zapwall/components/CreateAccountModalComponents.tsx
2026-01-14 11:05:27 +01:00

184 lines
5.1 KiB
TypeScript

import { Button, Card, ErrorState, Textarea } from '@/components/ui'
import { t } from '@/lib/i18n'
export function RecoveryWarning(): React.ReactElement {
return (
<Card variant="default" className="bg-yellow-900/20 border-yellow-400/50 mb-6">
<p className="text-yellow-400 font-semibold mb-2">{t('account.create.recovery.warning.title')}</p>
<p className="text-yellow-300/90 text-sm" dangerouslySetInnerHTML={{ __html: t('account.create.recovery.warning.part1') }} />
<p className="text-yellow-300/90 text-sm mt-2" dangerouslySetInnerHTML={{ __html: t('account.create.recovery.warning.part2') }} />
<p className="text-yellow-300/90 text-sm mt-2">{t('account.create.recovery.warning.part3')}</p>
</Card>
)
}
export function RecoveryPhraseDisplay({
recoveryPhrase,
copied,
onCopy,
}: {
recoveryPhrase: string[]
copied: boolean
onCopy: () => void
}): React.ReactElement {
const recoveryItems = buildRecoveryPhraseItems(recoveryPhrase)
return (
<Card variant="default" className="bg-cyber-darker mb-6">
<div className="grid grid-cols-2 gap-4 mb-4">
{recoveryItems.map((item, index) => (
<Card
key={item.key}
variant="default"
className="bg-cyber-dark 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">{item.word}</span>
</Card>
))}
</div>
<Button
onClick={() => {
void onCopy()
}}
variant="secondary"
size="small"
className="w-full"
>
{copied ? t('account.create.recovery.copied') : t('account.create.recovery.copy')}
</Button>
</Card>
)
}
function buildRecoveryPhraseItems(recoveryPhrase: string[]): { key: string; word: string }[] {
const counts = new Map<string, number>()
return recoveryPhrase.map((word) => {
const nextCount = (counts.get(word) ?? 0) + 1
counts.set(word, nextCount)
return { key: `${word}-${nextCount}`, word }
})
}
export function PublicKeyDisplay({ npub }: { npub: string }): React.ReactElement {
return (
<Card variant="default" className="bg-neon-blue/10 border-neon-blue/30 mb-6">
<p className="text-neon-blue font-semibold mb-2">{t('account.create.publicKey')}</p>
<p className="text-neon-cyan text-sm font-mono break-all">{npub}</p>
</Card>
)
}
export function ImportKeyForm({
importKey,
setImportKey,
error,
}: {
importKey: string
setImportKey: (key: string) => void
error: string | null
}): React.ReactElement {
return (
<>
<Textarea
id="importKey"
label={t('account.create.importKey.label')}
value={importKey}
onChange={(e) => setImportKey(e.target.value)}
placeholder={t('account.create.importKey.placeholder')}
className="font-mono text-sm text-neon-cyan bg-cyber-darker"
rows={4}
helperText={t('account.create.importKey.help')}
/>
{error && <ErrorState message={error} className="mb-4" />}
</>
)
}
export function ImportStepButtons({ loading, onImport, onBack }: { loading: boolean; onImport: () => void; onBack: () => void }): React.ReactElement {
return (
<div className="flex gap-4">
<Button
onClick={onBack}
variant="secondary"
className="flex-1"
>
{t('account.create.back')}
</Button>
<Button
onClick={() => {
void onImport()
}}
disabled={loading}
loading={loading}
variant="primary"
className="flex-1"
>
{loading ? t('import.loading') : t('import.button')}
</Button>
</div>
)
}
function GenerateButton({ loading, onGenerate }: { loading: boolean; onGenerate: () => void }): React.ReactElement {
return (
<Button
onClick={() => {
void onGenerate()
}}
disabled={loading}
loading={loading}
variant="primary"
size="large"
className="w-full"
>
{loading ? t('account.create.importing') : t('account.create.generateButton')}
</Button>
)
}
function ImportButton({ loading, onImport }: { loading: boolean; onImport: () => void }): React.ReactElement {
return (
<Button
onClick={onImport}
disabled={loading}
variant="secondary"
size="large"
className="w-full"
>
{t('account.create.importButton')}
</Button>
)
}
function CancelButton({ onClose }: { onClose: () => void }): React.ReactElement {
return (
<Button
onClick={onClose}
variant="ghost"
className="w-full"
>
{t('account.create.cancel')}
</Button>
)
}
export function ChooseStepButtons({
loading,
onGenerate,
onImport,
onClose,
}: {
loading: boolean
onGenerate: () => void
onImport: () => void
onClose: () => void
}): React.ReactElement {
return (
<div className="flex flex-col gap-4">
<GenerateButton loading={loading} onGenerate={onGenerate} />
<ImportButton loading={loading} onImport={onImport} />
<CancelButton onClose={onClose} />
</div>
)
}