story-research-zapwall/components/reviewForms/useReviewTipFormController.ts
2026-01-08 23:53:05 +01:00

84 lines
2.7 KiB
TypeScript

import { useState } from 'react'
import { nostrService } from '@/lib/nostr'
import { t } from '@/lib/i18n'
import { buildReviewTipZapRequestTags } from '@/lib/zapRequestBuilder'
import { calculateReviewSplit } from '@/lib/platformCommissions'
import type { Article, Review } from '@/types/nostr'
export interface ReviewTipFormController {
pubkey: string | null
text: string
loading: boolean
error: string | null
split: ReturnType<typeof calculateReviewSplit>
setText: (value: string) => void
handleSubmit: (e: React.FormEvent) => Promise<void>
}
export function useReviewTipFormController(params: {
review: Review
article: Article
pubkey: string | null
onSuccess?: () => void
}): ReviewTipFormController {
const [text, setText] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const split = calculateReviewSplit()
const handleSubmit = async (e: React.FormEvent): Promise<void> => {
e.preventDefault()
if (!params.pubkey) {
return
}
setLoading(true)
setError(null)
try {
await createAndPublishZapRequest({ review: params.review, article: params.article, text, split })
setText('')
params.onSuccess?.()
} catch (submitError) {
setError(submitError instanceof Error ? submitError.message : t('reviewTip.form.error.paymentFailed'))
} finally {
setLoading(false)
}
}
return { pubkey: params.pubkey, text, loading, error, split, setText, handleSubmit }
}
async function createAndPublishZapRequest(params: {
review: Review
article: Article
text: string
split: ReturnType<typeof calculateReviewSplit>
}): Promise<void> {
if (!nostrService.getPrivateKey()) {
throw new Error(t('reviewTip.form.error.noPrivateKey'))
}
const category = getArticleCategoryForTip(params.article)
const zapRequestTags = buildReviewTipZapRequestTags({
articleId: params.article.id,
reviewId: params.review.id,
authorPubkey: params.article.pubkey,
reviewerPubkey: params.review.reviewerPubkey,
...(category ? { category } : {}),
...(params.article.seriesId ? { seriesId: params.article.seriesId } : {}),
...(params.text.trim() ? { text: params.text.trim() } : {}),
})
await nostrService.createZapRequest(params.review.reviewerPubkey, params.review.id, params.split.total, zapRequestTags)
}
function getArticleCategoryForTip(article: Article): 'science-fiction' | 'scientific-research' | undefined {
if (article.category === 'author-presentation') {
return undefined
}
if (article.category === 'science-fiction' || article.category === 'scientific-research') {
return article.category
}
return undefined
}