feat: disciple highlight

This commit is contained in:
gosangam
2026-08-07 22:47:04 +05:30
parent 1984797ad3
commit 274c735b4d
13 changed files with 348 additions and 64 deletions
@@ -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}
</p>
</div>
{CHANNELS.map((channel) => (
<div
key={channel.key}
className="flex justify-center border-t border-border py-3"
>
{prefs ? (
<ToggleSwitch
checked={prefs[event.key][channel.key]}
disabled={busyCell === `${event.key}/${channel.key}`}
onToggle={() => toggle(event.key, channel.key)}
label={`${event.label} — ${channel.label}`}
/>
) : (
<span className="text-xs text-muted-foreground">…</span>
)}
</div>
))}
{CHANNELS.map((channel) => {
const deliverable =
!event.channels || event.channels.includes(channel.key);
return (
<div
key={channel.key}
className="flex justify-center border-t border-border py-3"
>
{!deliverable ? (
<span
className="text-xs text-muted-foreground"
title={`${event.label} isn't delivered by ${channel.label.toLowerCase()}`}
>
&mdash;
</span>
) : prefs ? (
<ToggleSwitch
checked={prefs[event.key]?.[channel.key] ?? true}
disabled={busyCell === `${event.key}/${channel.key}`}
onToggle={() => toggle(event.key, channel.key)}
label={`${event.label} — ${channel.label}`}
/>
) : (
<span className="text-xs text-muted-foreground">…</span>
)}
</div>
);
})}
</div>
))}
</div>