115 lines
3.2 KiB
TypeScript
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,
|
|
}
|
|
}
|