2026-01-13 14:49:19 +01:00

175 lines
5.5 KiB
TypeScript

import Head from 'next/head'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { ArticleEditor } from '@/components/ArticleEditor'
import { useNostrAuth } from '@/hooks/useNostrAuth'
import { getSeriesById } from '@/lib/seriesQueries'
import type { Series } from '@/types/nostr'
import { t } from '@/lib/i18n'
import Image from 'next/image'
function PublishHeader({ series }: { series: Series }): React.ReactElement {
return (
<Head>
<title>{t('series.publish.title', { series: series.title })} - zapwall.fr</title>
<meta name="description" content={t('series.publish.description')} />
</Head>
)
}
function SeriesHeader({ series }: { series: Series }): React.ReactElement {
return (
<div className="space-y-3 mb-6">
{series.coverUrl && (
<div className="relative w-full h-32">
<Image
src={series.coverUrl}
alt={series.title}
fill
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover rounded"
/>
</div>
)}
<h1 className="text-2xl font-bold">{series.title}</h1>
<p className="text-sm text-gray-600">{t('series.publish.subtitle')}</p>
</div>
)
}
export default function SeriesPublishPage(): React.ReactElement | null {
const router = useRouter()
const { id } = router.query
const seriesId = typeof id === 'string' ? id : ''
const { pubkey } = useNostrAuth()
const { series, loading, error, isAuthor } = useSeriesPublishPageData(seriesId, pubkey ?? null)
if (!seriesId) {
return null
}
if (loading) {
return <SeriesPublishLoading />
}
if (error || !series) {
return <SeriesPublishError error={error} onBack={() => { void router.back() }} />
}
if (!isAuthor) {
return <SeriesPublishNotAuthor onBack={() => { void router.push(`/series/${seriesId}`) }} />
}
return <SeriesPublishEditorView series={series} seriesId={seriesId} onBack={() => { void router.push(`/series/${seriesId}`) }} onAfterPublish={() => { void router.push(`/series/${seriesId}`) }} />
}
function SeriesPublishLoading(): React.ReactElement {
return (
<main className="min-h-screen bg-gray-50">
<div className="w-full px-4 py-8">
<p className="text-sm text-gray-600">{t('common.loading')}</p>
</div>
</main>
)
}
function SeriesPublishError(params: { error: string | null; onBack: () => void }): React.ReactElement {
return (
<main className="min-h-screen bg-gray-50">
<div className="w-full px-4 py-8">
<p className="text-sm text-red-600">{params.error ?? 'Série introuvable'}</p>
<button onClick={params.onBack} className="mt-4 text-blue-600 hover:text-blue-700 text-sm">
{t('common.back')}
</button>
</div>
</main>
)
}
function SeriesPublishNotAuthor(params: { onBack: () => void }): React.ReactElement {
return (
<main className="min-h-screen bg-gray-50">
<div className="w-full px-4 py-8">
<p className="text-sm text-red-600">{t('series.publish.error.notAuthor')}</p>
<button onClick={params.onBack} className="mt-4 text-blue-600 hover:text-blue-700 text-sm">
{t('common.back')}
</button>
</div>
</main>
)
}
function SeriesPublishEditorView(params: { series: Series; seriesId: string; onBack: () => void; onAfterPublish: () => void }): React.ReactElement {
const handlePublishSuccess = (): void => {
setTimeout(() => {
params.onAfterPublish()
}, 2000)
}
return (
<>
<PublishHeader series={params.series} />
<main className="min-h-screen bg-gray-50">
<header className="bg-white shadow-sm">
<div className="w-full px-4 py-4 flex justify-between items-center">
<h1 className="text-2xl font-bold text-gray-900">zapwall4Science</h1>
</div>
</header>
<div className="w-full px-4 py-8">
<button onClick={params.onBack} className="text-blue-600 hover:text-blue-700 text-sm font-medium mb-4">
{t('common.back')}
</button>
<SeriesHeader series={params.series} />
<ArticleEditor
onPublishSuccess={handlePublishSuccess}
onCancel={params.onBack}
seriesOptions={[{ id: params.series.id, title: params.series.title }]}
onSelectSeries={() => {
// Series is already selected and cannot be changed
}}
defaultSeriesId={params.series.id}
/>
</div>
</main>
</>
)
}
function useSeriesPublishPageData(
seriesId: string,
userPubkey: string | null
): {
series: Series | null
loading: boolean
error: string | null
isAuthor: boolean
} {
const [series, setSeries] = useState<Series | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!seriesId) {
return
}
const load = async (): Promise<void> => {
setLoading(true)
setError(null)
try {
const s = await getSeriesById(seriesId)
if (!s) {
setError('Série introuvable')
setLoading(false)
return
}
setSeries(s)
} catch (e) {
setError(e instanceof Error ? e.message : 'Erreur lors du chargement de la série')
} finally {
setLoading(false)
}
}
void load()
}, [seriesId])
const isAuthor = series !== null && userPubkey !== null && series.pubkey === userPubkey
return { series, loading, error, isAuthor }
}