'use client' import { useState, type Dispatch, type SetStateAction } from 'react' import { Users } from 'lucide-react' import { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription } from '@/components/ui/empty' import type { Member, SortKey, AreaLeadRole } from '../types' const TIER_COLORS: Record = { plus: 'text-blue-600 bg-blue-50 border-blue-200', basic: 'text-muted-foreground bg-muted border-border', associate: 'text-purple-600 bg-purple-50 border-purple-200', admin: 'text-primary bg-primary/5 border-primary/20', } interface MembersTableProps { // Already filtered by the orchestrator; the table owns only its sort order. members: Member[] isAdmin: boolean canGrantCerts: boolean canManageCards: boolean canViewForms: boolean areaLeadRoles: AreaLeadRole[] selected: Set setSelected: Dispatch>> toggleSel: (id: string) => void onApprove: (memberId: string) => void onRemove: (memberId: string) => void onEdit: (m: Member) => void onCerts: (m: Member) => void onCards: (m: Member) => void onForms: (m: Member) => void onMakeAreaLead: (memberId: string, areaLeadRoleId: string) => void } export function MembersTable({ members: filteredMembers, isAdmin, canGrantCerts, canManageCards, canViewForms, areaLeadRoles, selected, setSelected, toggleSel, onApprove, onRemove, onEdit, onCerts, onCards, onForms, onMakeAreaLead, }: MembersTableProps) { const [sort, setSort] = useState<{ key: SortKey; dir: 'asc' | 'desc' } | null>(null) const sortedMembers = sort ? [...filteredMembers].sort((a, b) => { const dir = sort.dir === 'asc' ? 1 : -1 const val = (m: Member): string => { switch (sort.key) { case 'name': return (m.display_name ?? '').toLowerCase() case 'tier': return m.tier ?? '' case 'status': return m.status ?? '' case 'joined': return m.joined_at ?? '' case 'last_payment': return (m.last_paid_at || m.last_payment_at || '') as string default: return '' } } return val(a).localeCompare(val(b)) * dir }) : filteredMembers function toggleSort(key: SortKey) { setSort(s => s && s.key === key ? (s.dir === 'asc' ? { key, dir: 'desc' } : null) : { key, dir: 'asc' }, ) } const caret = (key: SortKey) => (sort?.key === key ? (sort.dir === 'asc' ? ' ↑' : ' ↓') : '') return (
{isAdmin && ( )} {([ ['name', 'MEMBER', ''], ['tier', 'TIER', ''], ['joined', 'JOINED', 'hidden md:table-cell'], ['last_payment', 'LAST PAYMENT', 'hidden lg:table-cell'], ['status', 'STATUS', ''], ] as [SortKey, string, string][]).map(([key, label, cls]) => ( ))} {canGrantCerts && ( )} {canManageCards && ( )} {canViewForms && ( )} {isAdmin && ( )} {sortedMembers.length > 0 ? sortedMembers.map(m => { const initials = (m.display_name || 'U').split(' ').map((n: string) => n[0]).join('').toUpperCase().slice(0, 2) const hasIssue = m.payment_status && m.payment_status !== 'current' return ( {isAdmin && ( )} {canGrantCerts && ( )} {canManageCards && ( )} {canViewForms && ( )} {isAdmin && ( )} ) }) : ( )}
0 && sortedMembers.every(m => selected.has(m.id))} onChange={e => setSelected(e.target.checked ? new Set(sortedMembers.map(m => m.id)) : new Set()) } /> CERTSCARDSFORMSACTIONS
toggleSel(m.id)} />
{initials}

{m.display_name}

{m.email}{m.handle ? ` · @${m.handle}` : ''}{m.payment_note ? ` — ${m.payment_note}` : ''}

{m.tier?.toUpperCase()} {m.joined_at ? new Date(m.joined_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' }) : '-'} {(m.last_paid_at || m.last_payment_at) ? new Date((m.last_paid_at || m.last_payment_at)!).toLocaleDateString('en-US', { month: 'short', year: 'numeric' }) : '-'} {m.status === 'unverified' ? ( unverified ) : m.payment_status === 'current' ? ( current ) : m.payment_status ? ( {m.payment_status} ) : ( {m.status} )}
{m.status === 'unverified' && ( )} {areaLeadRoles.length > 0 && ( )}
No members match this filter Try a different tab, clear the search, or change the tier filter.
{/* Mobile: stacked cards (the table is unusable on phones). */}
{sortedMembers.length > 0 ? sortedMembers.map(m => { const hasIssue = m.payment_status && m.payment_status !== 'current' return (
{isAdmin && ( toggleSel(m.id)} /> )}

{m.display_name}

{m.email}

{m.tier?.toUpperCase()}

{m.status === 'unverified' ? 'unverified' : (m.payment_status || m.status)} {m.joined_at ? ` · joined ${new Date(m.joined_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}` : ''}

{isAdmin && m.status === 'unverified' && ( )} {isAdmin && ( )} {canGrantCerts && ( )} {canManageCards && ( )} {canViewForms && ( )} {isAdmin && ( )}
) }) : ( No members match this filter Try a different tab, clear the search, or change the tier filter. )}
) }