import { useState, useEffect, useMemo, useCallback } from 'react' import { useRouter } from 'next/router' import { useArticles } from '@/hooks/useArticles' import { useNostrConnect } from '@/hooks/useNostrConnect' import { useAuthorPresentation } from '@/hooks/useAuthorPresentation' import { applyFiltersAndSort } from '@/lib/articleFiltering' import type { Article } from '@/types/nostr' import type { ArticleFilters } from '@/components/ArticleFilters' import { HomeView } from '@/components/HomeView' function usePresentationGuard(connected: boolean, pubkey: string | null) { const router = useRouter() const { checkPresentationExists } = useAuthorPresentation(pubkey ?? null) useEffect(() => { const ensurePresentation = async () => { if (!connected || !pubkey) { return } const presentation = await checkPresentationExists() if (!presentation) { await router.push('/presentation') } } void ensurePresentation() }, [checkPresentationExists, connected, pubkey, router]) } function usePresentationArticles(allArticles: Article[]) { const [presentationArticles, setPresentationArticles] = useState>(new Map()) useEffect(() => { const presentations = new Map() allArticles.forEach((article) => { if (article.isPresentation && article.pubkey) { presentations.set(article.pubkey, article) } }) setPresentationArticles(presentations) }, [allArticles]) return presentationArticles } function useHomeState() { const [searchQuery, setSearchQuery] = useState('') const [selectedCategory, setSelectedCategory] = useState(null) const [filters, setFilters] = useState({ authorPubkey: null, sortBy: 'newest', category: null, }) const [unlockedArticles, setUnlockedArticles] = useState>(new Set()) return { searchQuery, setSearchQuery, selectedCategory, setSelectedCategory, filters, setFilters, unlockedArticles, setUnlockedArticles, } } function useArticlesData(searchQuery: string) { const { articles: allArticlesRaw, allArticles, loading, error, loadArticleContent } = useArticles(searchQuery, null) const presentationArticles = usePresentationArticles(allArticles) return { allArticlesRaw, allArticles, loading, error, loadArticleContent, presentationArticles } } function useCategorySync(selectedCategory: ArticleFilters['category'], setFilters: (value: ArticleFilters | ((prev: ArticleFilters) => ArticleFilters)) => void) { useEffect(() => { setFilters((prev) => ({ ...prev, category: selectedCategory, })) }, [selectedCategory, setFilters]) } function useFilteredArticles( allArticlesRaw: Article[], searchQuery: string, filters: ArticleFilters, presentationArticles: Map ) { return useMemo( () => applyFiltersAndSort(allArticlesRaw, searchQuery, filters, presentationArticles), [allArticlesRaw, searchQuery, filters, presentationArticles] ) } function useUnlockHandler( loadArticleContent: (id: string, pubkey: string) => Promise
, setUnlockedArticles: React.Dispatch>> ) { return useCallback( async (article: Article) => { const fullArticle = await loadArticleContent(article.id, article.pubkey) if (fullArticle?.paid) { setUnlockedArticles((prev) => new Set([...prev, article.id])) } }, [loadArticleContent, setUnlockedArticles] ) } function useHomeController() { const { connected, pubkey } = useNostrConnect() const { searchQuery, setSearchQuery, selectedCategory, setSelectedCategory, filters, setFilters, unlockedArticles, setUnlockedArticles, } = useHomeState() const { allArticlesRaw, allArticles, loading, error, loadArticleContent, presentationArticles } = useArticlesData(searchQuery) usePresentationGuard(connected, pubkey) useCategorySync(selectedCategory, setFilters) const articles = useFilteredArticles(allArticlesRaw, searchQuery, filters, presentationArticles) const handleUnlock = useUnlockHandler(loadArticleContent, setUnlockedArticles) return { searchQuery, setSearchQuery, selectedCategory, setSelectedCategory, filters, setFilters, articles, allArticles, loading, error, unlockedArticles, handleUnlock, } } export default function Home() { const controller = useHomeController() return ( { void controller.handleUnlock(a) }} /> ) }