155 lines
4.8 KiB
TypeScript
155 lines
4.8 KiB
TypeScript
import { useState } from 'react'
|
|
import { publishSeries } from '@/lib/articleMutations'
|
|
import { useNostrAuth } from '@/hooks/useNostrAuth'
|
|
import { nostrService } from '@/lib/nostr'
|
|
import { t } from '@/lib/i18n'
|
|
import type { SeriesDraft, SeriesAggregates } from './createSeriesModalTypes'
|
|
|
|
export interface CreateSeriesModalController {
|
|
draft: SeriesDraft
|
|
setDraft: (draft: SeriesDraft) => void
|
|
loading: boolean
|
|
error: string | null
|
|
canPublish: boolean
|
|
handleClose: () => void
|
|
handleSubmit: (e: React.FormEvent) => Promise<void>
|
|
}
|
|
|
|
export function useCreateSeriesModalController(params: {
|
|
authorPubkey: string
|
|
onClose: () => void
|
|
onSuccess: () => void
|
|
isOpen: boolean
|
|
}): CreateSeriesModalController {
|
|
const { pubkey, isUnlocked } = useNostrAuth()
|
|
const [draft, setDraft] = useState<SeriesDraft>(createInitialDraft())
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const aggregates = computeAggregates({ pubkey, isUnlocked, authorPubkey: params.authorPubkey })
|
|
const handleClose = createHandleClose({ loading, setDraft, setError, onClose: params.onClose })
|
|
const handleSubmit = createHandleSubmit({
|
|
authorPubkey: params.authorPubkey,
|
|
onClose: params.onClose,
|
|
onSuccess: params.onSuccess,
|
|
draft,
|
|
aggregates,
|
|
setDraft,
|
|
setLoading,
|
|
setError,
|
|
})
|
|
|
|
return { draft, setDraft, loading, error, canPublish: aggregates.canPublish, handleClose, handleSubmit }
|
|
}
|
|
|
|
function createInitialDraft(): SeriesDraft {
|
|
return { title: '', description: '', preview: '', coverUrl: '', category: 'science-fiction' }
|
|
}
|
|
|
|
function resetForm(params: { setDraft: (draft: SeriesDraft) => void; setError: (error: string | null) => void }): void {
|
|
params.setDraft(createInitialDraft())
|
|
params.setError(null)
|
|
}
|
|
|
|
function computeAggregates(params: { pubkey: string | null; isUnlocked: boolean; authorPubkey: string }): SeriesAggregates {
|
|
const privateKey = nostrService.getPrivateKey()
|
|
const canPublish = params.pubkey === params.authorPubkey && params.isUnlocked && privateKey !== null
|
|
return { canPublish, privateKey }
|
|
}
|
|
|
|
function getCanSubmitError(params: { canPublish: boolean; draft: SeriesDraft; privateKey: string | null }): string | null {
|
|
if (!params.canPublish || !params.privateKey) {
|
|
return t('series.create.error.notAuthor')
|
|
}
|
|
if (!params.draft.title.trim() || !params.draft.description.trim() || !params.draft.preview.trim()) {
|
|
return t('series.create.error.missingFields')
|
|
}
|
|
return null
|
|
}
|
|
|
|
function createHandleClose(params: {
|
|
loading: boolean
|
|
setDraft: (draft: SeriesDraft) => void
|
|
setError: (error: string | null) => void
|
|
onClose: () => void
|
|
}): () => void {
|
|
return (): void => {
|
|
if (params.loading) {
|
|
return
|
|
}
|
|
resetForm({ setDraft: params.setDraft, setError: params.setError })
|
|
params.onClose()
|
|
}
|
|
}
|
|
|
|
function createHandleSubmit(params: {
|
|
authorPubkey: string
|
|
onClose: () => void
|
|
onSuccess: () => void
|
|
draft: SeriesDraft
|
|
aggregates: SeriesAggregates
|
|
setDraft: (draft: SeriesDraft) => void
|
|
setLoading: (loading: boolean) => void
|
|
setError: (error: string | null) => void
|
|
}): (e: React.FormEvent) => Promise<void> {
|
|
return async (e: React.FormEvent): Promise<void> => submitSeriesForm(params, e)
|
|
}
|
|
|
|
async function submitSeriesForm(
|
|
params: {
|
|
authorPubkey: string
|
|
onClose: () => void
|
|
onSuccess: () => void
|
|
draft: SeriesDraft
|
|
aggregates: SeriesAggregates
|
|
setDraft: (draft: SeriesDraft) => void
|
|
setLoading: (loading: boolean) => void
|
|
setError: (error: string | null) => void
|
|
},
|
|
e: React.FormEvent
|
|
): Promise<void> {
|
|
e.preventDefault()
|
|
const canSubmitError = getCanSubmitError({ canPublish: params.aggregates.canPublish, draft: params.draft, privateKey: params.aggregates.privateKey })
|
|
if (canSubmitError) {
|
|
params.setError(canSubmitError)
|
|
return
|
|
}
|
|
|
|
params.setLoading(true)
|
|
params.setError(null)
|
|
try {
|
|
await publishSeries(buildPublishSeriesParams(params))
|
|
resetForm({ setDraft: params.setDraft, setError: params.setError })
|
|
params.onSuccess()
|
|
params.onClose()
|
|
} catch (submitError) {
|
|
params.setError(submitError instanceof Error ? submitError.message : t('series.create.error.publishFailed'))
|
|
} finally {
|
|
params.setLoading(false)
|
|
}
|
|
}
|
|
|
|
function buildPublishSeriesParams(params: {
|
|
authorPubkey: string
|
|
draft: SeriesDraft
|
|
aggregates: SeriesAggregates
|
|
}): {
|
|
title: string
|
|
description: string
|
|
preview: string
|
|
coverUrl?: string
|
|
category: SeriesDraft['category']
|
|
authorPubkey: string
|
|
authorPrivateKey: string
|
|
} {
|
|
return {
|
|
title: params.draft.title,
|
|
description: params.draft.description,
|
|
preview: params.draft.preview,
|
|
...(params.draft.coverUrl ? { coverUrl: params.draft.coverUrl } : {}),
|
|
category: params.draft.category,
|
|
authorPubkey: params.authorPubkey,
|
|
authorPrivateKey: params.aggregates.privateKey ?? '',
|
|
}
|
|
}
|