ClassLens / chatkit /frontend /src /components /step2 /StudentSelector.tsx
chih.yikuan
Add prompt editor and data preview back to Step 2
40aa09c
Raw
History Blame Contribute Delete
2.67 kB
import { useState, useEffect } from "react";
interface Student {
index: number;
name: string;
id: string;
}
interface StudentSelectorProps {
students: Student[];
onSelectionChange: (selectedIndices: number[]) => void;
}
export function StudentSelector({
students,
onSelectionChange,
}: StudentSelectorProps) {
const [selected, setSelected] = useState<Set<number>>(
() => new Set(students.map((s) => s.index))
);
useEffect(() => {
onSelectionChange(Array.from(selected).sort((a, b) => a - b));
}, [selected]);
const toggleAll = () => {
if (selected.size === students.length) {
setSelected(new Set());
} else {
setSelected(new Set(students.map((s) => s.index)));
}
};
const toggle = (index: number) => {
setSelected((prev) => {
const next = new Set(prev);
if (next.has(index)) {
next.delete(index);
} else {
next.add(index);
}
return next;
});
};
const allSelected = selected.size === students.length;
return (
<div className="space-y-3">
<div className="flex items-center gap-3">
<h3 className="font-display text-sm font-semibold text-[var(--color-text)]">
選擇學生
</h3>
<button
onClick={toggleAll}
className="btn btn-outline text-xs !py-1 !px-3"
>
{allSelected ? "取消全選" : "全選"}
</button>
<span className="text-sm text-[var(--color-text-muted)]">
已選 {selected.size} / {students.length} 位學生
</span>
</div>
<div className="card p-4 max-h-64 overflow-y-auto">
<div className="grid gap-1.5 sm:grid-cols-2">
{students.map((s) => (
<label
key={s.index}
className={`flex items-center gap-3 px-3 py-2 rounded-lg cursor-pointer transition-colors ${
selected.has(s.index)
? "bg-[var(--color-primary)]/10"
: "hover:bg-[var(--color-surface)]"
}`}
>
<input
type="checkbox"
checked={selected.has(s.index)}
onChange={() => toggle(s.index)}
className="w-4 h-4 rounded accent-[var(--color-primary)]"
/>
<span className="text-sm font-medium text-[var(--color-text)]">
{s.name}
</span>
{s.id && (
<span className="text-xs text-[var(--color-text-muted)]">
({s.id})
</span>
)}
</label>
))}
</div>
</div>
</div>
);
}