story-research-zapwall/hooks/useArticleEditing.ts
2025-12-23 02:20:57 +01:00

115 lines
3.2 KiB
TypeScript

import { useState } from 'react'
import type { ArticleDraft } from '@/lib/articlePublisher'
import type { ArticleUpdateResult } from '@/lib/articleMutations'
import { publishArticleUpdate, deleteArticleEvent, getStoredContent } from '@/lib/articleMutations'
import { nostrService } from '@/lib/nostr'
import type { Article } from '@/types/nostr'
interface EditState {
draft: ArticleDraft | null
articleId: string | null
}
export function useArticleEditing(authorPubkey: string | null) {
const [state, setState] = useState<EditState>({ draft: null, articleId: null })
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const updateDraft = (draft: ArticleDraft | null) => {
setState((prev) => ({ ...prev, draft }))
}
const startEditing = async (article: Article) => {
if (!authorPubkey) {
setError('Connect your Nostr wallet to edit')
return
}
setLoading(true)
setError(null)
try {
const stored = await getStoredContent(article.id)
if (!stored) {
setError('Private content not available locally. Please republish from original device.')
setLoading(false)
return
}
setState({
articleId: article.id,
draft: {
title: article.title,
preview: article.preview,
content: stored.content,
zapAmount: article.zapAmount,
...(article.category === 'science-fiction' || article.category === 'scientific-research'
? { category: article.category }
: {}),
},
})
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to load draft')
} finally {
setLoading(false)
}
}
const cancelEditing = () => {
setState({ draft: null, articleId: null })
setError(null)
}
const submitEdit = async (): Promise<ArticleUpdateResult | null> => {
if (!authorPubkey || !state.articleId || !state.draft) {
setError('Missing data for update')
return null
}
setLoading(true)
setError(null)
try {
const privateKey = nostrService.getPrivateKey() ?? undefined
const result = await publishArticleUpdate(state.articleId, state.draft, authorPubkey, privateKey)
if (!result.success) {
setError(result.error ?? 'Update failed')
return null
}
return result
} catch (e) {
setError(e instanceof Error ? e.message : 'Update failed')
return null
} finally {
setLoading(false)
setState({ draft: null, articleId: null })
}
}
const deleteArticle = async (articleId: string): Promise<boolean> => {
if (!authorPubkey) {
setError('Connect your Nostr wallet to delete')
return false
}
setLoading(true)
setError(null)
try {
const privateKey = nostrService.getPrivateKey() ?? undefined
await deleteArticleEvent(articleId, authorPubkey, privateKey)
return true
} catch (e) {
setError(e instanceof Error ? e.message : 'Delete failed')
return false
} finally {
setLoading(false)
}
}
return {
editingDraft: state.draft,
editingArticleId: state.articleId,
loading,
error,
startEditing,
cancelEditing,
submitEdit,
deleteArticle,
updateDraft,
}
}