import { useMemo, useState } from 'react' import type { Article } from '@/types/nostr' import { useArticleEditing } from '@/hooks/useArticleEditing' import type { ArticleDraft } from '@/lib/articlePublisherTypes' import type { UserArticlesController, UserArticlesControllerParams } from './types' export function useUserArticlesController(params: UserArticlesControllerParams): UserArticlesController { const [deletedArticleIds, setDeletedArticleIds] = useState>(new Set()) const [articleOverridesById, setArticleOverridesById] = useState>(new Map()) const [unlockedArticles, setUnlockedArticles] = useState>(new Set()) const [pendingDeleteId, setPendingDeleteId] = useState(null) const editingCtx = useArticleEditing(params.currentPubkey) const localArticles = useMemo((): Article[] => { return params.articles.filter((a) => !deletedArticleIds.has(a.id)).map((a) => articleOverridesById.get(a.id) ?? a) }, [articleOverridesById, deletedArticleIds, params.articles]) return { localArticles, unlockedArticles, pendingDeleteId, requestDelete: (id: string) => setPendingDeleteId(id), handleUnlock: createHandleUnlock(params.onLoadContent, setUnlockedArticles), handleDelete: createHandleDelete(editingCtx.deleteArticle, setDeletedArticleIds, setPendingDeleteId), handleEditSubmit: createHandleEditSubmit(editingCtx.submitEdit, editingCtx.editingDraft, params.currentPubkey, setArticleOverridesById), ...editingCtx, } } function createHandleUnlock( onLoadContent: (id: string, pubkey: string) => Promise
, setUnlocked: React.Dispatch>> ): (article: Article) => Promise { return async (article: Article): Promise => { const full = await onLoadContent(article.id, article.pubkey) if (full?.paid) { setUnlocked((prev) => new Set([...prev, article.id])) } } } function createHandleDelete( deleteArticle: (id: string) => Promise, setDeletedArticleIds: React.Dispatch>>, setPendingDeleteId: React.Dispatch> ): (article: Article) => Promise { return async (article: Article): Promise => { const ok = await deleteArticle(article.id) if (ok) { setDeletedArticleIds((prev) => new Set([...prev, article.id])) } setPendingDeleteId(null) } } function createHandleEditSubmit( submitEdit: () => Promise, draft: ReturnType['editingDraft'], currentPubkey: string | null, setArticleOverridesById: React.Dispatch>> ): () => Promise { return async (): Promise => { const result = await submitEdit() if (result && draft) { const updated = buildUpdatedArticle(draft, currentPubkey ?? '', result.articleId) setArticleOverridesById((prev) => { const next = new Map(prev) next.set(result.originalArticleId, { ...updated, id: result.originalArticleId }) return next }) } } } function buildUpdatedArticle(draft: ArticleDraft, pubkey: string, newId: string): Article { const parts = newId.split('_') const hash = parts[0] ?? '' const index = Number.parseInt(parts[1] ?? '0', 10) const version = Number.parseInt(parts[2] ?? '0', 10) return { id: newId, hash, version, index, pubkey, title: draft.title, preview: draft.preview, content: '', description: draft.preview, contentDescription: draft.preview, createdAt: Math.floor(Date.now() / 1000), zapAmount: draft.zapAmount, paid: false, thumbnailUrl: draft.bannerUrl ?? '', ...(draft.category ? { category: draft.category } : {}), ...(draft.seriesId ? { seriesId: draft.seriesId } : {}), ...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}), ...(draft.media ? { media: draft.media } : {}), ...(draft.pages ? { pages: draft.pages } : {}), } }