125 lines
4.7 KiB
TypeScript
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)
|
|
}
|
|
}
|