- **Motivations :** Assurer passage du lint strict et clarifier la logique paiements/publications. - **Root causes :** Fonctions trop longues, promesses non gérées et typages WebLN/Nostr incomplets. - **Correctifs :** Refactor PaymentModal (handlers void), extraction helpers articlePublisher, simplification polling sponsoring/zap, corrections curly et awaits. - **Evolutions :** Nouveau module articlePublisherHelpers pour présentation/aiguillage contenu privé. - **Page affectées :** components/PaymentModal.tsx, lib/articlePublisher.ts, lib/articlePublisherHelpers.ts, lib/paymentPolling.ts, lib/sponsoring.ts, lib/nostrZapVerification.ts et dépendances liées.
103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import Head from 'next/head'
|
|
import type { Article } from '@/types/nostr'
|
|
import { ArticleFiltersComponent, type ArticleFilters } from '@/components/ArticleFilters'
|
|
import { CategoryTabs } from '@/components/CategoryTabs'
|
|
import { SearchBar } from '@/components/SearchBar'
|
|
import { ArticlesList } from '@/components/ArticlesList'
|
|
import { PageHeader } from '@/components/PageHeader'
|
|
import type { Dispatch, SetStateAction } from 'react'
|
|
|
|
interface HomeViewProps {
|
|
searchQuery: string
|
|
setSearchQuery: Dispatch<SetStateAction<string>>
|
|
selectedCategory: ArticleFilters['category']
|
|
setSelectedCategory: Dispatch<SetStateAction<ArticleFilters['category']>>
|
|
filters: ArticleFilters
|
|
setFilters: Dispatch<SetStateAction<ArticleFilters>>
|
|
articles: Article[]
|
|
allArticles: Article[]
|
|
loading: boolean
|
|
error: string | null
|
|
onUnlock: (article: Article) => void
|
|
unlockedArticles: Set<string>
|
|
}
|
|
|
|
function HomeHead() {
|
|
return (
|
|
<Head>
|
|
<title>zapwall4Science - Science Fiction & Scientific Research</title>
|
|
<meta
|
|
name="description"
|
|
content="Plateforme de publication d'articles scientifiques et de science-fiction avec sponsoring et rémunération des avis"
|
|
/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link rel="icon" href="/favicon.ico" />
|
|
</Head>
|
|
)
|
|
}
|
|
|
|
function ArticlesHero({
|
|
searchQuery,
|
|
setSearchQuery,
|
|
selectedCategory,
|
|
setSelectedCategory,
|
|
}: Pick<HomeViewProps, 'searchQuery' | 'setSearchQuery' | 'selectedCategory' | 'setSelectedCategory'>) {
|
|
return (
|
|
<div className="mb-8">
|
|
<h2 className="text-3xl font-bold mb-4">Articles</h2>
|
|
<p className="text-gray-600 mb-4">Lisez les aperçus gratuitement, débloquez le contenu complet avec {800} sats</p>
|
|
<CategoryTabs selectedCategory={selectedCategory} onCategoryChange={setSelectedCategory} />
|
|
<div className="mb-4">
|
|
<SearchBar value={searchQuery} onChange={setSearchQuery} />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function HomeContent({
|
|
searchQuery,
|
|
setSearchQuery,
|
|
selectedCategory,
|
|
setSelectedCategory,
|
|
filters,
|
|
setFilters,
|
|
articles,
|
|
allArticles,
|
|
loading,
|
|
error,
|
|
onUnlock,
|
|
unlockedArticles,
|
|
}: HomeViewProps) {
|
|
const shouldShowFilters = !loading && allArticles.length > 0
|
|
const articlesListProps = { articles, allArticles, loading, error, onUnlock, unlockedArticles }
|
|
|
|
return (
|
|
<div className="max-w-4xl mx-auto px-4 py-8">
|
|
<ArticlesHero
|
|
searchQuery={searchQuery}
|
|
setSearchQuery={setSearchQuery}
|
|
selectedCategory={selectedCategory}
|
|
setSelectedCategory={setSelectedCategory}
|
|
/>
|
|
|
|
{shouldShowFilters && (
|
|
<ArticleFiltersComponent filters={filters} onFiltersChange={setFilters} articles={allArticles} />
|
|
)}
|
|
|
|
<ArticlesList {...articlesListProps} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function HomeView(props: HomeViewProps) {
|
|
return (
|
|
<>
|
|
<HomeHead />
|
|
<main className="min-h-screen bg-gray-50">
|
|
<PageHeader />
|
|
<HomeContent {...props} />
|
|
</main>
|
|
</>
|
|
)
|
|
}
|