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() {