From 32da38b24f82562a5e4392d6140ca35873066565 Mon Sep 17 00:00:00 2001 From: gosangam Date: Sun, 10 May 2026 00:35:14 +0530 Subject: [PATCH] feat: implement bff layer --- app/api/books/[book]/route.ts | 8 +- app/api/books/[book]/verses/route.ts | 58 +- app/api/books/route.ts | 6 +- app/api/glossary/route.ts | 6 +- app/books/bbd/page.tsx | 1 - app/books/bk/[chapter]/page.tsx | 9 +- app/books/bs/page.tsx | 2 - app/books/cbhc/[chapter]/page.tsx | 9 +- app/books/ds/page.tsx | 1 - app/books/ej/page.tsx | 1 - app/books/ek/page.tsx | 1 - app/books/gg/[chapter]/page.tsx | 9 +- app/books/gg/page.tsx | 2 - app/books/hkh/page.tsx | 1 - app/books/iso/[mantra]/page.tsx | 11 +- app/books/iso/page.tsx | 3 - app/books/kb/[volume]/page.tsx | 2 - app/books/lcl/[chapter]/page.tsx | 9 +- app/books/lcl/page.tsx | 2 - app/books/lob/page.tsx | 1 - app/books/mg/page.tsx | 1 - app/books/mm/page.tsx | 1 - app/books/mog/page.tsx | 1 - app/books/nbs/page.tsx | 1 - app/books/nod/[chapter]/page.tsx | 9 +- app/books/nod/page.tsx | 1 - app/books/noi/page.tsx | 3 - app/books/ochkm/page.tsx | 1 - app/books/owk/page.tsx | 1 - app/books/poy/page.tsx | 1 - app/books/pqpa/[chapter]/page.tsx | 9 +- app/books/pqpa/page.tsx | 2 - app/books/rv/page.tsx | 1 - app/books/ssr/page.tsx | 2 - app/books/sva/page.tsx | 2 - app/books/tlc/[chapter]/page.tsx | 85 +- app/books/tlc/page.tsx | 1 - app/books/tlk/[chapter]/page.tsx | 9 +- app/books/tlk/page.tsx | 2 - app/books/tqk/[chapter]/page.tsx | 9 +- app/books/tqk/page.tsx | 2 - app/essays/[slug]/page.tsx | 38 +- app/essays/page.tsx | 12 +- .../[slug]/play-audio-button.tsx | 6 +- app/transcriptions/place/[place]/page.tsx | 15 +- .../type/[type]/type-browser.tsx | 14 +- components/site-footer.tsx | 2 +- lib/api.ts | 341 +++-- lib/bbd.ts | 275 +--- lib/bff.ts | 123 ++ lib/bk.ts | 314 +---- lib/books.ts | 368 +++++ lib/bs.ts | 379 +---- lib/cbhc.ts | 314 +---- lib/db.ts | 11 - lib/disciples.ts | 246 ++-- lib/ds.ts | 344 +---- lib/ej.ts | 277 +--- lib/ek.ts | 275 +--- lib/gg.ts | 464 +----- lib/hkh.ts | 301 +--- lib/iso.ts | 354 +---- lib/journals.ts | 117 +- lib/lcl.ts | 462 +----- lib/letters.ts | 256 ++-- lib/lob.ts | 448 +----- lib/magazines.ts | 130 +- lib/mg.ts | 275 +--- lib/mog.ts | 447 +----- lib/nod.ts | 351 +---- lib/noi.ts | 323 +---- lib/ochkm.ts | 277 +--- lib/other-documents.ts | 142 +- lib/owk.ts | 275 +--- lib/pk.ts | 321 +---- lib/poy.ts | 275 +--- lib/pqpa.ts | 357 +---- lib/rv.ts | 275 +--- lib/ssr.ts | 355 +---- lib/sva.ts | 521 +------ lib/te.ts | 196 +-- lib/tlc.ts | 309 +--- lib/tlk.ts | 470 +------ lib/tqk.ts | 466 +----- lib/transcriptions.ts | 276 ++-- lib/ttp.ts | 297 +--- lib/va.ts | 182 +-- package.json | 5 - prisma.config.ts | 9 - prisma/schema.prisma | 398 ------ yarn.lock | 1244 +---------------- 91 files changed, 2434 insertions(+), 11784 deletions(-) create mode 100644 lib/bff.ts create mode 100644 lib/books.ts delete mode 100644 lib/db.ts delete mode 100644 prisma.config.ts delete mode 100644 prisma/schema.prisma diff --git a/app/api/books/[book]/route.ts b/app/api/books/[book]/route.ts index 3098a9f0..2e71cc78 100644 --- a/app/api/books/[book]/route.ts +++ b/app/api/books/[book]/route.ts @@ -1,12 +1,12 @@ import { NextResponse } from "next/server"; -import { prisma } from "@/lib/db"; +import { getBookMeta } from "@/lib/api"; export async function GET( _req: Request, - { params }: { params: Promise<{ book: string }> } + { params }: { params: Promise<{ book: string }> }, ) { const { book } = await params; - const meta = await prisma.bookMeta.findUnique({ where: { book } }); + const meta = await getBookMeta(book); if (!meta) return NextResponse.json({ error: "Not found" }, { status: 404 }); - return NextResponse.json({ book: meta.book, ...meta.data as Record }); + return NextResponse.json(meta); } diff --git a/app/api/books/[book]/verses/route.ts b/app/api/books/[book]/verses/route.ts index 11eecd8a..6947d572 100644 --- a/app/api/books/[book]/verses/route.ts +++ b/app/api/books/[book]/verses/route.ts @@ -1,5 +1,9 @@ import { NextResponse } from "next/server"; -import { prisma } from "@/lib/db"; +import { + getSingleVerse, + getChapterVerseIndex, + getChapterVerses, +} from "@/lib/api"; export async function GET( req: Request, @@ -7,7 +11,7 @@ export async function GET( ) { const { book } = await params; const url = new URL(req.url); - const division = url.searchParams.get("division"); + const division = url.searchParams.get("division") || null; const chapterStr = url.searchParams.get("chapter"); const verseStr = url.searchParams.get("verse"); const indexOnly = url.searchParams.get("indexOnly") === "true"; @@ -22,20 +26,18 @@ export async function GET( } const chapter = parseInt(chapterStr); - const where: Record = { book, chapter }; - if (book === "bg") { - where.division = null; - } else if (division) { - where.division = division; - } + const effectiveDivision = book === "bg" ? null : division; // --- Single verse mode: ?verse=N --- if (verseStr) { const verseNum = parseInt(verseStr); - const verse = await prisma.verse.findFirst({ - where: { ...where, verse: verseNum }, - }); + const verse = await getSingleVerse( + book, + effectiveDivision, + chapter, + verseNum, + ); if (!verse) { return NextResponse.json({ error: "Verse not found" }, { status: 404 }); @@ -46,15 +48,7 @@ export async function GET( // --- Index-only mode: return lightweight verse list for the sidebar --- if (indexOnly) { - const verses = await prisma.verse.findMany({ - where, - orderBy: { verse: "asc" }, - select: { - verse: true, - verseEnd: true, - reference: true, - }, - }); + const verses = await getChapterVerseIndex(book, effectiveDivision, chapter); return NextResponse.json({ verses, total: verses.length }); } @@ -62,24 +56,14 @@ export async function GET( // --- Paginated mode: return full verse data in pages --- const page = Math.max(1, parseInt(pageStr || "1")); const limit = Math.min(100, Math.max(1, parseInt(limitStr || "20"))); - const skip = (page - 1) * limit; - const [verses, total] = await Promise.all([ - prisma.verse.findMany({ - where, - orderBy: { verse: "asc" }, - skip, - take: limit, - }), - prisma.verse.count({ where }), - ]); - - return NextResponse.json({ - verses, - total, + const result = await getChapterVerses( + book, + effectiveDivision, + chapter, page, limit, - totalPages: Math.ceil(total / limit), - hasMore: skip + verses.length < total, - }); + ); + + return NextResponse.json(result); } diff --git a/app/api/books/route.ts b/app/api/books/route.ts index 007f02dd..81b74b52 100644 --- a/app/api/books/route.ts +++ b/app/api/books/route.ts @@ -1,7 +1,7 @@ import { NextResponse } from "next/server"; -import { prisma } from "@/lib/db"; +import { getAllBooks } from "@/lib/api"; export async function GET() { - const metas = await prisma.bookMeta.findMany(); - return NextResponse.json(metas.map((m) => ({ book: m.book, ...m.data as Record }))); + const books = await getAllBooks(); + return NextResponse.json(books); } diff --git a/app/api/glossary/route.ts b/app/api/glossary/route.ts index ab2c6a2e..24084b68 100644 --- a/app/api/glossary/route.ts +++ b/app/api/glossary/route.ts @@ -1,9 +1,7 @@ import { NextResponse } from "next/server"; -import { prisma } from "@/lib/db"; +import { getAllGlossaryEntries } from "@/lib/api"; export async function GET() { - const entries = await prisma.glossaryEntry.findMany({ - orderBy: { term: "asc" }, - }); + const entries = await getAllGlossaryEntries(); return NextResponse.json(entries); } diff --git a/app/books/bbd/page.tsx b/app/books/bbd/page.tsx index de54184e..68d7c31f 100644 --- a/app/books/bbd/page.tsx +++ b/app/books/bbd/page.tsx @@ -60,7 +60,6 @@ export default async function BbdPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/bk/[chapter]/page.tsx b/app/books/bk/[chapter]/page.tsx index 575d63d1..bc062030 100644 --- a/app/books/bk/[chapter]/page.tsx +++ b/app/books/bk/[chapter]/page.tsx @@ -162,14 +162,7 @@ function SidebarLink({ item: BkSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {introduction.paragraphs.length} paragraphs @@ -133,7 +132,6 @@ export default async function BsPage() { {foreword.title}

- {foreword.paragraphs.length} paragraphs diff --git a/app/books/cbhc/[chapter]/page.tsx b/app/books/cbhc/[chapter]/page.tsx index 5b8f7e8c..995a686c 100644 --- a/app/books/cbhc/[chapter]/page.tsx +++ b/app/books/cbhc/[chapter]/page.tsx @@ -162,14 +162,7 @@ function SidebarLink({ item: CbhcSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs diff --git a/app/books/ej/page.tsx b/app/books/ej/page.tsx index f6d8cc1d..d93e9ead 100644 --- a/app/books/ej/page.tsx +++ b/app/books/ej/page.tsx @@ -63,7 +63,6 @@ export default async function EjPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/ek/page.tsx b/app/books/ek/page.tsx index d5fe520b..c2a92a63 100644 --- a/app/books/ek/page.tsx +++ b/app/books/ek/page.tsx @@ -60,7 +60,6 @@ export default async function EkPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/gg/[chapter]/page.tsx b/app/books/gg/[chapter]/page.tsx index e29ce60b..b9548296 100644 --- a/app/books/gg/[chapter]/page.tsx +++ b/app/books/gg/[chapter]/page.tsx @@ -217,14 +217,7 @@ function SidebarLink({ item: GgSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs @@ -126,7 +125,6 @@ export default async function GgPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/hkh/page.tsx b/app/books/hkh/page.tsx index a4861446..8b07286d 100644 --- a/app/books/hkh/page.tsx +++ b/app/books/hkh/page.tsx @@ -60,7 +60,6 @@ export default async function HkhPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/iso/[mantra]/page.tsx b/app/books/iso/[mantra]/page.tsx index f7f1b1d3..0caa1528 100644 --- a/app/books/iso/[mantra]/page.tsx +++ b/app/books/iso/[mantra]/page.tsx @@ -50,8 +50,11 @@ export async function generateMetadata({ const isVerse_ = content && "mantra" in content && "devanagari" in content; const paragraphs = content ? isVerse_ - ? [(content as IsoVerse).translation, ...(content as IsoVerse).purport] - : (content as IsoIntroSegment).paragraphs + ? [ + (content as unknown as IsoVerse).translation, + ...(content as unknown as IsoVerse).purport, + ] + : (content as unknown as IsoIntroSegment).paragraphs : undefined; const quote = extractQuoteFromHl(sp, paragraphs); @@ -64,7 +67,7 @@ export async function generateMetadata({ } const title = isVerse_ - ? `${(content as IsoVerse).reference}: ${(content as IsoVerse).title}` + ? `${(content as unknown as IsoVerse).reference}` : content && "title" in content ? (content as IsoIntroSegment).title : `Mantra ${slug}`; @@ -110,7 +113,7 @@ export default async function IsoMantraPage({ {verse && ( <> {verse.reference}: - {verse.title} + {verse.bookTitle} )} {intro && intro.title} diff --git a/app/books/iso/page.tsx b/app/books/iso/page.tsx index 6495c711..a9c9210c 100644 --- a/app/books/iso/page.tsx +++ b/app/books/iso/page.tsx @@ -68,7 +68,6 @@ export default async function IsoPage() {

- {frontPages.paragraphs.length} paragraphs @@ -85,7 +84,6 @@ export default async function IsoPage() {

- {introduction.paragraphs.length} paragraphs @@ -164,7 +162,6 @@ export default async function IsoPage() {

- {aboutAuthor.paragraphs.length} paragraphs diff --git a/app/books/kb/[volume]/page.tsx b/app/books/kb/[volume]/page.tsx index da65ae6b..521ad44b 100644 --- a/app/books/kb/[volume]/page.tsx +++ b/app/books/kb/[volume]/page.tsx @@ -72,7 +72,6 @@ export default async function KbVolumePage({

- {seg.paragraphs.length} paragraphs @@ -106,7 +105,6 @@ export default async function KbVolumePage({

- {ch.paragraphs.length} paragraphs diff --git a/app/books/lcl/[chapter]/page.tsx b/app/books/lcl/[chapter]/page.tsx index dbbd9ba4..f9e3bcbf 100644 --- a/app/books/lcl/[chapter]/page.tsx +++ b/app/books/lcl/[chapter]/page.tsx @@ -221,14 +221,7 @@ function SidebarLink({ item: LclSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs @@ -126,7 +125,6 @@ export default async function LclPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/lob/page.tsx b/app/books/lob/page.tsx index fc974ca7..8938fa7d 100644 --- a/app/books/lob/page.tsx +++ b/app/books/lob/page.tsx @@ -60,7 +60,6 @@ export default async function LobPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/mg/page.tsx b/app/books/mg/page.tsx index 8d941904..d994f145 100644 --- a/app/books/mg/page.tsx +++ b/app/books/mg/page.tsx @@ -60,7 +60,6 @@ export default async function MgPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/mm/page.tsx b/app/books/mm/page.tsx index ab754f36..861f8767 100644 --- a/app/books/mm/page.tsx +++ b/app/books/mm/page.tsx @@ -116,7 +116,6 @@ export default async function MmPage() { {introduction.title}

- {introduction.paragraphs.length} paragraphs diff --git a/app/books/mog/page.tsx b/app/books/mog/page.tsx index 0b9e7210..b34388dc 100644 --- a/app/books/mog/page.tsx +++ b/app/books/mog/page.tsx @@ -60,7 +60,6 @@ export default async function MogPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/nbs/page.tsx b/app/books/nbs/page.tsx index f3fd8fdd..794c1caa 100644 --- a/app/books/nbs/page.tsx +++ b/app/books/nbs/page.tsx @@ -116,7 +116,6 @@ export default async function NbsPage() { {introduction.title}

- {introduction.paragraphs.length} paragraphs diff --git a/app/books/nod/[chapter]/page.tsx b/app/books/nod/[chapter]/page.tsx index 90da49b2..763a089e 100644 --- a/app/books/nod/[chapter]/page.tsx +++ b/app/books/nod/[chapter]/page.tsx @@ -203,14 +203,7 @@ function SidebarLink({ item: NodSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs diff --git a/app/books/noi/page.tsx b/app/books/noi/page.tsx index 98dd1d5f..6d0a0bc8 100644 --- a/app/books/noi/page.tsx +++ b/app/books/noi/page.tsx @@ -65,7 +65,6 @@ export default async function NoiPage() {

- {frontPages.paragraphs.length} paragraphs @@ -82,7 +81,6 @@ export default async function NoiPage() {

- {preface.paragraphs.length} paragraphs @@ -141,7 +139,6 @@ export default async function NoiPage() {

- {appendixes.paragraphs.length} paragraphs diff --git a/app/books/ochkm/page.tsx b/app/books/ochkm/page.tsx index 48d3c4f9..55aaf1b8 100644 --- a/app/books/ochkm/page.tsx +++ b/app/books/ochkm/page.tsx @@ -60,7 +60,6 @@ export default async function OchkmPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/owk/page.tsx b/app/books/owk/page.tsx index c24d5625..9f16d5dd 100644 --- a/app/books/owk/page.tsx +++ b/app/books/owk/page.tsx @@ -60,7 +60,6 @@ export default async function OwkPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/poy/page.tsx b/app/books/poy/page.tsx index 44cf5cf5..264bbfa0 100644 --- a/app/books/poy/page.tsx +++ b/app/books/poy/page.tsx @@ -60,7 +60,6 @@ export default async function PoyPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/pqpa/[chapter]/page.tsx b/app/books/pqpa/[chapter]/page.tsx index 70c69f44..52ab51b2 100644 --- a/app/books/pqpa/[chapter]/page.tsx +++ b/app/books/pqpa/[chapter]/page.tsx @@ -239,14 +239,7 @@ function SidebarLink({ item: PqpaSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs @@ -151,7 +150,6 @@ export default async function PqpaPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/rv/page.tsx b/app/books/rv/page.tsx index f8218701..6be5531c 100644 --- a/app/books/rv/page.tsx +++ b/app/books/rv/page.tsx @@ -60,7 +60,6 @@ export default async function RvPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/ssr/page.tsx b/app/books/ssr/page.tsx index 338c3a97..c86c6ebb 100644 --- a/app/books/ssr/page.tsx +++ b/app/books/ssr/page.tsx @@ -64,7 +64,6 @@ export default async function SsrPage() {

- {seg.paragraphs.length} paragraphs @@ -123,7 +122,6 @@ export default async function SsrPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/sva/page.tsx b/app/books/sva/page.tsx index a776f13f..3a559dbb 100644 --- a/app/books/sva/page.tsx +++ b/app/books/sva/page.tsx @@ -64,7 +64,6 @@ export default async function SvaPage() {

- {seg.paragraphs.length} paragraphs @@ -123,7 +122,6 @@ export default async function SvaPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/tlc/[chapter]/page.tsx b/app/books/tlc/[chapter]/page.tsx index 725c759a..86de2741 100644 --- a/app/books/tlc/[chapter]/page.tsx +++ b/app/books/tlc/[chapter]/page.tsx @@ -141,6 +141,31 @@ function TlcSidebar({ const introItems = items.filter((item) => item.type === "intro-segment"); const chapterItems = items.filter((item) => item.type === "chapter"); + // Group chapters by part (if parts exist) + const hasParts = chapterItems.some((item) => item.partNumber != null); + + const partGroups: { + partNumber: number; + partTitle: string; + chapters: TlcSidebarItem[]; + }[] = []; + if (hasParts) { + const partMap = new Map< + number, + { partTitle: string; chapters: TlcSidebarItem[] } + >(); + for (const item of chapterItems) { + const pn = item.partNumber ?? 0; + const pt = item.partTitle ?? `Part ${pn}`; + if (!partMap.has(pn)) partMap.set(pn, { partTitle: pt, chapters: [] }); + partMap.get(pn)!.chapters.push(item); + } + for (const [partNumber, { partTitle, chapters }] of partMap) { + partGroups.push({ partNumber, partTitle, chapters }); + } + partGroups.sort((a, b) => a.partNumber - b.partNumber); + } + return ( ); } @@ -189,14 +231,7 @@ function SidebarLink({ item: TlcSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs diff --git a/app/books/tlk/[chapter]/page.tsx b/app/books/tlk/[chapter]/page.tsx index 17b3cafa..749aeafc 100644 --- a/app/books/tlk/[chapter]/page.tsx +++ b/app/books/tlk/[chapter]/page.tsx @@ -226,14 +226,7 @@ function SidebarLink({ item: TlkSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs @@ -126,7 +125,6 @@ export default async function TlkPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/books/tqk/[chapter]/page.tsx b/app/books/tqk/[chapter]/page.tsx index 3a6a09d0..bd48f9cf 100644 --- a/app/books/tqk/[chapter]/page.tsx +++ b/app/books/tqk/[chapter]/page.tsx @@ -226,14 +226,7 @@ function SidebarLink({ item: TqkSidebarItem; isActive: boolean; }) { - let label: string; - if (item.type === "chapter" && item.chapter != null) { - // Extract just the title portion after "Chapter N: " - const titlePart = item.label.replace(/^Chapter \d+:\s*/, ""); - label = `${item.chapter}. ${titlePart}`; - } else { - label = item.label; - } + const label = item.label; return ( - {seg.paragraphs.length} paragraphs @@ -126,7 +125,6 @@ export default async function TqkPage() {

- {seg.paragraphs.length} paragraphs diff --git a/app/essays/[slug]/page.tsx b/app/essays/[slug]/page.tsx index 8025bf48..167662e4 100644 --- a/app/essays/[slug]/page.tsx +++ b/app/essays/[slug]/page.tsx @@ -10,8 +10,7 @@ import { buttonVariants } from "@/components/ui/button"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { cn } from "@/lib/utils"; import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav"; -import { prisma } from "@/lib/db"; -import type { JsonValue } from "@prisma/client/runtime/library"; +import { bff, bffList } from "@/lib/bff"; // --------------------------------------------------------------------------- // HTML sanitisation (same pattern used across all readers) @@ -31,25 +30,6 @@ function sanitizeHtml(html: string): string { return clean; } -function normalizeParagraphs(paragraphs: string[] | JsonValue): string[] { - let result: string[]; - - if (typeof paragraphs === "string") { - try { - const parsed = JSON.parse(paragraphs); - result = Array.isArray(parsed) ? parsed : [paragraphs]; - } catch { - result = [paragraphs]; - } - } else if (Array.isArray(paragraphs)) { - result = paragraphs as string[]; - } else { - result = []; - } - - return result.map(sanitizeHtml); -} - // --------------------------------------------------------------------------- // Data fetching // --------------------------------------------------------------------------- @@ -69,7 +49,14 @@ type SidebarItem = { }; async function getEssay(slug: string): Promise { - const doc = await prisma.essay.findUnique({ where: { slug } }); + const doc = await bff<{ + slug: string; + title: string; + author: string; + year: number | null; + group: string | null; + paragraphs: string[]; + }>(`/essays/${slug}`); if (!doc) return null; return { slug: doc.slug, @@ -77,15 +64,12 @@ async function getEssay(slug: string): Promise { author: doc.author, year: doc.year, group: doc.group, - paragraphs: normalizeParagraphs(doc.paragraphs), + paragraphs: (doc.paragraphs ?? []).map(sanitizeHtml), }; } async function getEssaySidebar(): Promise { - return prisma.essay.findMany({ - orderBy: [{ group: "asc" }, { order: "asc" }], - select: { slug: true, title: true }, - }); + return bffList("/essays"); } // --------------------------------------------------------------------------- diff --git a/app/essays/page.tsx b/app/essays/page.tsx index 68cbd03a..18e155ce 100644 --- a/app/essays/page.tsx +++ b/app/essays/page.tsx @@ -4,7 +4,7 @@ import type { Metadata } from "next"; import Link from "next/link"; import { PageHeader } from "@/components/page-header"; import { buildOgMeta } from "@/lib/og"; -import { prisma } from "@/lib/db"; +import { bffList } from "@/lib/bff"; import { EssaysGrid } from "./essays-grid"; export function generateMetadata(): Metadata { @@ -17,10 +17,12 @@ export function generateMetadata(): Metadata { } async function getAllEssays() { - return prisma.essay.findMany({ - orderBy: [{ group: "asc" }, { order: "asc" }], - select: { slug: true, title: true, year: true, group: true }, - }); + return bffList<{ + slug: string; + title: string; + year: number | null; + group: string | null; + }>("/essays"); } export default async function EssaysPage() { diff --git a/app/transcriptions/[slug]/play-audio-button.tsx b/app/transcriptions/[slug]/play-audio-button.tsx index bde1b4b2..73662407 100644 --- a/app/transcriptions/[slug]/play-audio-button.tsx +++ b/app/transcriptions/[slug]/play-audio-button.tsx @@ -67,7 +67,11 @@ export function PlayAudioButton({ aria-label={isThisPlaying ? "Pause" : "Play audio"} > {isThisPlaying ? ( - + ) : ( )} diff --git a/app/transcriptions/place/[place]/page.tsx b/app/transcriptions/place/[place]/page.tsx index 3e628be7..24b37ca4 100644 --- a/app/transcriptions/place/[place]/page.tsx +++ b/app/transcriptions/place/[place]/page.tsx @@ -8,7 +8,8 @@ import { buildOgMeta } from "@/lib/og"; import { PageHeader } from "@/components/page-header"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { Clock } from "lucide-react"; +import { Clock, MapPin } from "lucide-react"; +import { PlayAudioButton } from "@/app/transcriptions/[slug]/play-audio-button"; export async function generateMetadata({ params, @@ -60,7 +61,7 @@ export default async function TranscriptionsByPlacePage({
@@ -87,6 +88,16 @@ export default async function TranscriptionsByPlacePage({ )}
+ {t.audioUrl && ( + + )} ))} diff --git a/app/transcriptions/type/[type]/type-browser.tsx b/app/transcriptions/type/[type]/type-browser.tsx index 6b9e0ac7..af3737e3 100644 --- a/app/transcriptions/type/[type]/type-browser.tsx +++ b/app/transcriptions/type/[type]/type-browser.tsx @@ -8,6 +8,7 @@ import { buttonVariants } from "@/components/ui/button"; import { ReadingSettings } from "@/components/reading-settings"; import { cn } from "@/lib/utils"; import { ChevronLeft, ChevronRight, Menu, Clock, MapPin } from "lucide-react"; +import { PlayAudioButton } from "@/app/transcriptions/[slug]/play-audio-button"; import { Drawer, DrawerClose, @@ -34,6 +35,7 @@ export type TranscriptionItem = { reference: string | null; durationMinutes: number | null; participants: string[]; + audioUrl: string | null; }; type YearGroup = { @@ -364,7 +366,7 @@ function MonthSection({
  • @@ -396,6 +398,16 @@ function MonthSection({ )}
    + {t.audioUrl && ( + + )}
  • ))} diff --git a/components/site-footer.tsx b/components/site-footer.tsx index 9564a99e..1a4fa103 100644 --- a/components/site-footer.tsx +++ b/components/site-footer.tsx @@ -5,7 +5,7 @@ export function SiteFooter() {