import { getMemberToken, getApiBaseUrl } from '../../_lib/api'; import { SevaSignupButton } from './SevaSignupButton'; import Link from 'next/link'; type EntryStatus = 'SIGNED_UP' | 'COMPLETED' | 'CANCELLED'; interface SevaData { score: { lifetime: number; recent: number; byType: Record; eventCount: number }; leaderboard: Array<{ rank: number; userId: string; displayName: string; points: number }>; opportunities: Array<{ id: string; title: string; description: string | null; location: string | null; slots: number | null; startsAt: string | null; pointsAward: number; signupCount: number; myEntryStatus: EntryStatus | null; }>; myEntries: Array<{ id: string; opportunityTitle: string; status: EntryStatus; hours: number | null; pointsAward: number; completedAt: string | null; createdAt: string; }>; } async function fetchSeva(token: string): Promise { const res = await fetch(`${getApiBaseUrl()}/my/seva`, { headers: { Authorization: `Bearer ${token}` }, cache: 'no-store', }).catch(() => null); if (!res || !res.ok) return null; return (await res.json()) as SevaData; } const TYPE_LABELS: Record = { HELPFUL_ANSWER: 'Helpful answers', SEVA_COMPLETED: 'Seva completed', EVENT_ATTENDANCE: 'Event attendance', FAQ_APPROVED: 'FAQ contributions', WELCOME: 'Welcomes', PROFILE_COMPLETED: 'Profile', BUSINESS_ADDED: 'Business', }; export default async function SevaPage() { const token = await getMemberToken(); if (!token) return null; const data = await fetchSeva(token); if (!data) { return (
Could not load seva data.
); } const { score, leaderboard, opportunities, myEntries } = data; return (

Seva & points

← Dashboard
{/* Points hero */}

Your points

{score.lifetime}

{score.recent} active · {score.eventCount} contributions

{Object.keys(score.byType).length > 0 && (
{Object.entries(score.byType).map(([type, pts]) => ( {TYPE_LABELS[type] ?? type}: {pts} ))}
)}
{/* Open opportunities */}

Open opportunities

{opportunities.length === 0 ? (

No open seva opportunities right now.

) : (
{opportunities.map((o) => { const full = o.slots != null && o.signupCount >= o.slots && o.myEntryStatus == null; return (

{o.title}

+{o.pointsAward} points

{(o.location || o.startsAt) && (

{[o.location, o.startsAt ? new Date(o.startsAt).toLocaleDateString('en-IN', { day: 'numeric', month: 'short' }) : null] .filter(Boolean) .join(' · ')}

)}
{o.description &&

{o.description}

}

{o.signupCount} signed up{o.slots != null ? ` · ${o.slots} slots` : ''}

); })}
)}
{/* Leaderboard */} {leaderboard.length > 0 && (

Top contributors

{leaderboard.map((l) => (
#{l.rank} {l.displayName}
{l.points} pts
))}
)} {/* My seva history */} {myEntries.length > 0 && (

My seva

{myEntries.map((e) => (

{e.opportunityTitle}

{e.status === 'COMPLETED' && e.completedAt ? `Completed ${new Date(e.completedAt).toLocaleDateString()}` : e.status === 'SIGNED_UP' ? 'Signed up' : 'Cancelled'}

{e.status === 'COMPLETED' && ( +{e.pointsAward} )}
))}
)}
); }