feat: member portal Sprint 2 — digest history page and restore Digest/DigestConfig schema models

- Restore Digest + DigestConfig models to schema.prisma (wiped by prior git reset)
- Add Tenant.digestConfig / Tenant.digests relations
- GET /my/digest API endpoint (last 20 digests, truncated summary)
- BFF route /api/my/digest
- /my/digest page: digest cards with date, message count, summary preview
- Add Digest nav item to MemberShell sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 16:04:31 +05:30
parent a685f8b4d5
commit bc9fe7c145
6 changed files with 132 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
import { getMemberToken, getApiBaseUrl } from '../../_lib/api';
import Link from 'next/link';
interface DigestItem {
id: string;
digestDate: string;
summary: string;
messageCount: number;
sentAt: string;
}
async function fetchDigests(token: string): Promise<DigestItem[]> {
const res = await fetch(`${getApiBaseUrl()}/my/digest`, {
headers: { Authorization: `Bearer ${token}` },
cache: 'no-store',
}).catch(() => null);
if (!res || !res.ok) return [];
return (await res.json()) as DigestItem[];
}
export default async function DigestPage() {
const token = await getMemberToken();
if (!token) return null;
const digests = await fetchDigests(token);
return (
<div className="max-w-2xl mx-auto space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-xl font-semibold text-gray-900">Digest history</h1>
<Link href="/my" className="text-sm text-indigo-600 hover:underline"> Dashboard</Link>
</div>
{digests.length === 0 && (
<div className="text-center py-16 text-gray-400">
<p className="text-sm">No digests sent yet.</p>
<p className="text-xs mt-1">Your chapter admin generates these periodically.</p>
</div>
)}
<div className="space-y-4">
{digests.map((d) => (
<div key={d.id} className="bg-white rounded-xl border border-gray-200 p-5">
<div className="flex items-center justify-between mb-3">
<div>
<p className="text-sm font-semibold text-gray-900">
{new Date(d.digestDate).toLocaleDateString('en-IN', {
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
})}
</p>
<p className="text-xs text-gray-400 mt-0.5">
{d.messageCount} message{d.messageCount !== 1 ? 's' : ''} · sent {new Date(d.sentAt).toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' })}
</p>
</div>
<span className="text-xs bg-indigo-50 text-indigo-600 rounded-full px-3 py-1 font-medium">
Digest
</span>
</div>
<p className="text-sm text-gray-700 whitespace-pre-line leading-relaxed">
{d.summary}
{d.summary.length >= 300 && <span className="text-gray-400"></span>}
</p>
</div>
))}
</div>
</div>
);
}