story-research-zapwall/components/CreateAccountModal.tsx
2026-01-06 14:17:55 +01:00

173 lines
4.2 KiB
TypeScript

import { useState } from 'react'
import { nostrAuthService } from '@/lib/nostrAuth'
import { RecoveryStep, ImportStep, ChooseStep } from './CreateAccountModalSteps'
interface CreateAccountModalProps {
onSuccess: (npub: string) => void
onClose: () => void
initialStep?: Step
}
type Step = 'choose' | 'import' | 'recovery'
async function createAccountWithKey(key?: string): Promise<{ recoveryPhrase: string[]; npub: string; publicKey: string }> {
return nostrAuthService.createAccount(key)
}
async function handleAccountCreation(
key: string | undefined,
setLoading: (loading: boolean) => void,
setError: (error: string | null) => void,
setRecoveryPhrase: (phrase: string[]) => void,
setNpub: (npub: string) => void,
setStep: (step: Step) => void,
errorMessage: string
): Promise<void> {
if (key !== undefined && !key.trim()) {
setError('Please enter a private key')
return
}
setLoading(true)
setError(null)
try {
const result = await createAccountWithKey(key?.trim())
setRecoveryPhrase(result.recoveryPhrase)
setNpub(result.npub)
setStep('recovery')
} catch (e) {
setError(e instanceof Error ? e.message : errorMessage)
} finally {
setLoading(false)
}
}
function useAccountCreation(initialStep: Step = 'choose'): {
step: Step
setStep: (step: Step) => void
importKey: string
setImportKey: (key: string) => void
loading: boolean
error: string | null
setError: (error: string | null) => void
recoveryPhrase: string[]
npub: string
handleGenerate: () => Promise<void>
handleImport: () => Promise<void>
} {
const [step, setStep] = useState<Step>(initialStep)
const [importKey, setImportKey] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [recoveryPhrase, setRecoveryPhrase] = useState<string[]>([])
const [npub, setNpub] = useState('')
const handleGenerate = async (): Promise<void> => {
await handleAccountCreation(undefined, setLoading, setError, setRecoveryPhrase, setNpub, setStep, 'Failed to create account')
}
const handleImport = async (): Promise<void> => {
await handleAccountCreation(importKey, setLoading, setError, setRecoveryPhrase, setNpub, setStep, 'Failed to import key')
}
return {
step,
setStep,
importKey,
setImportKey,
loading,
error,
setError,
recoveryPhrase,
npub,
handleGenerate,
handleImport,
}
}
function handleImportBack(setStep: (step: Step) => void, setError: (error: string | null) => void, setImportKey: (key: string) => void): void {
setStep('choose')
setError(null)
setImportKey('')
}
function renderStep(
step: Step,
recoveryPhrase: string[],
npub: string,
importKey: string,
setImportKey: (key: string) => void,
loading: boolean,
error: string | null,
handleContinue: () => void,
handleImport: () => void,
setStep: (step: Step) => void,
setError: (error: string | null) => void,
handleGenerate: () => void,
onClose: () => void
): React.ReactElement {
if (step === 'recovery') {
return <RecoveryStep recoveryPhrase={recoveryPhrase} npub={npub} onContinue={handleContinue} />
}
if (step === 'import') {
return (
<ImportStep
importKey={importKey}
setImportKey={setImportKey}
loading={loading}
error={error}
onImport={handleImport}
onBack={() => handleImportBack(setStep, setError, setImportKey)}
/>
)
}
return (
<ChooseStep
loading={loading}
error={error}
onGenerate={handleGenerate}
onImport={() => setStep('import')}
onClose={onClose}
/>
)
}
export function CreateAccountModal({ onSuccess, onClose, initialStep = 'choose' }: CreateAccountModalProps): React.ReactElement {
const {
step,
setStep,
importKey,
setImportKey,
loading,
error,
setError,
recoveryPhrase,
npub,
handleGenerate,
handleImport,
} = useAccountCreation(initialStep)
const handleContinue = (): void => {
onSuccess(npub)
onClose()
}
return renderStep(
step,
recoveryPhrase,
npub,
importKey,
setImportKey,
loading,
error,
handleContinue,
handleImport,
setStep,
setError,
handleGenerate,
onClose
)
}