Nicolas Cantu cb7ee0cfd4 Replace nos2x and NostrConnect with Alby authentication
- Remove nos2x and NostrConnect support
- Create new NostrAuthService using Alby (window.nostr NIP-07)
- Replace useNostrConnect with useNostrAuth in all components
- Update NostrRemoteSigner to use Alby for signing
- Delete NostrConnect-related files (nostrconnect.ts, handlers, etc.)
- Update documentation to reflect Alby-only authentication
- Remove NOSTRCONNECT_BRIDGE environment variable
- All TypeScript checks pass
2025-12-27 23:54:34 +01:00

135 lines
3.9 KiB
TypeScript

import { useState, useEffect, useMemo, useCallback } from 'react'
import { useArticles } from '@/hooks/useArticles'
import { useNostrAuth } from '@/hooks/useNostrAuth'
import { applyFiltersAndSort } from '@/lib/articleFiltering'
import type { Article } from '@/types/nostr'
import type { ArticleFilters } from '@/components/ArticleFilters'
import { HomeView } from '@/components/HomeView'
function usePresentationArticles(allArticles: Article[]) {
const [presentationArticles, setPresentationArticles] = useState<Map<string, Article>>(new Map())
useEffect(() => {
const presentations = new Map<string, Article>()
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<ArticleFilters['category']>(null)
const [filters, setFilters] = useState<ArticleFilters>({
authorPubkey: null,
sortBy: 'newest',
category: null,
})
const [unlockedArticles, setUnlockedArticles] = useState<Set<string>>(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<string, Article>
) {
return useMemo(
() => applyFiltersAndSort(allArticlesRaw, searchQuery, filters, presentationArticles),
[allArticlesRaw, searchQuery, filters, presentationArticles]
)
}
function useUnlockHandler(
loadArticleContent: (id: string, pubkey: string) => Promise<Article | null>,
setUnlockedArticles: React.Dispatch<React.SetStateAction<Set<string>>>
) {
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 { } = useNostrAuth()
const {
searchQuery,
setSearchQuery,
selectedCategory,
setSelectedCategory,
filters,
setFilters,
unlockedArticles,
setUnlockedArticles,
} = useHomeState()
const { allArticlesRaw, allArticles, loading, error, loadArticleContent, presentationArticles } =
useArticlesData(searchQuery)
// Presentation guard removed - users can browse without author page
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 (
<HomeView
{...controller}
onUnlock={(a) => {
void controller.handleUnlock(a)
}}
/>
)
}