| |
| import React from "react"; |
| import { Edit2, Trash2, Users } from "lucide-react"; |
|
|
| export default function ClassesTable({ |
| classes, |
| isLoading, |
| onEdit, |
| onDelete, |
| onManageStudents, |
| }) { |
| if (isLoading) { |
| return ( |
| <div className="space-y-3"> |
| {[1, 2, 3].map((i) => ( |
| <div |
| key={i} |
| className="h-16 w-full animate-pulse rounded-md bg-stone-100" |
| /> |
| ))} |
| </div> |
| ); |
| } |
|
|
| if (!classes || classes.length === 0) { |
| return ( |
| <div className="text-center py-12 text-stone-500"> |
| <p>No classes created yet.</p> |
| </div> |
| ); |
| } |
|
|
| return ( |
| <> |
| {/* Desktop table */} |
| <div className="hidden md:block overflow-x-auto"> |
| <table className="min-w-full text-sm border border-stone-200 rounded-lg overflow-hidden"> |
| <thead className="bg-stone-50"> |
| <tr> |
| <th className="px-4 py-2 text-left font-semibold text-stone-800"> |
| Class Name |
| </th> |
| <th className="px-4 py-2 text-left font-semibold text-stone-800"> |
| Schedule |
| </th> |
| <th className="px-4 py-2 text-left font-semibold text-stone-800"> |
| Status |
| </th> |
| <th className="px-4 py-2 text-right font-semibold text-stone-800"> |
| Actions |
| </th> |
| </tr> |
| </thead> |
| <tbody> |
| {classes.map((cls) => ( |
| <tr key={cls.id} className="border-t border-stone-200"> |
| <td className="px-4 py-3 align-top"> |
| <div> |
| <div className="font-medium text-stone-900"> |
| {cls.name} |
| </div> |
| {cls.description && ( |
| <div className="text-xs text-stone-500 max-w-xs truncate"> |
| {cls.description} |
| </div> |
| )} |
| </div> |
| </td> |
| <td className="px-4 py-3 align-top"> |
| <div className="space-y-1 text-sm"> |
| {(cls.schedule || []).map((slot, idx) => ( |
| <div key={idx}> |
| <span className="font-medium">{slot.day}:</span>{" "} |
| {slot.start_time && slot.end_time |
| ? `${slot.start_time} - ${slot.end_time}` |
| : slot.time || ""} |
| </div> |
| ))} |
| </div> |
| </td> |
| <td className="px-4 py-3 align-top"> |
| <span |
| className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${ |
| cls.is_active |
| ? "bg-green-100 text-green-800" |
| : "bg-stone-200 text-stone-700" |
| }`} |
| > |
| {cls.is_active ? "Active" : "Inactive"} |
| </span> |
| </td> |
| <td className="px-4 py-3 align-top text-right"> |
| <div className="flex justify-end gap-2"> |
| <button |
| type="button" |
| onClick={() => onManageStudents(cls)} |
| className="inline-flex items-center gap-1 rounded-md border border-stone-300 px-2.5 py-1 text-xs font-medium text-stone-800 hover:bg-stone-50" |
| > |
| <Users className="w-4 h-4" /> |
| Students |
| </button> |
| <button |
| type="button" |
| onClick={() => onEdit(cls)} |
| className="inline-flex items-center justify-center rounded-md border border-stone-300 px-2.5 py-1 text-xs text-stone-800 hover:bg-stone-50" |
| > |
| <Edit2 className="w-4 h-4" /> |
| </button> |
| <button |
| type="button" |
| onClick={() => onDelete(cls.id)} |
| className="inline-flex items-center justify-center rounded-md border border-red-200 px-2.5 py-1 text-xs text-red-700 hover:bg-red-50" |
| > |
| <Trash2 className="w-4 h-4" /> |
| </button> |
| </div> |
| </td> |
| </tr> |
| ))} |
| </tbody> |
| </table> |
| </div> |
| |
| {/* Mobile cards */} |
| <div className="md:hidden space-y-3"> |
| {classes.map((cls) => ( |
| <div |
| key={cls.id} |
| className="rounded-lg border border-stone-200 p-4 bg-white shadow-sm" |
| > |
| <div className="flex justify-between items-start mb-2"> |
| <div className="font-semibold text-stone-900">{cls.name}</div> |
| <span |
| className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${ |
| cls.is_active |
| ? "bg-green-100 text-green-800" |
| : "bg-stone-200 text-stone-700" |
| }`} |
| > |
| {cls.is_active ? "Active" : "Inactive"} |
| </span> |
| </div> |
| {cls.description && ( |
| <p className="text-sm text-stone-600 mb-3"> |
| {cls.description} |
| </p> |
| )} |
| <div className="space-y-1 mb-3 text-sm"> |
| {(cls.schedule || []).map((slot, idx) => ( |
| <div key={idx}> |
| <span className="font-medium">{slot.day}:</span>{" "} |
| {slot.start_time && slot.end_time |
| ? `${slot.start_time} - ${slot.end_time}` |
| : slot.time || ""} |
| </div> |
| ))} |
| </div> |
| <div className="flex gap-2"> |
| <button |
| type="button" |
| onClick={() => onManageStudents(cls)} |
| className="flex-1 inline-flex items-center justify-center gap-1 rounded-md border border-stone-300 px-2.5 py-1.5 text-xs font-medium text-stone-800 hover:bg-stone-50" |
| > |
| <Users className="w-4 h-4" /> |
| Students |
| </button> |
| <button |
| type="button" |
| onClick={() => onEdit(cls)} |
| className="inline-flex items-center justify-center rounded-md border border-stone-300 px-2.5 py-1.5 text-xs text-stone-800 hover:bg-stone-50" |
| > |
| <Edit2 className="w-4 h-4" /> |
| </button> |
| <button |
| type="button" |
| onClick={() => onDelete(cls.id)} |
| className="inline-flex items-center justify-center rounded-md border border-red-200 px-2.5 py-1.5 text-xs text-red-700 hover:bg-red-50" |
| > |
| <Trash2 className="w-4 h-4" /> |
| </button> |
| </div> |
| </div> |
| ))} |
| </div> |
| </> |
| ); |
| } |
|
|