**Motivations:** - Corriger l'erreur 404 pour favicon.ico demandé par les navigateurs - Corriger l'erreur 500 de l'API NIP-95 upload empêchant les uploads de fichiers **Root causes:** - Fichier favicon.ico manquant dans public/ causant des erreurs 404 répétées - Incompatibilité entre form-data (npm) et fetch() natif de Node.js dans l'API NIP-95 **Correctifs:** - Ajout de favicon.svg et mise à jour des références dans les pages - Remplacement de fetch() par https/http natifs de Node.js dans nip95-upload.ts - Amélioration de la gestion des erreurs et nettoyage des fichiers temporaires **Evolutions:** - Documentation des problèmes et solutions dans fixKnowledge/ **Pages affectées:** - components/HomeView.tsx - pages/docs.tsx - pages/presentation.tsx - pages/api/nip95-upload.ts - features/account-creation-buttons-separation.md - fixKnowledge/favicon-404-error.md (nouveau) - fixKnowledge/nip95-upload-500-error.md (nouveau) - public/favicon.svg (nouveau)
128 lines
3.9 KiB
TypeScript
128 lines
3.9 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 { Footer } from '@/components/Footer'
|
|
import { FundingGauge } from '@/components/FundingGauge'
|
|
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>zapwall.fr</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.svg" type="image/svg+xml" />
|
|
</Head>
|
|
)
|
|
}
|
|
|
|
function ArticlesHero({
|
|
searchQuery,
|
|
setSearchQuery,
|
|
selectedCategory,
|
|
setSelectedCategory,
|
|
}: Pick<HomeViewProps, 'searchQuery' | 'setSearchQuery' | 'selectedCategory' | 'setSelectedCategory'>) {
|
|
return (
|
|
<div className="mb-8">
|
|
<CategoryTabs selectedCategory={selectedCategory} onCategoryChange={setSelectedCategory} />
|
|
<div className="mb-4">
|
|
<SearchBar value={searchQuery} onChange={setSearchQuery} />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function HomeIntroSection() {
|
|
return (
|
|
<div className="mt-12 mb-8">
|
|
<div className="mb-6 text-cyber-accent leading-relaxed bg-cyber-dark/50 border border-neon-cyan/20 rounded-lg p-4 backdrop-blur-sm">
|
|
<p className="mb-2">
|
|
Consultez les auteurs et aperçus, achetez les parutions au fil de l'eau par <strong className="text-neon-green">800 sats</strong> (moins 100 sats et frais de transaction).
|
|
</p>
|
|
<p className="mb-2">
|
|
Sponsorisez l'auteur pour <strong className="text-neon-green">0.046 BTC</strong> (moins 0.004 BTC et frais de transaction).
|
|
</p>
|
|
<p className="mb-2">
|
|
Les avis sont remerciables pour <strong className="text-neon-green">70 sats</strong> (moins 21 sats et frais de transaction).
|
|
</p>
|
|
<p className="text-sm text-cyber-accent/70 italic">
|
|
Les fonds de la plateforme servent à son développement.
|
|
</p>
|
|
</div>
|
|
<FundingGauge />
|
|
</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} />
|
|
|
|
<HomeIntroSection />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function HomeView(props: HomeViewProps) {
|
|
return (
|
|
<>
|
|
<HomeHead />
|
|
<main className="min-h-screen bg-cyber-darker">
|
|
<PageHeader />
|
|
<HomeContent {...props} />
|
|
<Footer />
|
|
</main>
|
|
</>
|
|
)
|
|
}
|