From 91d5d272d27b46922cf61041e4b960624ca54bfb Mon Sep 17 00:00:00 2001 From: gosangam Date: Tue, 2 Jun 2026 01:57:08 +0530 Subject: [PATCH] feat: add policy pages --- .../(auth)/forgot-password/page.tsx | 0 app/{ => (app)}/(auth)/layout.tsx | 0 app/(app)/(auth)/login/page.tsx | 65 +++ .../(auth)/reset-password/page.tsx | 0 app/{ => (app)}/(auth)/signup/page.tsx | 1 + app/{ => (app)}/about/page.tsx | 0 app/{ => (app)}/books/bbd/[chapter]/page.tsx | 0 app/{ => (app)}/books/bbd/page.tsx | 0 .../books/bg/[chapter]/[verse]/page.tsx | 2 +- app/{ => (app)}/books/bg/[chapter]/page.tsx | 0 app/{ => (app)}/books/bg/page.tsx | 0 app/{ => (app)}/books/bk/[chapter]/page.tsx | 0 app/{ => (app)}/books/bk/page.tsx | 0 app/{ => (app)}/books/books-grid.tsx | 0 .../books/bs/[chapter]/[verse]/page.tsx | 2 +- app/{ => (app)}/books/bs/[chapter]/page.tsx | 0 app/{ => (app)}/books/bs/page.tsx | 0 app/{ => (app)}/books/cbhc/[chapter]/page.tsx | 0 app/{ => (app)}/books/cbhc/page.tsx | 0 .../cc/[lila]/[chapter]/[verse]/page.tsx | 2 +- .../books/cc/[lila]/[chapter]/page.tsx | 0 app/{ => (app)}/books/cc/[lila]/page.tsx | 0 app/{ => (app)}/books/cc/page.tsx | 0 app/{ => (app)}/books/chapter-viewer.tsx | 0 app/{ => (app)}/books/ds/[chapter]/page.tsx | 0 app/{ => (app)}/books/ds/page.tsx | 0 app/{ => (app)}/books/ej/[chapter]/page.tsx | 0 app/{ => (app)}/books/ej/page.tsx | 0 app/{ => (app)}/books/ek/[chapter]/page.tsx | 0 app/{ => (app)}/books/ek/page.tsx | 0 .../books/extracted-verse-count.tsx | 0 app/{ => (app)}/books/gg/[chapter]/page.tsx | 0 app/{ => (app)}/books/gg/page.tsx | 0 app/{ => (app)}/books/hkh/[chapter]/page.tsx | 0 app/{ => (app)}/books/hkh/page.tsx | 0 app/{ => (app)}/books/iso/[mantra]/page.tsx | 0 app/{ => (app)}/books/iso/page.tsx | 0 .../books/kb/[volume]/[slug]/page.tsx | 0 app/{ => (app)}/books/kb/[volume]/page.tsx | 0 app/{ => (app)}/books/kb/page.tsx | 0 app/{ => (app)}/books/lcl/[chapter]/page.tsx | 0 app/{ => (app)}/books/lcl/page.tsx | 0 app/{ => (app)}/books/lob/[chapter]/page.tsx | 0 app/{ => (app)}/books/lob/page.tsx | 0 app/{ => (app)}/books/mg/[chapter]/page.tsx | 0 app/{ => (app)}/books/mg/page.tsx | 0 .../books/mm/[chapter]/[verse]/page.tsx | 2 +- app/{ => (app)}/books/mm/[chapter]/page.tsx | 0 app/{ => (app)}/books/mm/page.tsx | 0 app/{ => (app)}/books/mog/[chapter]/page.tsx | 0 app/{ => (app)}/books/mog/page.tsx | 0 .../books/nbs/[chapter]/[verse]/page.tsx | 2 +- app/{ => (app)}/books/nbs/[chapter]/page.tsx | 0 app/{ => (app)}/books/nbs/page.tsx | 0 app/{ => (app)}/books/nod/[chapter]/page.tsx | 0 app/{ => (app)}/books/nod/page.tsx | 0 app/{ => (app)}/books/noi/[text]/page.tsx | 0 app/{ => (app)}/books/noi/page.tsx | 0 .../books/ochkm/[chapter]/page.tsx | 0 app/{ => (app)}/books/ochkm/page.tsx | 0 app/{ => (app)}/books/owk/[chapter]/page.tsx | 0 app/{ => (app)}/books/owk/page.tsx | 0 app/{ => (app)}/books/page.tsx | 0 app/{ => (app)}/books/pk/[chapter]/page.tsx | 0 app/{ => (app)}/books/pk/page.tsx | 0 app/{ => (app)}/books/poy/[chapter]/page.tsx | 0 app/{ => (app)}/books/poy/page.tsx | 0 app/{ => (app)}/books/pqpa/[chapter]/page.tsx | 0 app/{ => (app)}/books/pqpa/page.tsx | 0 app/{ => (app)}/books/rv/[chapter]/page.tsx | 0 app/{ => (app)}/books/rv/page.tsx | 0 .../sb/[canto]/[chapter]/[verse]/page.tsx | 2 +- .../books/sb/[canto]/[chapter]/page.tsx | 0 app/{ => (app)}/books/sb/[canto]/page.tsx | 0 app/{ => (app)}/books/sb/page.tsx | 0 .../books/sb1962/[chapter]/[verse]/page.tsx | 2 +- .../books/sb1962/[chapter]/page.tsx | 0 app/{ => (app)}/books/sb1962/page.tsx | 0 app/{ => (app)}/books/ssr/[chapter]/page.tsx | 0 app/{ => (app)}/books/ssr/page.tsx | 0 app/{ => (app)}/books/sva/[chapter]/page.tsx | 0 app/{ => (app)}/books/sva/page.tsx | 0 app/{ => (app)}/books/tlc/[chapter]/page.tsx | 0 app/{ => (app)}/books/tlc/page.tsx | 0 app/{ => (app)}/books/tlk/[chapter]/page.tsx | 0 app/{ => (app)}/books/tlk/page.tsx | 0 app/{ => (app)}/books/tqk/[chapter]/page.tsx | 0 app/{ => (app)}/books/tqk/page.tsx | 0 app/{ => (app)}/books/ttp/[chapter]/page.tsx | 0 app/{ => (app)}/books/ttp/page.tsx | 0 app/{ => (app)}/books/va/[chapter]/page.tsx | 0 app/{ => (app)}/books/va/page.tsx | 0 app/{ => (app)}/c/[id]/page.tsx | 0 app/{ => (app)}/chat/page.tsx | 0 .../disciples/disciples-browser.tsx | 0 app/{ => (app)}/disciples/page.tsx | 0 app/{ => (app)}/essays/[slug]/page.tsx | 0 app/{ => (app)}/essays/essays-grid.tsx | 0 app/{ => (app)}/essays/page.tsx | 0 app/{ => (app)}/feedback/page.tsx | 0 app/{ => (app)}/glossary/[letter]/page.tsx | 0 app/{ => (app)}/glossary/glossary-client.tsx | 0 app/{ => (app)}/glossary/page.tsx | 0 .../journals/[slug]/[chapter]/page.tsx | 0 app/{ => (app)}/journals/[slug]/page.tsx | 0 app/{ => (app)}/journals/page.tsx | 0 app/(app)/layout.tsx | 40 ++ app/{ => (app)}/letters/[slug]/page.tsx | 0 .../letters/filter-year-browser.tsx | 0 app/{ => (app)}/letters/letters-browser.tsx | 0 app/{ => (app)}/letters/letters-nav.tsx | 0 .../letters/location/[name]/page.tsx | 0 app/{ => (app)}/letters/page.tsx | 0 .../letters/recipient/[name]/page.tsx | 0 app/{ => (app)}/letters/year/[year]/page.tsx | 0 .../year/[year]/year-month-browser.tsx | 0 .../magazines/[slug]/[issue]/page.tsx | 0 app/{ => (app)}/magazines/[slug]/page.tsx | 0 app/{ => (app)}/magazines/page.tsx | 0 .../other-documents/[slug]/[chapter]/page.tsx | 0 .../other-documents/[slug]/page.tsx | 0 .../other-documents/other-documents-grid.tsx | 0 app/{ => (app)}/other-documents/page.tsx | 0 app/{ => (app)}/page.tsx | 0 app/{ => (app)}/search/filters-menu.tsx | 0 app/{ => (app)}/search/page.tsx | 0 app/{ => (app)}/search/search-content.tsx | 0 app/{ => (app)}/share/[code]/not-found.tsx | 0 app/{ => (app)}/share/[code]/page.tsx | 0 .../share/[code]/redirect-client.tsx | 0 .../transcriptions/[slug]/page.tsx | 0 .../[slug]/play-audio-button.tsx | 0 app/{ => (app)}/transcriptions/page.tsx | 0 .../transcriptions/place/[place]/page.tsx | 2 +- .../transcriptions/transcriptions-browser.tsx | 0 .../transcriptions/transcriptions-nav.tsx | 0 .../transcriptions/type/[type]/page.tsx | 0 .../type/[type]/type-browser.tsx | 2 +- .../transcriptions/year/[year]/page.tsx | 0 .../year/[year]/year-browser.tsx | 2 +- .../u/[handle]/collections/page.tsx | 0 app/{ => (app)}/u/[handle]/layout.tsx | 34 +- app/{ => (app)}/u/[handle]/mentions/page.tsx | 0 app/{ => (app)}/u/[handle]/page.tsx | 0 app/{ => (app)}/u/[handle]/posts-grid.tsx | 0 app/{ => (app)}/u/[handle]/posts/page.tsx | 0 .../u/[handle]/posts/scroll-feed.tsx | 0 .../u/[handle]/profile-context.tsx | 0 app/{ => (app)}/u/[handle]/profile-og.ts | 0 app/{ => (app)}/u/me/bookmarks/page.tsx | 0 .../u/me/collections/[id]/page.tsx | 0 app/{ => (app)}/u/me/collections/page.tsx | 0 app/{ => (app)}/u/me/layout.tsx | 0 app/{ => (app)}/u/me/mentions/page.tsx | 0 app/{ => (app)}/u/me/page.tsx | 0 app/{ => (app)}/u/me/posts/page.tsx | 0 app/{ => (app)}/u/me/settings/page.tsx | 0 app/{ => (app)}/verify-email/page.tsx | 0 app/(auth)/login/page.tsx | 36 -- app/(legal)/data-deletion/page.tsx | 274 ++++++++++++ app/(legal)/layout.tsx | 20 + app/(legal)/privacy/page.tsx | 405 ++++++++++++++++++ app/(legal)/terms/page.tsx | 329 ++++++++++++++ app/layout.tsx | 32 +- components/auth/login-form.tsx | 11 +- components/auth/oauth-buttons.tsx | 100 +++++ components/auth/signup-form.tsx | 17 +- components/site-footer.tsx | 23 +- 168 files changed, 1326 insertions(+), 81 deletions(-) rename app/{ => (app)}/(auth)/forgot-password/page.tsx (100%) rename app/{ => (app)}/(auth)/layout.tsx (100%) create mode 100644 app/(app)/(auth)/login/page.tsx rename app/{ => (app)}/(auth)/reset-password/page.tsx (100%) rename app/{ => (app)}/(auth)/signup/page.tsx (96%) rename app/{ => (app)}/about/page.tsx (100%) rename app/{ => (app)}/books/bbd/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/bbd/page.tsx (100%) rename app/{ => (app)}/books/bg/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/bg/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/bg/page.tsx (100%) rename app/{ => (app)}/books/bk/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/bk/page.tsx (100%) rename app/{ => (app)}/books/books-grid.tsx (100%) rename app/{ => (app)}/books/bs/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/bs/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/bs/page.tsx (100%) rename app/{ => (app)}/books/cbhc/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/cbhc/page.tsx (100%) rename app/{ => (app)}/books/cc/[lila]/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/cc/[lila]/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/cc/[lila]/page.tsx (100%) rename app/{ => (app)}/books/cc/page.tsx (100%) rename app/{ => (app)}/books/chapter-viewer.tsx (100%) rename app/{ => (app)}/books/ds/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ds/page.tsx (100%) rename app/{ => (app)}/books/ej/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ej/page.tsx (100%) rename app/{ => (app)}/books/ek/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ek/page.tsx (100%) rename app/{ => (app)}/books/extracted-verse-count.tsx (100%) rename app/{ => (app)}/books/gg/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/gg/page.tsx (100%) rename app/{ => (app)}/books/hkh/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/hkh/page.tsx (100%) rename app/{ => (app)}/books/iso/[mantra]/page.tsx (100%) rename app/{ => (app)}/books/iso/page.tsx (100%) rename app/{ => (app)}/books/kb/[volume]/[slug]/page.tsx (100%) rename app/{ => (app)}/books/kb/[volume]/page.tsx (100%) rename app/{ => (app)}/books/kb/page.tsx (100%) rename app/{ => (app)}/books/lcl/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/lcl/page.tsx (100%) rename app/{ => (app)}/books/lob/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/lob/page.tsx (100%) rename app/{ => (app)}/books/mg/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/mg/page.tsx (100%) rename app/{ => (app)}/books/mm/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/mm/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/mm/page.tsx (100%) rename app/{ => (app)}/books/mog/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/mog/page.tsx (100%) rename app/{ => (app)}/books/nbs/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/nbs/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/nbs/page.tsx (100%) rename app/{ => (app)}/books/nod/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/nod/page.tsx (100%) rename app/{ => (app)}/books/noi/[text]/page.tsx (100%) rename app/{ => (app)}/books/noi/page.tsx (100%) rename app/{ => (app)}/books/ochkm/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ochkm/page.tsx (100%) rename app/{ => (app)}/books/owk/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/owk/page.tsx (100%) rename app/{ => (app)}/books/page.tsx (100%) rename app/{ => (app)}/books/pk/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/pk/page.tsx (100%) rename app/{ => (app)}/books/poy/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/poy/page.tsx (100%) rename app/{ => (app)}/books/pqpa/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/pqpa/page.tsx (100%) rename app/{ => (app)}/books/rv/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/rv/page.tsx (100%) rename app/{ => (app)}/books/sb/[canto]/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/sb/[canto]/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/sb/[canto]/page.tsx (100%) rename app/{ => (app)}/books/sb/page.tsx (100%) rename app/{ => (app)}/books/sb1962/[chapter]/[verse]/page.tsx (98%) rename app/{ => (app)}/books/sb1962/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/sb1962/page.tsx (100%) rename app/{ => (app)}/books/ssr/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ssr/page.tsx (100%) rename app/{ => (app)}/books/sva/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/sva/page.tsx (100%) rename app/{ => (app)}/books/tlc/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/tlc/page.tsx (100%) rename app/{ => (app)}/books/tlk/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/tlk/page.tsx (100%) rename app/{ => (app)}/books/tqk/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/tqk/page.tsx (100%) rename app/{ => (app)}/books/ttp/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/ttp/page.tsx (100%) rename app/{ => (app)}/books/va/[chapter]/page.tsx (100%) rename app/{ => (app)}/books/va/page.tsx (100%) rename app/{ => (app)}/c/[id]/page.tsx (100%) rename app/{ => (app)}/chat/page.tsx (100%) rename app/{ => (app)}/disciples/disciples-browser.tsx (100%) rename app/{ => (app)}/disciples/page.tsx (100%) rename app/{ => (app)}/essays/[slug]/page.tsx (100%) rename app/{ => (app)}/essays/essays-grid.tsx (100%) rename app/{ => (app)}/essays/page.tsx (100%) rename app/{ => (app)}/feedback/page.tsx (100%) rename app/{ => (app)}/glossary/[letter]/page.tsx (100%) rename app/{ => (app)}/glossary/glossary-client.tsx (100%) rename app/{ => (app)}/glossary/page.tsx (100%) rename app/{ => (app)}/journals/[slug]/[chapter]/page.tsx (100%) rename app/{ => (app)}/journals/[slug]/page.tsx (100%) rename app/{ => (app)}/journals/page.tsx (100%) create mode 100644 app/(app)/layout.tsx rename app/{ => (app)}/letters/[slug]/page.tsx (100%) rename app/{ => (app)}/letters/filter-year-browser.tsx (100%) rename app/{ => (app)}/letters/letters-browser.tsx (100%) rename app/{ => (app)}/letters/letters-nav.tsx (100%) rename app/{ => (app)}/letters/location/[name]/page.tsx (100%) rename app/{ => (app)}/letters/page.tsx (100%) rename app/{ => (app)}/letters/recipient/[name]/page.tsx (100%) rename app/{ => (app)}/letters/year/[year]/page.tsx (100%) rename app/{ => (app)}/letters/year/[year]/year-month-browser.tsx (100%) rename app/{ => (app)}/magazines/[slug]/[issue]/page.tsx (100%) rename app/{ => (app)}/magazines/[slug]/page.tsx (100%) rename app/{ => (app)}/magazines/page.tsx (100%) rename app/{ => (app)}/other-documents/[slug]/[chapter]/page.tsx (100%) rename app/{ => (app)}/other-documents/[slug]/page.tsx (100%) rename app/{ => (app)}/other-documents/other-documents-grid.tsx (100%) rename app/{ => (app)}/other-documents/page.tsx (100%) rename app/{ => (app)}/page.tsx (100%) rename app/{ => (app)}/search/filters-menu.tsx (100%) rename app/{ => (app)}/search/page.tsx (100%) rename app/{ => (app)}/search/search-content.tsx (100%) rename app/{ => (app)}/share/[code]/not-found.tsx (100%) rename app/{ => (app)}/share/[code]/page.tsx (100%) rename app/{ => (app)}/share/[code]/redirect-client.tsx (100%) rename app/{ => (app)}/transcriptions/[slug]/page.tsx (100%) rename app/{ => (app)}/transcriptions/[slug]/play-audio-button.tsx (100%) rename app/{ => (app)}/transcriptions/page.tsx (100%) rename app/{ => (app)}/transcriptions/place/[place]/page.tsx (97%) rename app/{ => (app)}/transcriptions/transcriptions-browser.tsx (100%) rename app/{ => (app)}/transcriptions/transcriptions-nav.tsx (100%) rename app/{ => (app)}/transcriptions/type/[type]/page.tsx (100%) rename app/{ => (app)}/transcriptions/type/[type]/type-browser.tsx (99%) rename app/{ => (app)}/transcriptions/year/[year]/page.tsx (100%) rename app/{ => (app)}/transcriptions/year/[year]/year-browser.tsx (98%) rename app/{ => (app)}/u/[handle]/collections/page.tsx (100%) rename app/{ => (app)}/u/[handle]/layout.tsx (73%) rename app/{ => (app)}/u/[handle]/mentions/page.tsx (100%) rename app/{ => (app)}/u/[handle]/page.tsx (100%) rename app/{ => (app)}/u/[handle]/posts-grid.tsx (100%) rename app/{ => (app)}/u/[handle]/posts/page.tsx (100%) rename app/{ => (app)}/u/[handle]/posts/scroll-feed.tsx (100%) rename app/{ => (app)}/u/[handle]/profile-context.tsx (100%) rename app/{ => (app)}/u/[handle]/profile-og.ts (100%) rename app/{ => (app)}/u/me/bookmarks/page.tsx (100%) rename app/{ => (app)}/u/me/collections/[id]/page.tsx (100%) rename app/{ => (app)}/u/me/collections/page.tsx (100%) rename app/{ => (app)}/u/me/layout.tsx (100%) rename app/{ => (app)}/u/me/mentions/page.tsx (100%) rename app/{ => (app)}/u/me/page.tsx (100%) rename app/{ => (app)}/u/me/posts/page.tsx (100%) rename app/{ => (app)}/u/me/settings/page.tsx (100%) rename app/{ => (app)}/verify-email/page.tsx (100%) delete mode 100644 app/(auth)/login/page.tsx create mode 100644 app/(legal)/data-deletion/page.tsx create mode 100644 app/(legal)/layout.tsx create mode 100644 app/(legal)/privacy/page.tsx create mode 100644 app/(legal)/terms/page.tsx create mode 100644 components/auth/oauth-buttons.tsx diff --git a/app/(auth)/forgot-password/page.tsx b/app/(app)/(auth)/forgot-password/page.tsx similarity index 100% rename from app/(auth)/forgot-password/page.tsx rename to app/(app)/(auth)/forgot-password/page.tsx diff --git a/app/(auth)/layout.tsx b/app/(app)/(auth)/layout.tsx similarity index 100% rename from app/(auth)/layout.tsx rename to app/(app)/(auth)/layout.tsx diff --git a/app/(app)/(auth)/login/page.tsx b/app/(app)/(auth)/login/page.tsx new file mode 100644 index 00000000..9a78f2a7 --- /dev/null +++ b/app/(app)/(auth)/login/page.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { Suspense } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { AuthCard, AuthFooterLink } from "@/components/auth/auth-card"; +import { LoginForm } from "@/components/auth/login-form"; + +function LoginContent() { + const router = useRouter(); + const params = useSearchParams(); + const next = params.get("next") ?? "/u/me"; + const oauthError = params.get("oauth_error"); + + return ( + + } + > + {oauthError ? ( +

+ {oauthErrorMessage(oauthError)} +

+ ) : null} + { + router.push(next); + router.refresh(); + }} + /> +
+ ); +} + +function oauthErrorMessage(code: string): string { + switch (code) { + case "email_required": + return "We couldn't sign you in because the provider didn't share an email. Please use the email/password form below."; + case "invalid_state": + case "missing_state": + return "Your sign-in link expired. Please try again."; + case "exchange_failed": + case "profile_failed": + return "Sign-in failed while talking to the provider. Please try again."; + case "unknown_provider": + return "That sign-in provider isn't configured. Please use email or another method."; + case "unavailable": + return "Social sign-in is temporarily unavailable. Please use email/password."; + case "server": + return "Something went wrong on our side. Please try again in a moment."; + default: + return "Sign-in failed. Please try again."; + } +} + +export default function LoginPage() { + return ( + + + + ); +} diff --git a/app/(auth)/reset-password/page.tsx b/app/(app)/(auth)/reset-password/page.tsx similarity index 100% rename from app/(auth)/reset-password/page.tsx rename to app/(app)/(auth)/reset-password/page.tsx diff --git a/app/(auth)/signup/page.tsx b/app/(app)/(auth)/signup/page.tsx similarity index 96% rename from app/(auth)/signup/page.tsx rename to app/(app)/(auth)/signup/page.tsx index 012ecec2..74820fc1 100644 --- a/app/(auth)/signup/page.tsx +++ b/app/(app)/(auth)/signup/page.tsx @@ -15,6 +15,7 @@ export default function SignUpPage() { } > { router.push("/u/me"); router.refresh(); diff --git a/app/about/page.tsx b/app/(app)/about/page.tsx similarity index 100% rename from app/about/page.tsx rename to app/(app)/about/page.tsx diff --git a/app/books/bbd/[chapter]/page.tsx b/app/(app)/books/bbd/[chapter]/page.tsx similarity index 100% rename from app/books/bbd/[chapter]/page.tsx rename to app/(app)/books/bbd/[chapter]/page.tsx diff --git a/app/books/bbd/page.tsx b/app/(app)/books/bbd/page.tsx similarity index 100% rename from app/books/bbd/page.tsx rename to app/(app)/books/bbd/page.tsx diff --git a/app/books/bg/[chapter]/[verse]/page.tsx b/app/(app)/books/bg/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/bg/[chapter]/[verse]/page.tsx rename to app/(app)/books/bg/[chapter]/[verse]/page.tsx index fdd1334c..c2cc0b61 100644 --- a/app/books/bg/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/bg/[chapter]/[verse]/page.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; import { PageHeader } from "@/components/page-header"; import { notFound } from "next/navigation"; import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/bg/[chapter]/page.tsx b/app/(app)/books/bg/[chapter]/page.tsx similarity index 100% rename from app/books/bg/[chapter]/page.tsx rename to app/(app)/books/bg/[chapter]/page.tsx diff --git a/app/books/bg/page.tsx b/app/(app)/books/bg/page.tsx similarity index 100% rename from app/books/bg/page.tsx rename to app/(app)/books/bg/page.tsx diff --git a/app/books/bk/[chapter]/page.tsx b/app/(app)/books/bk/[chapter]/page.tsx similarity index 100% rename from app/books/bk/[chapter]/page.tsx rename to app/(app)/books/bk/[chapter]/page.tsx diff --git a/app/books/bk/page.tsx b/app/(app)/books/bk/page.tsx similarity index 100% rename from app/books/bk/page.tsx rename to app/(app)/books/bk/page.tsx diff --git a/app/books/books-grid.tsx b/app/(app)/books/books-grid.tsx similarity index 100% rename from app/books/books-grid.tsx rename to app/(app)/books/books-grid.tsx diff --git a/app/books/bs/[chapter]/[verse]/page.tsx b/app/(app)/books/bs/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/bs/[chapter]/[verse]/page.tsx rename to app/(app)/books/bs/[chapter]/[verse]/page.tsx index f00415cd..c55f8681 100644 --- a/app/books/bs/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/bs/[chapter]/[verse]/page.tsx @@ -11,7 +11,7 @@ import { type VerseIndexEntry, type VerseRecord, } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/bs/[chapter]/page.tsx b/app/(app)/books/bs/[chapter]/page.tsx similarity index 100% rename from app/books/bs/[chapter]/page.tsx rename to app/(app)/books/bs/[chapter]/page.tsx diff --git a/app/books/bs/page.tsx b/app/(app)/books/bs/page.tsx similarity index 100% rename from app/books/bs/page.tsx rename to app/(app)/books/bs/page.tsx diff --git a/app/books/cbhc/[chapter]/page.tsx b/app/(app)/books/cbhc/[chapter]/page.tsx similarity index 100% rename from app/books/cbhc/[chapter]/page.tsx rename to app/(app)/books/cbhc/[chapter]/page.tsx diff --git a/app/books/cbhc/page.tsx b/app/(app)/books/cbhc/page.tsx similarity index 100% rename from app/books/cbhc/page.tsx rename to app/(app)/books/cbhc/page.tsx diff --git a/app/books/cc/[lila]/[chapter]/[verse]/page.tsx b/app/(app)/books/cc/[lila]/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/cc/[lila]/[chapter]/[verse]/page.tsx rename to app/(app)/books/cc/[lila]/[chapter]/[verse]/page.tsx index 415279dd..0c90bec6 100644 --- a/app/books/cc/[lila]/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/cc/[lila]/[chapter]/[verse]/page.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { PageHeader } from "@/components/page-header"; import { notFound } from "next/navigation"; import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/cc/[lila]/[chapter]/page.tsx b/app/(app)/books/cc/[lila]/[chapter]/page.tsx similarity index 100% rename from app/books/cc/[lila]/[chapter]/page.tsx rename to app/(app)/books/cc/[lila]/[chapter]/page.tsx diff --git a/app/books/cc/[lila]/page.tsx b/app/(app)/books/cc/[lila]/page.tsx similarity index 100% rename from app/books/cc/[lila]/page.tsx rename to app/(app)/books/cc/[lila]/page.tsx diff --git a/app/books/cc/page.tsx b/app/(app)/books/cc/page.tsx similarity index 100% rename from app/books/cc/page.tsx rename to app/(app)/books/cc/page.tsx diff --git a/app/books/chapter-viewer.tsx b/app/(app)/books/chapter-viewer.tsx similarity index 100% rename from app/books/chapter-viewer.tsx rename to app/(app)/books/chapter-viewer.tsx diff --git a/app/books/ds/[chapter]/page.tsx b/app/(app)/books/ds/[chapter]/page.tsx similarity index 100% rename from app/books/ds/[chapter]/page.tsx rename to app/(app)/books/ds/[chapter]/page.tsx diff --git a/app/books/ds/page.tsx b/app/(app)/books/ds/page.tsx similarity index 100% rename from app/books/ds/page.tsx rename to app/(app)/books/ds/page.tsx diff --git a/app/books/ej/[chapter]/page.tsx b/app/(app)/books/ej/[chapter]/page.tsx similarity index 100% rename from app/books/ej/[chapter]/page.tsx rename to app/(app)/books/ej/[chapter]/page.tsx diff --git a/app/books/ej/page.tsx b/app/(app)/books/ej/page.tsx similarity index 100% rename from app/books/ej/page.tsx rename to app/(app)/books/ej/page.tsx diff --git a/app/books/ek/[chapter]/page.tsx b/app/(app)/books/ek/[chapter]/page.tsx similarity index 100% rename from app/books/ek/[chapter]/page.tsx rename to app/(app)/books/ek/[chapter]/page.tsx diff --git a/app/books/ek/page.tsx b/app/(app)/books/ek/page.tsx similarity index 100% rename from app/books/ek/page.tsx rename to app/(app)/books/ek/page.tsx diff --git a/app/books/extracted-verse-count.tsx b/app/(app)/books/extracted-verse-count.tsx similarity index 100% rename from app/books/extracted-verse-count.tsx rename to app/(app)/books/extracted-verse-count.tsx diff --git a/app/books/gg/[chapter]/page.tsx b/app/(app)/books/gg/[chapter]/page.tsx similarity index 100% rename from app/books/gg/[chapter]/page.tsx rename to app/(app)/books/gg/[chapter]/page.tsx diff --git a/app/books/gg/page.tsx b/app/(app)/books/gg/page.tsx similarity index 100% rename from app/books/gg/page.tsx rename to app/(app)/books/gg/page.tsx diff --git a/app/books/hkh/[chapter]/page.tsx b/app/(app)/books/hkh/[chapter]/page.tsx similarity index 100% rename from app/books/hkh/[chapter]/page.tsx rename to app/(app)/books/hkh/[chapter]/page.tsx diff --git a/app/books/hkh/page.tsx b/app/(app)/books/hkh/page.tsx similarity index 100% rename from app/books/hkh/page.tsx rename to app/(app)/books/hkh/page.tsx diff --git a/app/books/iso/[mantra]/page.tsx b/app/(app)/books/iso/[mantra]/page.tsx similarity index 100% rename from app/books/iso/[mantra]/page.tsx rename to app/(app)/books/iso/[mantra]/page.tsx diff --git a/app/books/iso/page.tsx b/app/(app)/books/iso/page.tsx similarity index 100% rename from app/books/iso/page.tsx rename to app/(app)/books/iso/page.tsx diff --git a/app/books/kb/[volume]/[slug]/page.tsx b/app/(app)/books/kb/[volume]/[slug]/page.tsx similarity index 100% rename from app/books/kb/[volume]/[slug]/page.tsx rename to app/(app)/books/kb/[volume]/[slug]/page.tsx diff --git a/app/books/kb/[volume]/page.tsx b/app/(app)/books/kb/[volume]/page.tsx similarity index 100% rename from app/books/kb/[volume]/page.tsx rename to app/(app)/books/kb/[volume]/page.tsx diff --git a/app/books/kb/page.tsx b/app/(app)/books/kb/page.tsx similarity index 100% rename from app/books/kb/page.tsx rename to app/(app)/books/kb/page.tsx diff --git a/app/books/lcl/[chapter]/page.tsx b/app/(app)/books/lcl/[chapter]/page.tsx similarity index 100% rename from app/books/lcl/[chapter]/page.tsx rename to app/(app)/books/lcl/[chapter]/page.tsx diff --git a/app/books/lcl/page.tsx b/app/(app)/books/lcl/page.tsx similarity index 100% rename from app/books/lcl/page.tsx rename to app/(app)/books/lcl/page.tsx diff --git a/app/books/lob/[chapter]/page.tsx b/app/(app)/books/lob/[chapter]/page.tsx similarity index 100% rename from app/books/lob/[chapter]/page.tsx rename to app/(app)/books/lob/[chapter]/page.tsx diff --git a/app/books/lob/page.tsx b/app/(app)/books/lob/page.tsx similarity index 100% rename from app/books/lob/page.tsx rename to app/(app)/books/lob/page.tsx diff --git a/app/books/mg/[chapter]/page.tsx b/app/(app)/books/mg/[chapter]/page.tsx similarity index 100% rename from app/books/mg/[chapter]/page.tsx rename to app/(app)/books/mg/[chapter]/page.tsx diff --git a/app/books/mg/page.tsx b/app/(app)/books/mg/page.tsx similarity index 100% rename from app/books/mg/page.tsx rename to app/(app)/books/mg/page.tsx diff --git a/app/books/mm/[chapter]/[verse]/page.tsx b/app/(app)/books/mm/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/mm/[chapter]/[verse]/page.tsx rename to app/(app)/books/mm/[chapter]/[verse]/page.tsx index 92d2b4df..b12106cd 100644 --- a/app/books/mm/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/mm/[chapter]/[verse]/page.tsx @@ -10,7 +10,7 @@ import { type VerseIndexEntry, type VerseRecord, } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import type { Metadata } from "next"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/mm/[chapter]/page.tsx b/app/(app)/books/mm/[chapter]/page.tsx similarity index 100% rename from app/books/mm/[chapter]/page.tsx rename to app/(app)/books/mm/[chapter]/page.tsx diff --git a/app/books/mm/page.tsx b/app/(app)/books/mm/page.tsx similarity index 100% rename from app/books/mm/page.tsx rename to app/(app)/books/mm/page.tsx diff --git a/app/books/mog/[chapter]/page.tsx b/app/(app)/books/mog/[chapter]/page.tsx similarity index 100% rename from app/books/mog/[chapter]/page.tsx rename to app/(app)/books/mog/[chapter]/page.tsx diff --git a/app/books/mog/page.tsx b/app/(app)/books/mog/page.tsx similarity index 100% rename from app/books/mog/page.tsx rename to app/(app)/books/mog/page.tsx diff --git a/app/books/nbs/[chapter]/[verse]/page.tsx b/app/(app)/books/nbs/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/nbs/[chapter]/[verse]/page.tsx rename to app/(app)/books/nbs/[chapter]/[verse]/page.tsx index b80b691c..5a5f1054 100644 --- a/app/books/nbs/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/nbs/[chapter]/[verse]/page.tsx @@ -14,7 +14,7 @@ import { type VerseRecord, } from "@/lib/api"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; type NbsMeta = { diff --git a/app/books/nbs/[chapter]/page.tsx b/app/(app)/books/nbs/[chapter]/page.tsx similarity index 100% rename from app/books/nbs/[chapter]/page.tsx rename to app/(app)/books/nbs/[chapter]/page.tsx diff --git a/app/books/nbs/page.tsx b/app/(app)/books/nbs/page.tsx similarity index 100% rename from app/books/nbs/page.tsx rename to app/(app)/books/nbs/page.tsx diff --git a/app/books/nod/[chapter]/page.tsx b/app/(app)/books/nod/[chapter]/page.tsx similarity index 100% rename from app/books/nod/[chapter]/page.tsx rename to app/(app)/books/nod/[chapter]/page.tsx diff --git a/app/books/nod/page.tsx b/app/(app)/books/nod/page.tsx similarity index 100% rename from app/books/nod/page.tsx rename to app/(app)/books/nod/page.tsx diff --git a/app/books/noi/[text]/page.tsx b/app/(app)/books/noi/[text]/page.tsx similarity index 100% rename from app/books/noi/[text]/page.tsx rename to app/(app)/books/noi/[text]/page.tsx diff --git a/app/books/noi/page.tsx b/app/(app)/books/noi/page.tsx similarity index 100% rename from app/books/noi/page.tsx rename to app/(app)/books/noi/page.tsx diff --git a/app/books/ochkm/[chapter]/page.tsx b/app/(app)/books/ochkm/[chapter]/page.tsx similarity index 100% rename from app/books/ochkm/[chapter]/page.tsx rename to app/(app)/books/ochkm/[chapter]/page.tsx diff --git a/app/books/ochkm/page.tsx b/app/(app)/books/ochkm/page.tsx similarity index 100% rename from app/books/ochkm/page.tsx rename to app/(app)/books/ochkm/page.tsx diff --git a/app/books/owk/[chapter]/page.tsx b/app/(app)/books/owk/[chapter]/page.tsx similarity index 100% rename from app/books/owk/[chapter]/page.tsx rename to app/(app)/books/owk/[chapter]/page.tsx diff --git a/app/books/owk/page.tsx b/app/(app)/books/owk/page.tsx similarity index 100% rename from app/books/owk/page.tsx rename to app/(app)/books/owk/page.tsx diff --git a/app/books/page.tsx b/app/(app)/books/page.tsx similarity index 100% rename from app/books/page.tsx rename to app/(app)/books/page.tsx diff --git a/app/books/pk/[chapter]/page.tsx b/app/(app)/books/pk/[chapter]/page.tsx similarity index 100% rename from app/books/pk/[chapter]/page.tsx rename to app/(app)/books/pk/[chapter]/page.tsx diff --git a/app/books/pk/page.tsx b/app/(app)/books/pk/page.tsx similarity index 100% rename from app/books/pk/page.tsx rename to app/(app)/books/pk/page.tsx diff --git a/app/books/poy/[chapter]/page.tsx b/app/(app)/books/poy/[chapter]/page.tsx similarity index 100% rename from app/books/poy/[chapter]/page.tsx rename to app/(app)/books/poy/[chapter]/page.tsx diff --git a/app/books/poy/page.tsx b/app/(app)/books/poy/page.tsx similarity index 100% rename from app/books/poy/page.tsx rename to app/(app)/books/poy/page.tsx diff --git a/app/books/pqpa/[chapter]/page.tsx b/app/(app)/books/pqpa/[chapter]/page.tsx similarity index 100% rename from app/books/pqpa/[chapter]/page.tsx rename to app/(app)/books/pqpa/[chapter]/page.tsx diff --git a/app/books/pqpa/page.tsx b/app/(app)/books/pqpa/page.tsx similarity index 100% rename from app/books/pqpa/page.tsx rename to app/(app)/books/pqpa/page.tsx diff --git a/app/books/rv/[chapter]/page.tsx b/app/(app)/books/rv/[chapter]/page.tsx similarity index 100% rename from app/books/rv/[chapter]/page.tsx rename to app/(app)/books/rv/[chapter]/page.tsx diff --git a/app/books/rv/page.tsx b/app/(app)/books/rv/page.tsx similarity index 100% rename from app/books/rv/page.tsx rename to app/(app)/books/rv/page.tsx diff --git a/app/books/sb/[canto]/[chapter]/[verse]/page.tsx b/app/(app)/books/sb/[canto]/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/sb/[canto]/[chapter]/[verse]/page.tsx rename to app/(app)/books/sb/[canto]/[chapter]/[verse]/page.tsx index 1b909a38..8b3b87ee 100644 --- a/app/books/sb/[canto]/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/sb/[canto]/[chapter]/[verse]/page.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { PageHeader } from "@/components/page-header"; import { notFound } from "next/navigation"; import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/sb/[canto]/[chapter]/page.tsx b/app/(app)/books/sb/[canto]/[chapter]/page.tsx similarity index 100% rename from app/books/sb/[canto]/[chapter]/page.tsx rename to app/(app)/books/sb/[canto]/[chapter]/page.tsx diff --git a/app/books/sb/[canto]/page.tsx b/app/(app)/books/sb/[canto]/page.tsx similarity index 100% rename from app/books/sb/[canto]/page.tsx rename to app/(app)/books/sb/[canto]/page.tsx diff --git a/app/books/sb/page.tsx b/app/(app)/books/sb/page.tsx similarity index 100% rename from app/books/sb/page.tsx rename to app/(app)/books/sb/page.tsx diff --git a/app/books/sb1962/[chapter]/[verse]/page.tsx b/app/(app)/books/sb1962/[chapter]/[verse]/page.tsx similarity index 98% rename from app/books/sb1962/[chapter]/[verse]/page.tsx rename to app/(app)/books/sb1962/[chapter]/[verse]/page.tsx index 8e06af9a..c9e05fc8 100644 --- a/app/books/sb1962/[chapter]/[verse]/page.tsx +++ b/app/(app)/books/sb1962/[chapter]/[verse]/page.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; import { PageHeader } from "@/components/page-header"; import { notFound } from "next/navigation"; import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api"; -import { ChapterViewer } from "@/app/books/chapter-viewer"; +import { ChapterViewer } from "@/app/(app)/books/chapter-viewer"; import type { MobileNavGroup } from "@/components/mobile-nav"; import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; diff --git a/app/books/sb1962/[chapter]/page.tsx b/app/(app)/books/sb1962/[chapter]/page.tsx similarity index 100% rename from app/books/sb1962/[chapter]/page.tsx rename to app/(app)/books/sb1962/[chapter]/page.tsx diff --git a/app/books/sb1962/page.tsx b/app/(app)/books/sb1962/page.tsx similarity index 100% rename from app/books/sb1962/page.tsx rename to app/(app)/books/sb1962/page.tsx diff --git a/app/books/ssr/[chapter]/page.tsx b/app/(app)/books/ssr/[chapter]/page.tsx similarity index 100% rename from app/books/ssr/[chapter]/page.tsx rename to app/(app)/books/ssr/[chapter]/page.tsx diff --git a/app/books/ssr/page.tsx b/app/(app)/books/ssr/page.tsx similarity index 100% rename from app/books/ssr/page.tsx rename to app/(app)/books/ssr/page.tsx diff --git a/app/books/sva/[chapter]/page.tsx b/app/(app)/books/sva/[chapter]/page.tsx similarity index 100% rename from app/books/sva/[chapter]/page.tsx rename to app/(app)/books/sva/[chapter]/page.tsx diff --git a/app/books/sva/page.tsx b/app/(app)/books/sva/page.tsx similarity index 100% rename from app/books/sva/page.tsx rename to app/(app)/books/sva/page.tsx diff --git a/app/books/tlc/[chapter]/page.tsx b/app/(app)/books/tlc/[chapter]/page.tsx similarity index 100% rename from app/books/tlc/[chapter]/page.tsx rename to app/(app)/books/tlc/[chapter]/page.tsx diff --git a/app/books/tlc/page.tsx b/app/(app)/books/tlc/page.tsx similarity index 100% rename from app/books/tlc/page.tsx rename to app/(app)/books/tlc/page.tsx diff --git a/app/books/tlk/[chapter]/page.tsx b/app/(app)/books/tlk/[chapter]/page.tsx similarity index 100% rename from app/books/tlk/[chapter]/page.tsx rename to app/(app)/books/tlk/[chapter]/page.tsx diff --git a/app/books/tlk/page.tsx b/app/(app)/books/tlk/page.tsx similarity index 100% rename from app/books/tlk/page.tsx rename to app/(app)/books/tlk/page.tsx diff --git a/app/books/tqk/[chapter]/page.tsx b/app/(app)/books/tqk/[chapter]/page.tsx similarity index 100% rename from app/books/tqk/[chapter]/page.tsx rename to app/(app)/books/tqk/[chapter]/page.tsx diff --git a/app/books/tqk/page.tsx b/app/(app)/books/tqk/page.tsx similarity index 100% rename from app/books/tqk/page.tsx rename to app/(app)/books/tqk/page.tsx diff --git a/app/books/ttp/[chapter]/page.tsx b/app/(app)/books/ttp/[chapter]/page.tsx similarity index 100% rename from app/books/ttp/[chapter]/page.tsx rename to app/(app)/books/ttp/[chapter]/page.tsx diff --git a/app/books/ttp/page.tsx b/app/(app)/books/ttp/page.tsx similarity index 100% rename from app/books/ttp/page.tsx rename to app/(app)/books/ttp/page.tsx diff --git a/app/books/va/[chapter]/page.tsx b/app/(app)/books/va/[chapter]/page.tsx similarity index 100% rename from app/books/va/[chapter]/page.tsx rename to app/(app)/books/va/[chapter]/page.tsx diff --git a/app/books/va/page.tsx b/app/(app)/books/va/page.tsx similarity index 100% rename from app/books/va/page.tsx rename to app/(app)/books/va/page.tsx diff --git a/app/c/[id]/page.tsx b/app/(app)/c/[id]/page.tsx similarity index 100% rename from app/c/[id]/page.tsx rename to app/(app)/c/[id]/page.tsx diff --git a/app/chat/page.tsx b/app/(app)/chat/page.tsx similarity index 100% rename from app/chat/page.tsx rename to app/(app)/chat/page.tsx diff --git a/app/disciples/disciples-browser.tsx b/app/(app)/disciples/disciples-browser.tsx similarity index 100% rename from app/disciples/disciples-browser.tsx rename to app/(app)/disciples/disciples-browser.tsx diff --git a/app/disciples/page.tsx b/app/(app)/disciples/page.tsx similarity index 100% rename from app/disciples/page.tsx rename to app/(app)/disciples/page.tsx diff --git a/app/essays/[slug]/page.tsx b/app/(app)/essays/[slug]/page.tsx similarity index 100% rename from app/essays/[slug]/page.tsx rename to app/(app)/essays/[slug]/page.tsx diff --git a/app/essays/essays-grid.tsx b/app/(app)/essays/essays-grid.tsx similarity index 100% rename from app/essays/essays-grid.tsx rename to app/(app)/essays/essays-grid.tsx diff --git a/app/essays/page.tsx b/app/(app)/essays/page.tsx similarity index 100% rename from app/essays/page.tsx rename to app/(app)/essays/page.tsx diff --git a/app/feedback/page.tsx b/app/(app)/feedback/page.tsx similarity index 100% rename from app/feedback/page.tsx rename to app/(app)/feedback/page.tsx diff --git a/app/glossary/[letter]/page.tsx b/app/(app)/glossary/[letter]/page.tsx similarity index 100% rename from app/glossary/[letter]/page.tsx rename to app/(app)/glossary/[letter]/page.tsx diff --git a/app/glossary/glossary-client.tsx b/app/(app)/glossary/glossary-client.tsx similarity index 100% rename from app/glossary/glossary-client.tsx rename to app/(app)/glossary/glossary-client.tsx diff --git a/app/glossary/page.tsx b/app/(app)/glossary/page.tsx similarity index 100% rename from app/glossary/page.tsx rename to app/(app)/glossary/page.tsx diff --git a/app/journals/[slug]/[chapter]/page.tsx b/app/(app)/journals/[slug]/[chapter]/page.tsx similarity index 100% rename from app/journals/[slug]/[chapter]/page.tsx rename to app/(app)/journals/[slug]/[chapter]/page.tsx diff --git a/app/journals/[slug]/page.tsx b/app/(app)/journals/[slug]/page.tsx similarity index 100% rename from app/journals/[slug]/page.tsx rename to app/(app)/journals/[slug]/page.tsx diff --git a/app/journals/page.tsx b/app/(app)/journals/page.tsx similarity index 100% rename from app/journals/page.tsx rename to app/(app)/journals/page.tsx diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx new file mode 100644 index 00000000..eea8edd3 --- /dev/null +++ b/app/(app)/layout.tsx @@ -0,0 +1,40 @@ +import { Suspense } from "react"; +import { SiteHeader } from "@/components/site-header"; +import { SiteSidebar } from "@/components/site-sidebar"; +import { SiteBottomNav } from "@/components/site-bottom-nav"; +import { VerifyEmailBanner } from "@/components/auth/verify-email-banner"; +import { TextSelectionToolbar } from "@/components/text-selection-toolbar"; +import { TextHighlighter } from "@/components/text-highlighter"; +import { PageBookmarks } from "@/components/social/page-bookmarks"; + +/** + * Default app layout — the reading-app chrome that wraps the home page, all + * the book / letter / transcription / etc. routes, the user profile, and + * the auth pages. + * + * Sibling groups (e.g. `(legal)/`) opt out of this chrome by living in their + * own route group with their own layout. Everything in the root layout + * (providers, fonts, toaster, floating audio player) still wraps this layer. + */ +export default function AppLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + <> + + +
+ + {children} +
+ + + + + + + + ); +} diff --git a/app/letters/[slug]/page.tsx b/app/(app)/letters/[slug]/page.tsx similarity index 100% rename from app/letters/[slug]/page.tsx rename to app/(app)/letters/[slug]/page.tsx diff --git a/app/letters/filter-year-browser.tsx b/app/(app)/letters/filter-year-browser.tsx similarity index 100% rename from app/letters/filter-year-browser.tsx rename to app/(app)/letters/filter-year-browser.tsx diff --git a/app/letters/letters-browser.tsx b/app/(app)/letters/letters-browser.tsx similarity index 100% rename from app/letters/letters-browser.tsx rename to app/(app)/letters/letters-browser.tsx diff --git a/app/letters/letters-nav.tsx b/app/(app)/letters/letters-nav.tsx similarity index 100% rename from app/letters/letters-nav.tsx rename to app/(app)/letters/letters-nav.tsx diff --git a/app/letters/location/[name]/page.tsx b/app/(app)/letters/location/[name]/page.tsx similarity index 100% rename from app/letters/location/[name]/page.tsx rename to app/(app)/letters/location/[name]/page.tsx diff --git a/app/letters/page.tsx b/app/(app)/letters/page.tsx similarity index 100% rename from app/letters/page.tsx rename to app/(app)/letters/page.tsx diff --git a/app/letters/recipient/[name]/page.tsx b/app/(app)/letters/recipient/[name]/page.tsx similarity index 100% rename from app/letters/recipient/[name]/page.tsx rename to app/(app)/letters/recipient/[name]/page.tsx diff --git a/app/letters/year/[year]/page.tsx b/app/(app)/letters/year/[year]/page.tsx similarity index 100% rename from app/letters/year/[year]/page.tsx rename to app/(app)/letters/year/[year]/page.tsx diff --git a/app/letters/year/[year]/year-month-browser.tsx b/app/(app)/letters/year/[year]/year-month-browser.tsx similarity index 100% rename from app/letters/year/[year]/year-month-browser.tsx rename to app/(app)/letters/year/[year]/year-month-browser.tsx diff --git a/app/magazines/[slug]/[issue]/page.tsx b/app/(app)/magazines/[slug]/[issue]/page.tsx similarity index 100% rename from app/magazines/[slug]/[issue]/page.tsx rename to app/(app)/magazines/[slug]/[issue]/page.tsx diff --git a/app/magazines/[slug]/page.tsx b/app/(app)/magazines/[slug]/page.tsx similarity index 100% rename from app/magazines/[slug]/page.tsx rename to app/(app)/magazines/[slug]/page.tsx diff --git a/app/magazines/page.tsx b/app/(app)/magazines/page.tsx similarity index 100% rename from app/magazines/page.tsx rename to app/(app)/magazines/page.tsx diff --git a/app/other-documents/[slug]/[chapter]/page.tsx b/app/(app)/other-documents/[slug]/[chapter]/page.tsx similarity index 100% rename from app/other-documents/[slug]/[chapter]/page.tsx rename to app/(app)/other-documents/[slug]/[chapter]/page.tsx diff --git a/app/other-documents/[slug]/page.tsx b/app/(app)/other-documents/[slug]/page.tsx similarity index 100% rename from app/other-documents/[slug]/page.tsx rename to app/(app)/other-documents/[slug]/page.tsx diff --git a/app/other-documents/other-documents-grid.tsx b/app/(app)/other-documents/other-documents-grid.tsx similarity index 100% rename from app/other-documents/other-documents-grid.tsx rename to app/(app)/other-documents/other-documents-grid.tsx diff --git a/app/other-documents/page.tsx b/app/(app)/other-documents/page.tsx similarity index 100% rename from app/other-documents/page.tsx rename to app/(app)/other-documents/page.tsx diff --git a/app/page.tsx b/app/(app)/page.tsx similarity index 100% rename from app/page.tsx rename to app/(app)/page.tsx diff --git a/app/search/filters-menu.tsx b/app/(app)/search/filters-menu.tsx similarity index 100% rename from app/search/filters-menu.tsx rename to app/(app)/search/filters-menu.tsx diff --git a/app/search/page.tsx b/app/(app)/search/page.tsx similarity index 100% rename from app/search/page.tsx rename to app/(app)/search/page.tsx diff --git a/app/search/search-content.tsx b/app/(app)/search/search-content.tsx similarity index 100% rename from app/search/search-content.tsx rename to app/(app)/search/search-content.tsx diff --git a/app/share/[code]/not-found.tsx b/app/(app)/share/[code]/not-found.tsx similarity index 100% rename from app/share/[code]/not-found.tsx rename to app/(app)/share/[code]/not-found.tsx diff --git a/app/share/[code]/page.tsx b/app/(app)/share/[code]/page.tsx similarity index 100% rename from app/share/[code]/page.tsx rename to app/(app)/share/[code]/page.tsx diff --git a/app/share/[code]/redirect-client.tsx b/app/(app)/share/[code]/redirect-client.tsx similarity index 100% rename from app/share/[code]/redirect-client.tsx rename to app/(app)/share/[code]/redirect-client.tsx diff --git a/app/transcriptions/[slug]/page.tsx b/app/(app)/transcriptions/[slug]/page.tsx similarity index 100% rename from app/transcriptions/[slug]/page.tsx rename to app/(app)/transcriptions/[slug]/page.tsx diff --git a/app/transcriptions/[slug]/play-audio-button.tsx b/app/(app)/transcriptions/[slug]/play-audio-button.tsx similarity index 100% rename from app/transcriptions/[slug]/play-audio-button.tsx rename to app/(app)/transcriptions/[slug]/play-audio-button.tsx diff --git a/app/transcriptions/page.tsx b/app/(app)/transcriptions/page.tsx similarity index 100% rename from app/transcriptions/page.tsx rename to app/(app)/transcriptions/page.tsx diff --git a/app/transcriptions/place/[place]/page.tsx b/app/(app)/transcriptions/place/[place]/page.tsx similarity index 97% rename from app/transcriptions/place/[place]/page.tsx rename to app/(app)/transcriptions/place/[place]/page.tsx index 24b37ca4..93136e37 100644 --- a/app/transcriptions/place/[place]/page.tsx +++ b/app/(app)/transcriptions/place/[place]/page.tsx @@ -9,7 +9,7 @@ import { PageHeader } from "@/components/page-header"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Clock, MapPin } from "lucide-react"; -import { PlayAudioButton } from "@/app/transcriptions/[slug]/play-audio-button"; +import { PlayAudioButton } from "@/app/(app)/transcriptions/[slug]/play-audio-button"; export async function generateMetadata({ params, diff --git a/app/transcriptions/transcriptions-browser.tsx b/app/(app)/transcriptions/transcriptions-browser.tsx similarity index 100% rename from app/transcriptions/transcriptions-browser.tsx rename to app/(app)/transcriptions/transcriptions-browser.tsx diff --git a/app/transcriptions/transcriptions-nav.tsx b/app/(app)/transcriptions/transcriptions-nav.tsx similarity index 100% rename from app/transcriptions/transcriptions-nav.tsx rename to app/(app)/transcriptions/transcriptions-nav.tsx diff --git a/app/transcriptions/type/[type]/page.tsx b/app/(app)/transcriptions/type/[type]/page.tsx similarity index 100% rename from app/transcriptions/type/[type]/page.tsx rename to app/(app)/transcriptions/type/[type]/page.tsx diff --git a/app/transcriptions/type/[type]/type-browser.tsx b/app/(app)/transcriptions/type/[type]/type-browser.tsx similarity index 99% rename from app/transcriptions/type/[type]/type-browser.tsx rename to app/(app)/transcriptions/type/[type]/type-browser.tsx index 39e303df..08aef431 100644 --- a/app/transcriptions/type/[type]/type-browser.tsx +++ b/app/(app)/transcriptions/type/[type]/type-browser.tsx @@ -7,7 +7,7 @@ import { Badge } from "@/components/ui/badge"; import { buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { ChevronLeft, ChevronRight, Menu, Clock, MapPin } from "lucide-react"; -import { PlayAudioButton } from "@/app/transcriptions/[slug]/play-audio-button"; +import { PlayAudioButton } from "@/app/(app)/transcriptions/[slug]/play-audio-button"; import { Drawer, DrawerClose, diff --git a/app/transcriptions/year/[year]/page.tsx b/app/(app)/transcriptions/year/[year]/page.tsx similarity index 100% rename from app/transcriptions/year/[year]/page.tsx rename to app/(app)/transcriptions/year/[year]/page.tsx diff --git a/app/transcriptions/year/[year]/year-browser.tsx b/app/(app)/transcriptions/year/[year]/year-browser.tsx similarity index 98% rename from app/transcriptions/year/[year]/year-browser.tsx rename to app/(app)/transcriptions/year/[year]/year-browser.tsx index c1137649..efbdcf14 100644 --- a/app/transcriptions/year/[year]/year-browser.tsx +++ b/app/(app)/transcriptions/year/[year]/year-browser.tsx @@ -7,7 +7,7 @@ import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; import { ChevronRight, Clock, MapPin } from "lucide-react"; -import { PlayAudioButton } from "@/app/transcriptions/[slug]/play-audio-button"; +import { PlayAudioButton } from "@/app/(app)/transcriptions/[slug]/play-audio-button"; type TranscriptionItem = { slug: string; diff --git a/app/u/[handle]/collections/page.tsx b/app/(app)/u/[handle]/collections/page.tsx similarity index 100% rename from app/u/[handle]/collections/page.tsx rename to app/(app)/u/[handle]/collections/page.tsx diff --git a/app/u/[handle]/layout.tsx b/app/(app)/u/[handle]/layout.tsx similarity index 73% rename from app/u/[handle]/layout.tsx rename to app/(app)/u/[handle]/layout.tsx index d98274cc..66450320 100644 --- a/app/u/[handle]/layout.tsx +++ b/app/(app)/u/[handle]/layout.tsx @@ -36,9 +36,15 @@ export default function PublicProfileLayout(props: { const router = useRouter(); const pathname = usePathname(); const { user } = useAuth(); - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [missing, setMissing] = useState(false); + + // Store the request handle alongside the result. The view derives + // `loading` from "do we have a result whose handle matches the current + // route?" — that lets us skip a synchronous setLoading(true) inside the + // fetch effect (which would trigger a cascading render on every mount). + type Result = + | { handle: string; data: PublicProfile; missing: false } + | { handle: string; data: null; missing: true }; + const [result, setResult] = useState(null); const isOwn = !!user && user.handle.toLowerCase() === handle.toLowerCase(); @@ -54,21 +60,33 @@ export default function PublicProfileLayout(props: { useEffect(() => { if (isOwn) return; let cancelled = false; - setLoading(true); profile .get(handle) .then((p) => { - if (!cancelled) setData(p); + if (!cancelled) setResult({ handle, data: p, missing: false }); }) .catch((err) => { - if (err instanceof SocialError && err.status === 404) setMissing(true); - }) - .finally(() => !cancelled && setLoading(false)); + if ( + !cancelled && + err instanceof SocialError && + err.status === 404 + ) { + setResult({ handle, data: null, missing: true }); + } + }); return () => { cancelled = true; }; }, [handle, isOwn]); + // A result for a previous handle is treated as "still loading the new + // one" — so when the route changes we automatically show the spinner + // again without any setState during render or in an effect body. + const fresh = result?.handle === handle ? result : null; + const missing = fresh?.missing === true; + const data = fresh && fresh.missing === false ? fresh.data : null; + const loading = fresh === null; + if (missing) notFound(); if (isOwn) return null; diff --git a/app/u/[handle]/mentions/page.tsx b/app/(app)/u/[handle]/mentions/page.tsx similarity index 100% rename from app/u/[handle]/mentions/page.tsx rename to app/(app)/u/[handle]/mentions/page.tsx diff --git a/app/u/[handle]/page.tsx b/app/(app)/u/[handle]/page.tsx similarity index 100% rename from app/u/[handle]/page.tsx rename to app/(app)/u/[handle]/page.tsx diff --git a/app/u/[handle]/posts-grid.tsx b/app/(app)/u/[handle]/posts-grid.tsx similarity index 100% rename from app/u/[handle]/posts-grid.tsx rename to app/(app)/u/[handle]/posts-grid.tsx diff --git a/app/u/[handle]/posts/page.tsx b/app/(app)/u/[handle]/posts/page.tsx similarity index 100% rename from app/u/[handle]/posts/page.tsx rename to app/(app)/u/[handle]/posts/page.tsx diff --git a/app/u/[handle]/posts/scroll-feed.tsx b/app/(app)/u/[handle]/posts/scroll-feed.tsx similarity index 100% rename from app/u/[handle]/posts/scroll-feed.tsx rename to app/(app)/u/[handle]/posts/scroll-feed.tsx diff --git a/app/u/[handle]/profile-context.tsx b/app/(app)/u/[handle]/profile-context.tsx similarity index 100% rename from app/u/[handle]/profile-context.tsx rename to app/(app)/u/[handle]/profile-context.tsx diff --git a/app/u/[handle]/profile-og.ts b/app/(app)/u/[handle]/profile-og.ts similarity index 100% rename from app/u/[handle]/profile-og.ts rename to app/(app)/u/[handle]/profile-og.ts diff --git a/app/u/me/bookmarks/page.tsx b/app/(app)/u/me/bookmarks/page.tsx similarity index 100% rename from app/u/me/bookmarks/page.tsx rename to app/(app)/u/me/bookmarks/page.tsx diff --git a/app/u/me/collections/[id]/page.tsx b/app/(app)/u/me/collections/[id]/page.tsx similarity index 100% rename from app/u/me/collections/[id]/page.tsx rename to app/(app)/u/me/collections/[id]/page.tsx diff --git a/app/u/me/collections/page.tsx b/app/(app)/u/me/collections/page.tsx similarity index 100% rename from app/u/me/collections/page.tsx rename to app/(app)/u/me/collections/page.tsx diff --git a/app/u/me/layout.tsx b/app/(app)/u/me/layout.tsx similarity index 100% rename from app/u/me/layout.tsx rename to app/(app)/u/me/layout.tsx diff --git a/app/u/me/mentions/page.tsx b/app/(app)/u/me/mentions/page.tsx similarity index 100% rename from app/u/me/mentions/page.tsx rename to app/(app)/u/me/mentions/page.tsx diff --git a/app/u/me/page.tsx b/app/(app)/u/me/page.tsx similarity index 100% rename from app/u/me/page.tsx rename to app/(app)/u/me/page.tsx diff --git a/app/u/me/posts/page.tsx b/app/(app)/u/me/posts/page.tsx similarity index 100% rename from app/u/me/posts/page.tsx rename to app/(app)/u/me/posts/page.tsx diff --git a/app/u/me/settings/page.tsx b/app/(app)/u/me/settings/page.tsx similarity index 100% rename from app/u/me/settings/page.tsx rename to app/(app)/u/me/settings/page.tsx diff --git a/app/verify-email/page.tsx b/app/(app)/verify-email/page.tsx similarity index 100% rename from app/verify-email/page.tsx rename to app/(app)/verify-email/page.tsx diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx deleted file mode 100644 index 5383544e..00000000 --- a/app/(auth)/login/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -"use client"; - -import { Suspense } from "react"; -import { useRouter, useSearchParams } from "next/navigation"; -import { AuthCard, AuthFooterLink } from "@/components/auth/auth-card"; -import { LoginForm } from "@/components/auth/login-form"; - -function LoginContent() { - const router = useRouter(); - const params = useSearchParams(); - - return ( - - } - > - { - router.push(params.get("next") ?? "/u/me"); - router.refresh(); - }} - /> - - ); -} - -export default function LoginPage() { - return ( - - - - ); -} diff --git a/app/(legal)/data-deletion/page.tsx b/app/(legal)/data-deletion/page.tsx new file mode 100644 index 00000000..72c148ff --- /dev/null +++ b/app/(legal)/data-deletion/page.tsx @@ -0,0 +1,274 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import { PageHeader } from "@/components/page-header"; +import { buildOgMeta } from "@/lib/og"; + +const EFFECTIVE_DATE = "June 1, 2026"; +const CONTACT_EMAIL = "support@prabhupadasays.org"; +const OPERATOR = "Krispire Solutions LLP"; +const SERVICE = "Prabhupāda Says"; +const SLA_DAYS = 30; + +export function generateMetadata(): Metadata { + return buildOgMeta({ + title: "Data Deletion — Prabhupāda Says", + quote: "How to delete your account and personal data from Prabhupāda Says.", + }); +} + +export default function DataDeletionPage() { + const subject = "Delete my account"; + const body = `Hello,\n\nI would like to delete my Prabhupāda Says account and all associated personal data.\n\n— Email address registered with the account: \n— Account handle (if known): \n— Reason for deletion (optional): \n\nThank you.`; + const mailto = `mailto:${CONTACT_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; + + return ( +
+ + + ← Home + +

+ Data Deletion +

+

Effective {EFFECTIVE_DATE}

+
+ +
+
+

+ You can delete your {SERVICE} account and the personal data + associated with it at any time. This page explains exactly how to + request deletion, what we delete, what we keep, and how long the + process takes. +

+

+ Self-service deletion from within your profile settings is planned + and will be added in a future release. Until then, please use the + email process below — we will process every valid request + within {SLA_DAYS} days. +

+
+ +
+
    +
  1. +

    + Send an email from the email address registered with your + account to{" "} + + {CONTACT_EMAIL} + + . +

    +

    + Sending from your registered email helps us verify the request + is genuinely yours. If you signed up through Google or Facebook, + send the email from the address linked to that provider. +

    +
  2. +
  3. +

    + Use the subject line:{" "} + + Delete my account + +

    +
  4. +
  5. +

    In the body of the email, include:

    +
      +
    • The email address registered with your account.
    • +
    • Your account handle, if you remember it.
    • +
    • + (Optional) The reason for deletion — this helps us + improve the Service, but you do not need to share it. +
    • +
    +
  6. +
  7. +

    + We will reply to confirm we have received your request, + typically within 2 business days, and again once the deletion is + complete. +

    +
  8. +
+ +
+

+ Prefer to skip the typing? Click the button below to open a + pre-filled email in your mail client. +

+ + Open pre-filled email + +
+
+ +
+

+ Once we verify your request, we permanently delete the following + within {SLA_DAYS} days: +

+
    +
  • + Your user account (email address, name, handle, password hash, + avatar URL, role, reading preferences, and account timestamps). +
  • +
  • + Any linked third-party sign-in identities (Google, Facebook). The + provider is the source of truth for your account with them; you + can revoke that link from the provider as well. +
  • +
  • Your avatar image stored in our object storage.
  • +
  • Your posts, bookmarks, collections, and short share links.
  • +
  • + Any outstanding password-reset or email-verification tokens. +
  • +
+

+ Records linked to your user identifier via foreign keys are removed + via cascade or set to a deleted-user placeholder at the same time. +

+
+ +
+

+ A small amount of information may be retained after account + deletion, in line with the law and the legitimate operation of the + Service: +

+
    +
  • + Feedback messages you + submitted are retained after deletion, but the link to your user + identifier is removed (so the message remains as anonymous product + feedback). +
  • +
  • + + Server and security logs + {" "} + may contain references to your activity for a short operational + window (typically 30 days) before they are deleted or anonymised. + These logs are not used to reconstruct your account. +
  • +
  • + + Records we are legally required to retain + {" "} + — for example, in connection with a pending legal claim, + regulatory request, or tax/accounting requirement — will be + kept only for as long as the law requires and then deleted. +
  • +
  • + Backups taken before + your deletion request are encrypted and rotate out on a regular + schedule. Your data will be overwritten as backups roll, typically + within 30 days. +
  • +
+
+ +
+
    +
  • + + Within 2 business days + {" "} + — we acknowledge your request. +
  • +
  • + + Within {SLA_DAYS} days + {" "} + — we complete the deletion in our active systems and send + you a confirmation email. +
  • +
  • + Up to 30 days after{" "} + — residual copies in encrypted backups roll out as part of + our normal backup retention schedule. +
  • +
+
+ +
+

+ Deleting your {SERVICE} account does not automatically remove your + account with Google or Facebook. To remove your data entirely from + those providers, also revoke the “Prabhupāda Says” app + connection in your provider settings: +

+
    +
  • + Google: visit your + Google Account → Security →{" "} + Third-party apps with account access → select + “Prabhupāda Says” → Remove access. +
  • +
  • + Facebook: visit{" "} + Settings & privacy → Settings →{" "} + Apps and websites → select “Prabhupāda + Says” → Remove. +
  • +
+
+ +
+

+ Besides deletion, you can also ask us to provide a copy of the + personal information we hold about you, or to correct information + that is inaccurate. See our{" "} + + Privacy Policy + {" "} + for the full list of rights available to you. +

+
+ +
+

+ If you have any trouble with the deletion process or want to verify + the status of a previous request, write to{" "} + + {CONTACT_EMAIL} + + . The Service is operated by {OPERATOR}. +

+
+
+
+ ); +} + +function Section({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) { + return ( +
+

{title}

+ {children} +
+ ); +} diff --git a/app/(legal)/layout.tsx b/app/(legal)/layout.tsx new file mode 100644 index 00000000..44d36683 --- /dev/null +++ b/app/(legal)/layout.tsx @@ -0,0 +1,20 @@ +import { SiteHeader } from "@/components/site-header"; + +/** + * Minimal layout for legal / informational pages (Privacy Policy, Terms of + * Use, Data Deletion). Just the global SiteHeader and the content — no + * sidebar, no bottom nav, no in-page reading affordances. Keeps these + * pages focused on the text they exist to deliver. + */ +export default function LegalLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+ + {children} +
+ ); +} diff --git a/app/(legal)/privacy/page.tsx b/app/(legal)/privacy/page.tsx new file mode 100644 index 00000000..76290a77 --- /dev/null +++ b/app/(legal)/privacy/page.tsx @@ -0,0 +1,405 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import { PageHeader } from "@/components/page-header"; +import { buildOgMeta } from "@/lib/og"; + +const EFFECTIVE_DATE = "June 1, 2026"; +const CONTACT_EMAIL = "support@prabhupadasays.org"; +const OPERATOR = "Krispire Solutions LLP"; +const SERVICE = "Prabhupāda Says"; + +export function generateMetadata(): Metadata { + return buildOgMeta({ + title: "Privacy Policy — Prabhupāda Says", + quote: + "How we collect, use, and protect your information when you use Prabhupāda Says.", + }); +} + +export default function PrivacyPolicyPage() { + return ( +
+ + + ← Home + +

+ Privacy Policy +

+

+ Effective {EFFECTIVE_DATE} +

+
+ +
+
+

+ This Privacy Policy explains how {OPERATOR} (“we”, + “us”, “our”) collects, uses, stores, and + shares your personal information when you use {SERVICE}{" "} + (the “Service”) available at prabhupadasays.org. By using + the Service you agree to the practices described below. +

+

+ We are committed to handling your information lawfully, fairly, and + transparently in accordance with India’s Digital Personal Data + Protection Act, 2023 (DPDP Act). +

+
+ +
+

+ The Service is developed and owned by {OPERATOR}, a limited + liability partnership registered in India. For any questions about + this Policy or your personal data, contact us at{" "} + + {CONTACT_EMAIL} + + . +

+
+ +
+

We collect only the information needed to operate the Service:

+ +

+ (a) Information you give us +

+
    +
  • + Account details when + you sign up by email: your name, email address, password (stored + only as a one-way bcrypt hash — we never see or store your + plain password), and a public handle. +
  • +
  • + Profile information{" "} + that you choose to add: display name, handle, and an optional + avatar image you upload. +
  • +
  • + User content you + create within the Service, such as posts (selected quotes you + choose to share publicly), bookmarks (private), collections + (private or public), and short share links. +
  • +
  • + Reading preferences{" "} + such as your chosen font, theme, and palette, so the reading + experience follows you across devices. +
  • +
  • + Feedback messages{" "} + you submit through the feedback form, including any contact + email you provide. +
  • +
+ +

+ (b) Information from third-party sign-in +

+
    +
  • + If you choose “Login with Google” or + “Login with Facebook”, we receive a stable + provider user identifier, your email, your name, and your + profile picture URL from that provider. We use this information + solely to create or sign you in to your account. +
  • +
+ +

+ (c) Information collected automatically +

+
    +
  • + Session cookies. We + set an httpOnly, secure session cookie ( + spsays_auth) after + you sign in, so you stay signed in across page loads. During + third-party sign-in we briefly set a second cookie ( + spsays_oauth_state) + to protect against cross-site request forgery; it is deleted at + the end of the sign-in handshake. +
  • +
  • + Share link analytics.{" "} + When someone clicks a short share link, we log the timestamp + and whether the request came from a known social-media link + preview bot. We do not log IP addresses or build user profiles + from this data. +
  • +
  • + Standard server logs.{" "} + Our servers retain short-lived logs containing request paths, + status codes, and timing for security and reliability. These + logs are not used for advertising or profiling. +
  • +
+
+ +
+
    +
  • To create and operate your account, and authenticate you.
  • +
  • + To deliver the features you request — bookmarks, + collections, posts, share links, search, and reading + preferences. +
  • +
  • + To send transactional emails: email verification, password + reset, and notifications you have opted into. +
  • +
  • + To respond to your feedback, questions, and support requests. +
  • +
  • + To protect the Service against abuse, fraud, and security + incidents. +
  • +
  • + To comply with applicable laws, court orders, and lawful + requests by public authorities. +
  • +
+

+ We do not sell your personal information, and we do not use it for + advertising or to build profiles about you for third parties. +

+
+ +
+

+ Where the DPDP Act or other applicable law requires a legal basis, + we rely on the following: +

+
    +
  • + Your consent, given + when you sign up or submit information voluntarily. +
  • +
  • + The performance of our + service to you (for example, processing your account + so you can sign in). +
  • +
  • + Our legitimate + interests in keeping the Service secure, preventing + abuse, and improving reliability. +
  • +
  • + Legal obligations{" "} + we are required to meet. +
  • +
+
+ +
+

+ We share your information only with the service providers we need + to run {SERVICE}. Each provider is bound by contractual or + statutory confidentiality obligations and processes data only on + our instructions. +

+
    +
  • + Google LLC — + when you use “Continue with Google”, Google + authenticates you and shares your profile basics with us. +
  • +
  • + Meta Platforms, Inc.{" "} + — when you use “Continue with Facebook”, + Facebook authenticates you and shares your profile basics with + us. +
  • +
  • + Cloudflare, Inc.{" "} + — we store avatar images you upload in Cloudflare R2 + object storage. +
  • +
  • + MongoDB, Inc. and + hosting/infrastructure providers — we store + account data and content in managed Postgres, MongoDB, and + DragonflyDB instances. +
  • +
  • + Typesense, Inc.{" "} + — we use a Typesense search index to power on-site search + for public content. +
  • +
  • + Our email delivery + provider — we send transactional emails (account + verification, password reset, feedback notifications) via an + SMTP relay. +
  • +
+

+ We may also disclose information when required by law, by valid + legal process, or to protect the rights, property, or safety of + our users, the public, or {OPERATOR}. +

+
+ +
+

+ Some of the providers listed above operate servers outside India. + Where data is transferred internationally, we rely on the + provider’s standard contractual safeguards and security + controls, in line with the DPDP Act and applicable cross-border + transfer rules. +

+
+ +
+
    +
  • + Account data is + kept for as long as your account is active. +
  • +
  • + User content{" "} + (posts, bookmarks, collections, profile) is kept until you + delete it or delete your account. +
  • +
  • + Password-reset and + email-verification tokens expire within 1 hour and 24 + hours respectively, and are deleted shortly after. +
  • +
  • + Server and click logs{" "} + are retained for a short operational window (typically 30 days + or less) and then deleted or anonymised. +
  • +
  • + Feedback messages{" "} + may be retained after your account is deleted, with your user + identifier removed, so we can act on the product feedback you + shared. +
  • +
+
+ +
+

+ Subject to the DPDP Act and other applicable laws, you have the + right to: +

+
    +
  • Access the personal information we hold about you.
  • +
  • Correct information that is inaccurate or out of date.
  • +
  • + Request deletion of your account and personal information (see{" "} + + Data Deletion + + ). +
  • +
  • Withdraw any consent you previously gave us.
  • +
  • + Nominate another person to exercise these rights on your behalf + in the event of your death or incapacity. +
  • +
  • + Lodge a grievance with us at{" "} + + {CONTACT_EMAIL} + + , or with the Data Protection Board of India. +
  • +
+

+ You can edit your name, handle, avatar, and reading preferences at + any time from your profile settings. For any other request, write + to us at the email above — we respond within 30 days. +

+
+ +
+

+ The Service is not directed to children under 13. If you are under + 13, please do not use the Service or provide any personal + information. If we learn that we have collected personal + information from a child under 13 without verified parental + consent, we will delete that information promptly. Parents and + guardians who believe their child has provided personal + information to us can contact us at{" "} + + {CONTACT_EMAIL} + + . +

+
+ +
+

+ We use industry-standard safeguards to protect your information, + including encryption in transit (HTTPS), bcrypt password hashing, + httpOnly secure cookies, signed CSRF tokens for third-party + sign-in, and least-privilege access controls. No method of + transmission or storage is perfectly secure; we will notify you + and the appropriate authority of a personal-data breach as + required by law. +

+
+ +
+

+ We may update this Policy from time to time. We will revise the + “Effective” date at the top of the page and, for + material changes, give you reasonable advance notice (for + example, by email or an in-app notice). +

+
+ +
+

+ Grievance Officer: contact{" "} + + {CONTACT_EMAIL} + {" "} + with the subject line “Privacy” and we will route + your message appropriately. {OPERATOR} is registered in India. +

+
+
+
+ ); +} + +function Section({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) { + return ( +
+

{title}

+ {children} +
+ ); +} diff --git a/app/(legal)/terms/page.tsx b/app/(legal)/terms/page.tsx new file mode 100644 index 00000000..b8dc39ed --- /dev/null +++ b/app/(legal)/terms/page.tsx @@ -0,0 +1,329 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import { PageHeader } from "@/components/page-header"; +import { buildOgMeta } from "@/lib/og"; + +const EFFECTIVE_DATE = "June 1, 2026"; +const CONTACT_EMAIL = "support@prabhupadasays.org"; +const OPERATOR = "Krispire Solutions LLP"; +const SERVICE = "Prabhupāda Says"; + +export function generateMetadata(): Metadata { + return buildOgMeta({ + title: "Terms of Use — Prabhupāda Says", + quote: + "The terms that govern your use of Prabhupāda Says — please read carefully.", + }); +} + +export default function TermsOfUsePage() { + return ( +
+ + + ← Home + +

+ Terms of Use +

+

+ Effective {EFFECTIVE_DATE} +

+
+ +
+
+

+ These Terms of Use (“Terms”) form a legally binding + agreement between you and {OPERATOR} (“we”, + “us”, “our”) and govern your access to and + use of {SERVICE} (the “Service”) at + prabhupadasays.org. By creating an account or otherwise using the + Service, you agree to these Terms. If you do not agree, please do + not use the Service. +

+
+ +
+

+ You must be at least 13 years old to use the Service. By using the + Service you represent that you meet this age requirement. If you + are between 13 and the age of majority where you live, you confirm + that your parent or legal guardian has reviewed and agreed to + these Terms on your behalf. +

+
+ +
+

+ You may create an account by signing up with an email and password + or by using a supported third-party sign-in provider (Google or + Facebook). You are responsible for keeping your sign-in + credentials confidential and for everything that happens under + your account. Notify us at{" "} + + {CONTACT_EMAIL} + {" "} + promptly if you suspect any unauthorised use. +

+

+ You agree to provide accurate information when signing up and to + keep it current. We may suspend or terminate accounts that contain + false, misleading, or impersonating information. +

+
+ +
+

+ {SERVICE} presents the books, letters, lectures, conversations, + and other writings of His Divine Grace A.C. Bhaktivedanta Swami + Prabhupāda, sourced from the pre-1980s Vedabase and related + archival materials. We provide this content for personal study, + research, and devotional engagement. We are an independent + project; we are not affiliated with, nor do we represent or + promote the views of, any institution, governing body, or faction + within the broader Vaiṣṇava community. +

+

+ We strive for textual fidelity, but the archive is being expanded + and verified on an ongoing basis. We do not warrant that the + content is free of typographical errors or omissions. If you spot + an issue, please let us know via the feedback form. +

+

+ The interface, software, database structure, design, and original + editorial work on the Service are owned by {OPERATOR} or its + licensors and are protected by copyright and other laws. +

+
+ +
+

You agree not to:

+
    +
  • + Use the Service to break any law, infringe anyone’s rights, + or send unlawful, defamatory, harassing, hateful, or sexually + explicit content. +
  • +
  • + Impersonate any person or organisation, including Śrīla + Prabhupāda or any disciple, or misrepresent your affiliation + with anyone. +
  • +
  • + Upload malware, exploit vulnerabilities, attempt to gain + unauthorised access, or interfere with the integrity or + performance of the Service. +
  • +
  • + Scrape, crawl, or harvest data from the Service in a way that + imposes a disproportionate load on our systems, or attempt to + extract content for the purpose of building a competing dataset. +
  • +
  • + Use the Service for commercial purposes (such as selling user + data, paid republishing of our editorial work, or running paid + services on top of our APIs) without our prior written consent. +
  • +
  • + Use the URL-shortener feature to disguise links to malware, + phishing, or unlawful content. +
  • +
+

+ We may remove user-generated content and suspend or terminate + accounts that violate these Terms. +

+
+ +
+

+ The Service lets you create user content — including posts, + bookmarks, collections, and short share links. You retain + ownership of any original material you contribute. By submitting + user content to the Service, you grant us a worldwide, + non-exclusive, royalty-free licence to host, store, reproduce, + display, and distribute that content as needed to operate the + Service (for example, to render a public collection on your + profile or to deliver a share link you created). +

+

+ You are responsible for the user content you create. You confirm + that you have the rights necessary to submit it and that it does + not violate any law or third-party right. +

+
+ +
+

+ The Service integrates with third-party services for sign-in, + object storage, email delivery, and search. Your use of those + services is also governed by their respective terms and privacy + policies. We are not responsible for outages, changes, or actions + taken by third-party providers. +

+
+ +
+

+ Our{" "} + + Privacy Policy + {" "} + explains how we collect, use, and share your information. By using + the Service, you agree to the practices described in that Policy. + For account deletion, see{" "} + + Data Deletion + + . +

+
+ +
+

+ We are actively developing the Service and may add, change, or + remove features at any time. We will try to give reasonable + advance notice of significant changes, but we may need to make + urgent changes for security or legal reasons without notice. +

+
+ +
+

+ The Service is provided on an “as is” and “as + available” basis. To the maximum extent permitted by law, + we disclaim all warranties, whether express or implied, including + warranties of merchantability, fitness for a particular purpose, + and non-infringement. We do not warrant that the Service will be + uninterrupted, secure, or free from errors. +

+

+ The Service is intended for educational and devotional use. It is + not a substitute for professional spiritual, medical, legal, + financial, or other professional advice. +

+
+ +
+

+ To the maximum extent permitted by law, {OPERATOR} and its + partners, employees, and contractors will not be liable for any + indirect, incidental, special, consequential, exemplary, or + punitive damages, or for any loss of profits, revenue, data, + goodwill, or other intangible losses arising out of or related to + your use of (or inability to use) the Service. +

+

+ Where liability cannot be excluded under applicable law, our + total aggregate liability to you in any 12-month period will not + exceed the greater of (a) ₹1,000 (Indian Rupees one thousand) or + (b) the amount you have paid us for the Service in that period + (which is typically zero, as the Service is provided free of + charge). +

+
+ +
+

+ You agree to indemnify and hold harmless {OPERATOR}, its partners, + employees, and contractors from and against any claims, losses, + damages, liabilities, costs, and expenses (including reasonable + legal fees) arising out of (a) your use of the Service in + violation of these Terms, (b) any user content you submit, or + (c) your violation of any law or third-party right. +

+
+ +
+

+ You may stop using the Service at any time and may delete your + account by following the steps on the{" "} + + Data Deletion + {" "} + page. We may suspend or terminate your access to the Service if + you violate these Terms, if required by law, or if it is necessary + to protect the Service or its users. Sections of these Terms that + by their nature should survive termination (including ownership, + disclaimers, limitation of liability, indemnity, and governing + law) will continue to apply after termination. +

+
+ +
+

+ These Terms are governed by the laws of India, without regard to + its conflict-of-laws principles. Any dispute arising out of or in + connection with these Terms or the Service shall be subject to + the exclusive jurisdiction of the competent courts located in + India. +

+

+ Before initiating any formal dispute, please write to us at{" "} + + {CONTACT_EMAIL} + {" "} + so we can try to resolve the matter informally. +

+
+ +
+

+ We may update these Terms from time to time. We will revise the + “Effective” date above and, for material changes, + give you reasonable advance notice. If you continue to use the + Service after the updated Terms take effect, you accept the + updated Terms. +

+
+ +
+

+ For any questions about these Terms, write to us at{" "} + + {CONTACT_EMAIL} + + . +

+
+
+
+ ); +} + +function Section({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) { + return ( +
+

{title}

+ {children} +
+ ); +} diff --git a/app/layout.tsx b/app/layout.tsx index ec0dcc89..1055ddf9 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,20 +1,11 @@ import type { Metadata } from "next"; -import { Suspense } from "react"; import { Geist, Geist_Mono, Lora, Bricolage_Grotesque } from "next/font/google"; import { ogDefault } from "@/lib/og"; import { ThemeProvider } from "@/components/theme-provider"; import { TooltipProvider } from "@/components/ui/tooltip"; -import { SiteHeader } from "@/components/site-header"; -import { SiteSidebar } from "@/components/site-sidebar"; -import { SiteBottomNav } from "@/components/site-bottom-nav"; -import { SiteFooter } from "@/components/site-footer"; -import { TextSelectionToolbar } from "@/components/text-selection-toolbar"; -import { TextHighlighter } from "@/components/text-highlighter"; import { AudioPlayerProvider, FloatingPlayer } from "@/components/audio-player"; import { AuthProvider } from "@/components/auth/auth-provider"; import { AuthGateProvider } from "@/components/auth/auth-gate"; -import { VerifyEmailBanner } from "@/components/auth/verify-email-banner"; -import { PageBookmarks } from "@/components/social/page-bookmarks"; import { SharePostProvider } from "@/components/social/share-post-provider"; import { Toaster } from "@/components/ui/toaster"; import "./globals.css"; @@ -56,6 +47,13 @@ export const metadata: Metadata = { ...ogDefault(), }; +/** + * Root layout — html/body shell + global providers + truly global widgets + * (toaster, floating audio player). Per-route chrome lives in the route + * groups beneath this: + * • (app)/ — sidebar, header, bottom nav, reading affordances + * • (legal)/ — header only, minimal chrome + */ export default function RootLayout({ children, }: Readonly<{ @@ -79,19 +77,11 @@ export default function RootLayout({ - - -
- - {children} -
- - - - - + {children} + {/* Toaster and FloatingPlayer are global — toasts and + currently-playing audio survive navigation between + route groups. */} -
diff --git a/components/auth/login-form.tsx b/components/auth/login-form.tsx index d77bce74..1a89cf12 100644 --- a/components/auth/login-form.tsx +++ b/components/auth/login-form.tsx @@ -16,6 +16,7 @@ import { useState } from "react"; import Link from "next/link"; import { useAuth } from "@/components/auth/auth-provider"; +import { OAuthButtons } from "@/components/auth/oauth-buttons"; import { AuthError } from "@/lib/auth"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -25,10 +26,13 @@ export function LoginForm({ onSuccess, forgotPasswordHref = "/forgot-password", showForgotLink = true, + oauthNext, }: { onSuccess?: () => void; forgotPasswordHref?: string; showForgotLink?: boolean; + /** Post-OAuth redirect path on the frontend. */ + oauthNext?: string; }) { const { logIn } = useAuth(); const [email, setEmail] = useState(""); @@ -51,7 +55,9 @@ export function LoginForm({ } return ( -
+
+ +
{submitting ? "Logging in…" : "Log in"} - + +
); } diff --git a/components/auth/oauth-buttons.tsx b/components/auth/oauth-buttons.tsx new file mode 100644 index 00000000..daa5ed07 --- /dev/null +++ b/components/auth/oauth-buttons.tsx @@ -0,0 +1,100 @@ +"use client"; + +/** + * OAuthButtons — "Continue with Google / Facebook" row used above both + * LoginForm and SignUpForm. Clicking a button performs a top-level + * navigation to the BFF's /oauth//start endpoint, which kicks off + * the Authorization Code flow. The BFF handles the round-trip and 302s back + * to ${frontend}${next} with the session cookie already set. + * + * Top-level navigation (not fetch) is intentional: cross-origin redirects + * to Google / Facebook can't happen from XHR, and we need the BFF to set + * the cookie before the browser lands back on the frontend. + */ + +import { useMemo } from "react"; + +const BFF_BASE = + process.env.NEXT_PUBLIC_BFF_URL || "http://localhost:8080"; + +type Props = { + /** Frontend path to land on after the round-trip. Defaults to /u/me. */ + next?: string; + /** Whether to render a divider with "or continue with email" below. */ + showDivider?: boolean; +}; + +export function OAuthButtons({ next, showDivider = true }: Props) { + const startUrl = useMemo( + () => (provider: "google" | "facebook") => { + const u = new URL(`${BFF_BASE}/api/v1/auth/oauth/${provider}/start`); + if (next) u.searchParams.set("next", next); + return u.toString(); + }, + [next], + ); + + return ( +
+ + {showDivider ? ( +
+ + + or + + +
+ ) : null} +
+ ); +} + +function GoogleIcon({ className }: { className?: string }) { + return ( + + + + + + + ); +} + +function FacebookIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/components/auth/signup-form.tsx b/components/auth/signup-form.tsx index 08d941c6..bd5079d4 100644 --- a/components/auth/signup-form.tsx +++ b/components/auth/signup-form.tsx @@ -8,12 +8,20 @@ import { useState } from "react"; import { useAuth } from "@/components/auth/auth-provider"; +import { OAuthButtons } from "@/components/auth/oauth-buttons"; import { AuthError } from "@/lib/auth"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -export function SignUpForm({ onSuccess }: { onSuccess?: () => void }) { +export function SignUpForm({ + onSuccess, + oauthNext, +}: { + onSuccess?: () => void; + /** Post-OAuth redirect path on the frontend. */ + oauthNext?: string; +}) { const { signUp } = useAuth(); const [name, setName] = useState(""); const [email, setEmail] = useState(""); @@ -36,7 +44,9 @@ export function SignUpForm({ onSuccess }: { onSuccess?: () => void }) { } return ( -
+
+ +
void }) { - + +
); } diff --git a/components/site-footer.tsx b/components/site-footer.tsx index 48b81375..7ecd1d49 100644 --- a/components/site-footer.tsx +++ b/components/site-footer.tsx @@ -16,7 +16,7 @@ export function SiteFooter() { > Prabhupāda Says -
+
· + + Privacy + + · + + Terms + + · + + Data Deletion + + · All glories to Śrīla Prabhupāda