diff --git a/src/app/admin/content-pages/[slug]/_components/EditorForm.tsx b/src/app/admin/content-pages/[slug]/_components/EditorForm.tsx index 64e3818..0f2d54a 100644 --- a/src/app/admin/content-pages/[slug]/_components/EditorForm.tsx +++ b/src/app/admin/content-pages/[slug]/_components/EditorForm.tsx @@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"; type Page = { slug: string; + lang: string; title: string; body: string; category: string; @@ -25,11 +26,14 @@ export default function EditorForm({ page }: { page: Page }) { setMsg(null); setErr(null); try { - const res = await fetch(`/api/admin/content-pages/${encodeURIComponent(page.slug)}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ title, body, published }), - }); + const res = await fetch( + `/api/admin/content-pages/${encodeURIComponent(page.slug)}?lang=${encodeURIComponent(page.lang)}`, + { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ title, body, published }), + }, + ); if (!res.ok) { const j = await res.json().catch(() => ({})); throw new Error(j?.error || `HTTP ${res.status}`); diff --git a/src/app/admin/content-pages/[slug]/page.tsx b/src/app/admin/content-pages/[slug]/page.tsx index d9e6b25..db82c4b 100644 --- a/src/app/admin/content-pages/[slug]/page.tsx +++ b/src/app/admin/content-pages/[slug]/page.tsx @@ -2,46 +2,90 @@ import { notFound } from "next/navigation"; import Link from "next/link"; import { requireRole } from "@/lib/authorization"; import { UserRole } from "@/generated/prisma/enums"; -import { getContentPage } from "@/lib/content-pages"; import { prisma } from "@/lib/prisma"; import EditorForm from "./_components/EditorForm"; export const dynamic = "force-dynamic"; -type PageProps = { params: Promise<{ slug: string }> }; +type PageProps = { + params: Promise<{ slug: string }>; + searchParams: Promise<{ lang?: string }>; +}; -export default async function EditContentPage({ params }: PageProps) { +function normalizeLang(v: string | undefined): string { + if (!v) return "fr"; + const l = v.toLowerCase().trim(); + return /^[a-z]{2}$/.test(l) ? l : "fr"; +} + +export default async function EditContentPage({ params, searchParams }: PageProps) { await requireRole([UserRole.ADMIN]); const { slug } = await params; - // Pas getContentPage : il filtre published=true. Ici on veut tout voir. - // Admin édite la version FR par défaut. (Édition EN = future feature.) - const row = await prisma.contentPage.findUnique({ - where: { slug_lang: { slug, lang: "fr" } }, - }); + const sp = await searchParams; + const lang = normalizeLang(sp.lang); + + const [row, siblings] = await Promise.all([ + prisma.contentPage.findUnique({ where: { slug_lang: { slug, lang } } }), + prisma.contentPage.findMany({ + where: { slug }, + select: { lang: true, title: true, published: true, updatedAt: true }, + orderBy: { lang: "asc" }, + }), + ]); if (!row) notFound(); - // Re-construction du type minimal attendu par le formulaire. + const page = { slug: row.slug, + lang: row.lang, title: row.title, body: row.body, category: row.category, published: row.published, - updatedAt: row.updatedAt, }; - // Mute eslint sur le _ = getContentPage (gardé importé pour la cohérence future). - void getContentPage; + return ( -
- URL publique : /{page.slug}
-
+ URL publique : /{page.slug}
+ {page.lang !== "fr" ? ` · variante ${page.lang}` : ""}
+
- Pages markdown affichées dans le site public. La catégorie « Général »
- est gérée par le plugin content-pages, la catégorie « Légales »
- par legal-pages. Désactiver le plugin dépublie ses pages
- sans les supprimer.
-
+ Pages markdown servies par le site public. Chaque page existe en une ou + plusieurs langues — utilisez le bouton de la langue voulue pour éditer + la bonne version. +
+/{p.slug} · {p.published ? "publié" : "dépublié"} ·
- mis à jour le {new Date(p.updatedAt).toLocaleDateString("fr-FR")}
- | Slug | +Titre (FR) | +Traductions | +MAJ | +Éditer | +
|---|---|---|---|---|
| /{p.slug} | ++ {fr ? ( + <> + {fr.title} + {!fr.published ? ( + + dépublié + + ) : null} + > + ) : ( + — (pas de version FR) + )} + | ++ {others.length === 0 ? ( + — + ) : ( + + {others.map((t) => ( + + {t.lang} + + ))} + + )} + | ++ {lastUpdated ? dateFmt.format(new Date(lastUpdated)) : "—"} + | ++ + {p.translations + .sort((a, b) => (a.lang === "fr" ? -1 : b.lang === "fr" ? 1 : a.lang.localeCompare(b.lang))) + .map((t) => ( + + {t.lang} + + ))} + + | +