feat(classes): per-session signups roster on /classes/manage (staff)

Reuses the existing SessionAttendance component (listSessionSignups,
classes.manage/instruct-gated) behind a per-session 'Signups' toggle on
the manage page, so managers can see who signed up + status + mark
attendance + complete without leaving the manage screen. Members still
see only spots-left (privacy posture unchanged).
This commit is contained in:
Moheeb Zara
2026-05-16 21:41:59 -07:00
parent f3b05afe14
commit 69fa64c82d
@@ -17,6 +17,7 @@ import {
deleteSession, deleteSession,
} from '@/lib/actions' } from '@/lib/actions'
import { SESSION_STATUS_LABEL } from '@/lib/classes-logic' import { SESSION_STATUS_LABEL } from '@/lib/classes-logic'
import { SessionAttendance } from '@/components/classes/session-attendance'
type Cls = { type Cls = {
id: string id: string
@@ -77,6 +78,7 @@ export function ClassesManageClient({
const [editDraft, setEditDraft] = useState(emptyClassDraft()) const [editDraft, setEditDraft] = useState(emptyClassDraft())
const [sessForClass, setSessForClass] = useState<string | null>(null) const [sessForClass, setSessForClass] = useState<string | null>(null)
const [sessDraft, setSessDraft] = useState(emptySessionDraft()) const [sessDraft, setSessDraft] = useState(emptySessionDraft())
const [rosterFor, setRosterFor] = useState<string | null>(null)
const [busy, setBusy] = useState(false) const [busy, setBusy] = useState(false)
function certName(id: string | null) { function certName(id: string | null) {
@@ -395,7 +397,8 @@ export function ClassesManageClient({
) : ( ) : (
<ul className="divide-y divide-border"> <ul className="divide-y divide-border">
{cs.map(s => ( {cs.map(s => (
<li key={s.id} className="py-2 flex items-center justify-between gap-3 flex-wrap"> <li key={s.id} className="py-2">
<div className="flex items-center justify-between gap-3 flex-wrap">
<div className="font-mono text-[11px] text-muted-foreground"> <div className="font-mono text-[11px] text-muted-foreground">
{new Date(s.starts_at).toLocaleString()} {new Date(s.starts_at).toLocaleString()}
{s.location ? ` · ${s.location}` : ''} {s.location ? ` · ${s.location}` : ''}
@@ -406,11 +409,26 @@ export function ClassesManageClient({
</span> </span>
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<Button size="sm" variant="outline"
onClick={() => setRosterFor(rosterFor === s.id ? null : s.id)}>
{rosterFor === s.id ? 'Hide signups' : 'Signups'}
</Button>
{s.status === 'scheduled' && ( {s.status === 'scheduled' && (
<Button size="sm" variant="outline" onClick={() => onCancelSession(s)}>Cancel</Button> <Button size="sm" variant="outline" onClick={() => onCancelSession(s)}>Cancel</Button>
)} )}
<Button size="sm" variant="outline" onClick={() => onDeleteSession(s)}>Delete</Button> <Button size="sm" variant="outline" onClick={() => onDeleteSession(s)}>Delete</Button>
</div> </div>
</div>
{rosterFor === s.id && (
<SessionAttendance
sessionId={s.id}
sessionStatus={s.status}
onCompleted={() => {
setSessions(prev => prev.map(x => (x.id === s.id ? { ...x, status: 'completed' } : x)))
setRosterFor(null)
}}
/>
)}
</li> </li>
))} ))}
</ul> </ul>