2026-01-13 14:49:19 +01:00

125 lines
4.7 KiB
TypeScript

import { useCallback, useEffect, useState, type Dispatch, type FormEvent, type SetStateAction } from 'react'
import { useRouter } from 'next/router'
import { useAuthorPresentation } from '@/hooks/useAuthorPresentation'
import { extractPresentationData } from '@/lib/presentationParsing'
import { userConfirm } from '@/lib/userConfirm'
import { t } from '@/lib/i18n'
import type { Article } from '@/types/nostr'
import type { AuthorPresentationDraft } from './types'
import { validatePresentationDraft } from './validation'
export interface AuthorPresentationState {
draft: AuthorPresentationDraft
setDraft: (next: AuthorPresentationDraft) => void
validationError: string | null
error: string | null
loading: boolean
handleSubmit: (e: FormEvent<HTMLFormElement>) => Promise<void>
deleting: boolean
handleDelete: () => Promise<void>
success: boolean
}
export function useAuthorPresentationState(
pubkey: string | null,
existingAuthorName: string | undefined,
existingPresentation: Article | null | undefined,
): AuthorPresentationState {
const { loading, error, success, publishPresentation, deletePresentation } = useAuthorPresentation(pubkey)
const router = useRouter()
const [draft, setDraft] = useState<AuthorPresentationDraft>(() => buildInitialDraft(existingPresentation, existingAuthorName))
const [validationError, setValidationError] = useState<string | null>(null)
const [deleting, setDeleting] = useState(false)
useEffect(() => {
syncAuthorNameIntoDraft({ existingAuthorName, draftAuthorName: draft.authorName, hasExistingPresentation: Boolean(existingPresentation), setDraft })
}, [existingAuthorName, existingPresentation, draft.authorName])
const handleSubmit = useCallback(
async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
await submitPresentationDraft({ draft, setValidationError, publishPresentation })
},
[draft, publishPresentation],
)
const handleDelete = useCallback(async () => {
await deletePresentationFlow({
existingPresentationId: existingPresentation?.id,
deletePresentation,
router,
setDeleting,
setValidationError,
})
}, [existingPresentation, deletePresentation, router])
return { loading, error, success, draft, setDraft, validationError, handleSubmit, deleting, handleDelete }
}
function buildInitialDraft(existingPresentation: Article | null | undefined, existingAuthorName: string | undefined): AuthorPresentationDraft {
if (existingPresentation) {
const { presentation, contentDescription } = extractPresentationData(existingPresentation)
const authorName = existingPresentation.title.replace(/^Présentation de /, '') ?? existingAuthorName ?? ''
return {
authorName,
presentation,
contentDescription,
mainnetAddress: existingPresentation.mainnetAddress ?? '',
...(existingPresentation.bannerUrl ? { pictureUrl: existingPresentation.bannerUrl } : {}),
}
}
return { authorName: existingAuthorName ?? '', presentation: '', contentDescription: '', mainnetAddress: '' }
}
function syncAuthorNameIntoDraft(params: {
existingAuthorName: string | undefined
draftAuthorName: string
hasExistingPresentation: boolean
setDraft: Dispatch<SetStateAction<AuthorPresentationDraft>>
}): void {
if (!params.existingAuthorName || params.hasExistingPresentation || params.existingAuthorName === params.draftAuthorName) {
return
}
params.setDraft((prev) => ({ ...prev, authorName: params.existingAuthorName as string }))
}
async function submitPresentationDraft(params: {
draft: AuthorPresentationDraft
setValidationError: (value: string | null) => void
publishPresentation: (draft: AuthorPresentationDraft) => Promise<void>
}): Promise<void> {
const validationError = validatePresentationDraft(params.draft)
if (validationError) {
params.setValidationError(validationError)
return
}
params.setValidationError(null)
await params.publishPresentation(params.draft)
}
async function deletePresentationFlow(params: {
existingPresentationId: string | undefined
deletePresentation: (articleId: string) => Promise<void>
router: ReturnType<typeof useRouter>
setDeleting: (value: boolean) => void
setValidationError: (value: string | null) => void
}): Promise<void> {
if (!params.existingPresentationId) {
return
}
const confirmed = await userConfirm(t('presentation.delete.confirm'))
if (!confirmed) {
return
}
params.setDeleting(true)
params.setValidationError(null)
try {
await params.deletePresentation(params.existingPresentationId)
await params.router.push('/')
} catch (e) {
params.setValidationError(e instanceof Error ? e.message : t('presentation.delete.error'))
} finally {
params.setDeleting(false)
}
}