import { useEffect, useState, type Dispatch, type SetStateAction } from 'react' import type { Article } from '@/types/nostr' import { useArticleEditing } from '@/hooks/useArticleEditing' import { UserArticlesView } from './UserArticlesList' import { EditPanel } from './UserArticlesEditPanel' interface UserArticlesProps { articles: Article[] loading: boolean error: string | null onLoadContent: (articleId: string, authorPubkey: string) => Promise
showEmptyMessage?: boolean currentPubkey: string | null onSelectSeries?: ((seriesId: string | undefined) => void) | undefined } export function UserArticles({ articles, loading, error, onLoadContent, showEmptyMessage = true, currentPubkey, onSelectSeries, }: UserArticlesProps) { const controller = useUserArticlesController({ articles, onLoadContent, currentPubkey }) return ( ) } function useUserArticlesController({ articles, onLoadContent, currentPubkey, }: { articles: Article[] onLoadContent: (articleId: string, authorPubkey: string) => Promise
currentPubkey: string | null }) { const [localArticles, setLocalArticles] = useState(articles) const [unlockedArticles, setUnlockedArticles] = useState>(new Set()) const [pendingDeleteId, setPendingDeleteId] = useState(null) const editingCtx = useArticleEditing(currentPubkey) useEffect(() => setLocalArticles(articles), [articles]) return { localArticles, unlockedArticles, pendingDeleteId, requestDelete: (id: string) => setPendingDeleteId(id), handleUnlock: createHandleUnlock(onLoadContent, setUnlockedArticles), handleDelete: createHandleDelete(editingCtx.deleteArticle, setLocalArticles, setPendingDeleteId), handleEditSubmit: createHandleEditSubmit( editingCtx.submitEdit, editingCtx.editingDraft, currentPubkey, setLocalArticles ), ...editingCtx, } } function createHandleUnlock( onLoadContent: (id: string, pubkey: string) => Promise
, setUnlocked: Dispatch>> ) { return async (article: Article) => { const full = await onLoadContent(article.id, article.pubkey) if (full?.paid) { setUnlocked((prev) => new Set([...prev, article.id])) } } } function createHandleDelete( deleteArticle: (id: string) => Promise, setLocalArticles: Dispatch>, setPendingDeleteId: Dispatch> ) { return async (article: Article) => { const ok = await deleteArticle(article.id) if (ok) { setLocalArticles((prev) => prev.filter((a) => a.id !== article.id)) } setPendingDeleteId(null) } } function createHandleEditSubmit( submitEdit: () => Promise, draft: ReturnType['editingDraft'], currentPubkey: string | null, setLocalArticles: Dispatch> ) { return async () => { const result = await submitEdit() if (result && draft) { const updated = buildUpdatedArticle(draft, currentPubkey ?? '', result.articleId) setLocalArticles((prev) => { const filtered = prev.filter((a) => a.id !== result.originalArticleId) return [updated, ...filtered] }) } } } function buildUpdatedArticle( draft: NonNullable['editingDraft']>, pubkey: string, newId: string ): Article { return { id: newId, pubkey, title: draft.title, preview: draft.preview, content: '', createdAt: Math.floor(Date.now() / 1000), zapAmount: draft.zapAmount, paid: false, ...(draft.category ? { category: draft.category } : {}), } } function UserArticlesLayout({ controller, loading, error, showEmptyMessage, currentPubkey, onSelectSeries, }: { controller: ReturnType loading: boolean error: string | null showEmptyMessage: boolean currentPubkey: string | null onSelectSeries?: ((seriesId: string | undefined) => void) | undefined }) { const { editPanelProps, listProps } = createLayoutProps(controller, { loading, error, showEmptyMessage, currentPubkey, onSelectSeries, }) return (
) } function createLayoutProps( controller: ReturnType, view: { loading: boolean error: string | null showEmptyMessage: boolean currentPubkey: string | null onSelectSeries?: ((seriesId: string | undefined) => void) | undefined } ) { return { editPanelProps: buildEditPanelProps(controller), listProps: buildListProps(controller, view), } } function buildEditPanelProps(controller: ReturnType) { return { draft: controller.editingDraft, editingArticleId: controller.editingArticleId, loading: controller.loading, error: controller.error, onCancel: controller.cancelEditing, onDraftChange: controller.updateDraft, onSubmit: controller.handleEditSubmit, } } function buildListProps( controller: ReturnType, view: { loading: boolean error: string | null showEmptyMessage: boolean currentPubkey: string | null onSelectSeries?: ((seriesId: string | undefined) => void) | undefined } ) { return { articles: controller.localArticles, loading: view.loading, error: view.error, showEmptyMessage: view.showEmptyMessage, unlockedArticles: controller.unlockedArticles, onUnlock: (a: Article) => { void controller.handleUnlock(a) }, onEdit: (a: Article) => { void controller.startEditing(a) }, onDelete: (a: Article) => { void controller.handleDelete(a) }, editingArticleId: controller.editingArticleId, currentPubkey: view.currentPubkey, pendingDeleteId: controller.pendingDeleteId, requestDelete: controller.requestDelete, ...(view.onSelectSeries ? { onSelectSeries: view.onSelectSeries } : {}), } }