story-research-zapwall/components/CreateAccountModal.tsx
2026-01-08 23:04:56 +01:00

185 lines
4.7 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)
}
interface HandleAccountCreationParams {
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
}
async function handleAccountCreation(params: HandleAccountCreationParams): Promise<void> {
if (params.key !== undefined && !params.key.trim()) {
params.setError('Please enter a private key')
return
}
params.setLoading(true)
params.setError(null)
try {
const result = await createAccountWithKey(params.key?.trim())
params.setRecoveryPhrase(result.recoveryPhrase)
params.setNpub(result.npub)
params.setStep('recovery')
} catch (e) {
params.setError(e instanceof Error ? e.message : params.errorMessage)
} finally {
params.setLoading(false)
}
}
interface AccountCreationState {
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>
}
function useAccountCreation(initialStep: Step = 'choose'): AccountCreationState {
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 = (): Promise<void> =>
handleAccountCreation({
key: undefined,
setLoading,
setError,
setRecoveryPhrase,
setNpub,
setStep,
errorMessage: 'Failed to create account',
})
const handleImport = (): Promise<void> =>
handleAccountCreation({
key: importKey,
setLoading,
setError,
setRecoveryPhrase,
setNpub,
setStep,
errorMessage: '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('')
}
interface RenderStepParams {
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
}
function renderStep(params: RenderStepParams): React.ReactElement {
if (params.step === 'recovery') {
return <RecoveryStep recoveryPhrase={params.recoveryPhrase} npub={params.npub} onContinue={params.handleContinue} />
}
if (params.step === 'import') {
return (
<ImportStep
importKey={params.importKey}
setImportKey={params.setImportKey}
loading={params.loading}
error={params.error}
onImport={params.handleImport}
onBack={() => handleImportBack(params.setStep, params.setError, params.setImportKey)}
/>
)
}
return (
<ChooseStep
loading={params.loading}
error={params.error}
onGenerate={params.handleGenerate}
onImport={() => params.setStep('import')}
onClose={params.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: () => {
void handleImport()
},
setStep,
setError,
handleGenerate: () => {
void handleGenerate()
},
onClose,
})
}