104 lines
3.6 KiB
TypeScript
104 lines
3.6 KiB
TypeScript
import { Button, Card } from '@/components/ui'
|
|
import { t } from '@/lib/i18n'
|
|
import type { KeyManagementManagerActions } from './useKeyManagementManager'
|
|
import type { KeyManagementManagerState } from './keyManagementController'
|
|
|
|
export function KeyManagementRecoverySection(params: {
|
|
state: KeyManagementManagerState
|
|
actions: KeyManagementManagerActions
|
|
}): React.ReactElement | null {
|
|
if (!params.state.recoveryPhrase || !params.state.newNpub) {
|
|
return null
|
|
}
|
|
return (
|
|
<div className="mt-6 space-y-4">
|
|
<KeyManagementRecoveryWarning />
|
|
<Card variant="default" className="bg-cyber-darker">
|
|
<RecoveryWordsGrid recoveryPhrase={params.state.recoveryPhrase} />
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
size="small"
|
|
onClick={params.actions.onCopyRecoveryPhrase}
|
|
className="w-full"
|
|
>
|
|
{params.state.copiedRecoveryPhrase ? t('settings.keyManagement.recovery.copied') : t('settings.keyManagement.recovery.copy')}
|
|
</Button>
|
|
</Card>
|
|
<KeyManagementNewNpubCard newNpub={params.state.newNpub} />
|
|
<KeyManagementDoneButton onDone={params.actions.onDoneRecovery} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function KeyManagementRecoveryWarning(): React.ReactElement {
|
|
return (
|
|
<Card variant="default" className="bg-yellow-900/20 border-yellow-400/50">
|
|
<p className="text-yellow-400 font-semibold mb-2">{t('settings.keyManagement.recovery.warning.title')}</p>
|
|
<p className="text-yellow-300/90 text-sm" dangerouslySetInnerHTML={{ __html: t('settings.keyManagement.recovery.warning.part1') }} />
|
|
<p className="text-yellow-300/90 text-sm mt-2" dangerouslySetInnerHTML={{ __html: t('settings.keyManagement.recovery.warning.part2') }} />
|
|
<p className="text-yellow-300/90 text-sm mt-2">{t('settings.keyManagement.recovery.warning.part3')}</p>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
function KeyManagementNewNpubCard(params: { newNpub: string }): React.ReactElement {
|
|
return (
|
|
<Card variant="default" className="bg-neon-blue/10 border-neon-blue/30">
|
|
<p className="text-neon-blue font-semibold mb-2">{t('settings.keyManagement.recovery.newNpub')}</p>
|
|
<p className="text-neon-cyan text-sm font-mono break-all">{params.newNpub}</p>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
function KeyManagementDoneButton(params: { onDone: () => void }): React.ReactElement {
|
|
return (
|
|
<Button
|
|
type="button"
|
|
variant="primary"
|
|
onClick={params.onDone}
|
|
className="w-full"
|
|
>
|
|
{t('settings.keyManagement.recovery.done')}
|
|
</Button>
|
|
)
|
|
}
|
|
|
|
function RecoveryWordsGrid(params: { recoveryPhrase: string[] }): React.ReactElement {
|
|
const items = buildRecoveryWordItems(params.recoveryPhrase)
|
|
return (
|
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
|
{items.map((item) => (
|
|
<Card
|
|
key={item.id}
|
|
variant="default"
|
|
className="bg-cyber-dark p-3 text-center font-mono text-lg"
|
|
>
|
|
<span className="text-cyber-accent/70 text-sm mr-2">{item.position}.</span>
|
|
<span className="font-semibold text-neon-cyan">{item.word}</span>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface RecoveryWordItem {
|
|
id: string
|
|
position: number
|
|
word: string
|
|
}
|
|
|
|
function buildRecoveryWordItems(recoveryPhrase: readonly string[]): RecoveryWordItem[] {
|
|
const occurrences = new Map<string, number>()
|
|
const items: RecoveryWordItem[] = []
|
|
let position = 1
|
|
for (const word of recoveryPhrase) {
|
|
const current = occurrences.get(word) ?? 0
|
|
const next = current + 1
|
|
occurrences.set(word, next)
|
|
items.push({ id: `${word}-${next}`, position, word })
|
|
position += 1
|
|
}
|
|
return items
|
|
}
|