- {pageData.map((disciple) => {
- const locationYear = formatLocationYear(
- disciple.initiationPlace,
- disciple.initiationDate,
- );
-
- return (
-
-
-
-
- {disciple.initiatedName}
-
- {disciple.suffix && (
-
- {disciple.suffix}
-
- )}
-
- {locationYear && (
-
- {locationYear}
-
- )}
-
-
- );
- })}
+ {pageData.map((disciple) => (
+
+ ))}
)}
diff --git a/app/(app)/(reader)/disciples/page.tsx b/app/(app)/(reader)/disciples/page.tsx
index 8a476af2..d5eb9e05 100644
--- a/app/(app)/(reader)/disciples/page.tsx
+++ b/app/(app)/(reader)/disciples/page.tsx
@@ -12,6 +12,7 @@ import {
getDiscipleYears,
getDiscipleSuffixCounts,
getFilteredDiscipleCount,
+ getDiscipleLinks,
} from "@/lib/disciples";
import type { SuffixFilter } from "@/lib/disciples";
import { DisciplesBrowser } from "./disciples-browser";
@@ -62,6 +63,7 @@ export default async function DisciplesPage({
places,
years,
suffixCounts,
+ links,
] = await Promise.all([
getTotalDiscipleCount(),
getFilteredDisciples(letterFilter, activeSuffix),
@@ -70,6 +72,7 @@ export default async function DisciplesPage({
getDisciplePlaces(),
getDiscipleYears(),
getDiscipleSuffixCounts(),
+ getDiscipleLinks(),
]);
// Serialize dates to ISO strings for the client component
@@ -105,6 +108,7 @@ export default async function DisciplesPage({
years={years}
totalCount={totalCount}
filteredCount={filteredCount}
+ links={links}
/>
diff --git a/app/(app)/notifications/page.tsx b/app/(app)/notifications/page.tsx
index c41652be..26ce2305 100644
--- a/app/(app)/notifications/page.tsx
+++ b/app/(app)/notifications/page.tsx
@@ -350,6 +350,8 @@ function messageFor(n: AppNotification): string {
return "replied to your comment.";
case "comment_mention":
return "mentioned you in a comment.";
+ case "disciple_joined":
+ return "— a direct disciple of Śrīla Prabhupāda — has joined Prabhupāda Says.";
case "admin_message":
return n.body ?? "sent you a message.";
default:
diff --git a/app/(app)/u/[handle]/layout.tsx b/app/(app)/u/[handle]/layout.tsx
index 2c131eba..212d64c2 100644
--- a/app/(app)/u/[handle]/layout.tsx
+++ b/app/(app)/u/[handle]/layout.tsx
@@ -129,6 +129,7 @@ export default function PublicProfileLayout(props: {
interactiveCounts={false}
joinedAt={data.joined_at}
country={data.country}
+ isDirectDisciple={!!data.is_direct_disciple}
/>
@@ -174,6 +175,7 @@ export default function PublicProfileLayout(props: {
enableActions
joinedAt={data.joined_at}
country={data.country}
+ isDirectDisciple={!!data.is_direct_disciple}
/>
diff --git a/app/(app)/u/me/layout.tsx b/app/(app)/u/me/layout.tsx
index d438dfa1..701f532d 100644
--- a/app/(app)/u/me/layout.tsx
+++ b/app/(app)/u/me/layout.tsx
@@ -140,6 +140,7 @@ export default function MeLayout({ children }: { children: React.ReactNode }) {
name={user.name}
handle={user.handle}
joinedAt={user.created_at}
+ isDirectDisciple={!!user.is_direct_disciple}
editHref="/settings/profile"
postCount={counts?.posts}
followerCount={counts?.followers}
diff --git a/components/notifications/notification-matrix.tsx b/components/notifications/notification-matrix.tsx
index c8b5d0b1..6c29a542 100644
--- a/components/notifications/notification-matrix.tsx
+++ b/components/notifications/notification-matrix.tsx
@@ -26,7 +26,15 @@ import {
pushSupported,
} from "@/lib/push";
-const EVENTS: { key: PrefEvent; label: string; description: string }[] = [
+const EVENTS: {
+ key: PrefEvent;
+ label: string;
+ description: string;
+ /** Channels this event can actually be delivered on. Omit for all three.
+ * A cell outside this set renders as "—" rather than a live toggle, so we
+ * never show a switch that silently does nothing. */
+ channels?: PrefChannel[];
+}[] = [
{
key: "follows",
label: "Follows",
@@ -42,6 +50,14 @@ const EVENTS: { key: PrefEvent; label: string; description: string }[] = [
label: "Sādhana reminders",
description: "Daily nudges to chant your rounds and share a verse.",
},
+ {
+ key: "community",
+ label: "Community",
+ description:
+ "Rare announcements — such as a direct disciple of Śrīla Prabhupāda joining.",
+ // Announcements are in-app/push only; we deliberately don't email them.
+ channels: ["in_app", "push"],
+ },
];
const CHANNELS: { key: PrefChannel; label: string }[] = [
@@ -73,7 +89,9 @@ export function NotificationMatrix() {
async function toggle(event: PrefEvent, channel: PrefChannel) {
if (!prefs) return;
- const next = !prefs[event][channel];
+ // Default-on when the key is absent: prefs are stored as opt-outs, and a
+ // BFF that predates this category simply omits it.
+ const next = !(prefs[event]?.[channel] ?? true);
setBusyCell(`${event}/${channel}`);
try {
// Turning a push cell ON only helps if this device can receive push —
@@ -132,23 +150,34 @@ export function NotificationMatrix() {
{event.description}
- {CHANNELS.map((channel) => (
-