story-research-zapwall/components/reviewForms/useReviewFormController.ts
2026-01-09 01:09:02 +01:00

168 lines
4.4 KiB
TypeScript

import { useState } from 'react'
import { publishReview } from '@/lib/articleMutations'
import { nostrService } from '@/lib/nostr'
import { t } from '@/lib/i18n'
import type { ReviewFormProps } from './reviewFormTypes'
import type { Article } from '@/types/nostr'
export interface ReviewFormController {
pubkey: string | null
content: string
title: string
text: string
loading: boolean
error: string | null
setContent: (value: string) => void
setTitle: (value: string) => void
setText: (value: string) => void
handleSubmit: (e: React.FormEvent) => Promise<void>
}
export function useReviewFormController(params: {
article: ReviewFormProps['article']
pubkey: string | null
onSuccess?: () => void
}): ReviewFormController {
const [content, setContent] = useState('')
const [title, setTitle] = useState('')
const [text, setText] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleSubmit = buildReviewSubmitHandler({
article: params.article,
pubkey: params.pubkey,
content,
title,
text,
setLoading,
setError,
reset: () => resetFields({ setContent, setTitle, setText }),
...(params.onSuccess ? { onSuccess: params.onSuccess } : {}),
})
return {
pubkey: params.pubkey,
content,
title,
text,
loading,
error,
setContent,
setTitle,
setText,
handleSubmit,
}
}
function buildReviewSubmitHandler(params: {
article: Article
pubkey: string | null
content: string
title: string
text: string
setLoading: (loading: boolean) => void
setError: (error: string | null) => void
reset: () => void
onSuccess?: () => void
}): (e: React.FormEvent) => Promise<void> {
return async (e: React.FormEvent): Promise<void> => {
e.preventDefault()
const {pubkey} = params
if (!pubkey) {
return
}
const contentError = validateRequiredContent(params.content)
if (contentError) {
params.setError(contentError)
return
}
await submitReview({ ...params, pubkey })
}
}
async function submitReview(params: {
article: Article
pubkey: string
content: string
title: string
text: string
setLoading: (loading: boolean) => void
setError: (error: string | null) => void
reset: () => void
onSuccess?: () => void
}): Promise<void> {
params.setLoading(true)
params.setError(null)
try {
await publishReview(buildPublishReviewParams({ article: params.article, reviewerPubkey: params.pubkey, content: params.content, title: params.title, text: params.text }))
params.reset()
params.onSuccess?.()
} catch (submitError) {
params.setError(submitError instanceof Error ? submitError.message : t('review.form.error.publishFailed'))
} finally {
params.setLoading(false)
}
}
function validateRequiredContent(content: string): string | null {
if (!content.trim()) {
return t('review.form.error.contentRequired')
}
return null
}
function buildPublishReviewParams(params: {
article: Article
reviewerPubkey: string
content: string
title: string
text: string
}): {
articleId: string
seriesId: string
category: 'science-fiction' | 'scientific-research'
authorPubkey: string
reviewerPubkey: string
content: string
title?: string
text?: string
authorPrivateKey: string
} {
const privateKey = nostrService.getPrivateKey()
if (!privateKey) {
throw new Error(t('review.form.error.noPrivateKey'))
}
const category = normalizeArticleCategory(params.article)
const seriesId = params.article.seriesId ?? ''
return {
articleId: params.article.id,
seriesId,
category,
authorPubkey: params.article.pubkey,
reviewerPubkey: params.reviewerPubkey,
content: params.content.trim(),
...(params.title.trim() ? { title: params.title.trim() } : {}),
...(params.text.trim() ? { text: params.text.trim() } : {}),
authorPrivateKey: privateKey,
}
}
function normalizeArticleCategory(article: Article): 'science-fiction' | 'scientific-research' {
if (article.category === 'author-presentation') {
return 'science-fiction'
}
return article.category === 'scientific-research' ? 'scientific-research' : 'science-fiction'
}
function resetFields(params: {
setContent: (value: string) => void
setTitle: (value: string) => void
setText: (value: string) => void
}): void {
params.setContent('')
params.setTitle('')
params.setText('')
}