refactor: update UI components and pages with a refreshed visual design and improved styling.
This commit is contained in:
@@ -149,9 +149,9 @@ export default function GradebookPage() {
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setShowBulkEnroll(true)}
|
||||
className="bg-white/5 hover:bg-white/10 border border-white/10 px-4 py-2 rounded-xl flex items-center gap-2 transition-all font-medium text-sm"
|
||||
className="bg-slate-50 dark:bg-white/5 hover:bg-slate-100 dark:hover:bg-white/10 border border-slate-200 dark:border-white/10 px-4 py-2 rounded-xl flex items-center gap-2 transition-all font-bold text-xs uppercase tracking-widest text-slate-600 dark:text-gray-400 shadow-sm"
|
||||
>
|
||||
<Users size={16} /> Inscripción Masiva
|
||||
<Users size={16} className="text-blue-500" /> Inscripción Masiva
|
||||
</button>
|
||||
<button
|
||||
onClick={exportCSV}
|
||||
@@ -166,66 +166,73 @@ export default function GradebookPage() {
|
||||
|
||||
{/* Bulk Enroll Modal */}
|
||||
{showBulkEnroll && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 dark:bg-black/80 backdrop-blur-sm animate-in fade-in duration-300">
|
||||
<div className="bg-white dark:bg-[#1a1d23] border border-slate-200 dark:border-white/10 rounded-2xl w-full max-w-2xl overflow-hidden shadow-2xl animate-in fade-in zoom-in duration-200">
|
||||
<div className="p-6 border-b border-slate-100 dark:border-white/5 flex items-center justify-between">
|
||||
<h3 className="text-xl font-bold flex items-center gap-2 text-slate-900 dark:text-white">
|
||||
<Users className="text-blue-500 dark:text-blue-400" /> Inscripción Masiva de Estudiantes
|
||||
</h3>
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/40 dark:bg-black/80 backdrop-blur-md animate-in fade-in duration-300">
|
||||
<div className="bg-white dark:bg-[#1a1d23] border border-slate-200 dark:border-white/10 rounded-[2.5rem] w-full max-w-2xl overflow-hidden shadow-2xl animate-in zoom-in-95 duration-200">
|
||||
<div className="p-8 border-b border-slate-100 dark:border-white/5 flex items-center justify-between bg-slate-50/50 dark:bg-transparent">
|
||||
<div>
|
||||
<h3 className="text-2xl font-black flex items-center gap-3 text-slate-900 dark:text-white uppercase tracking-tight">
|
||||
<Users className="text-blue-600 dark:text-blue-400" /> Inscripción Masiva
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 dark:text-gray-500 font-bold uppercase tracking-widest mt-1">Enroll multiple students at once</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowBulkEnroll(false);
|
||||
setBulkResults(null);
|
||||
setBulkEmails("");
|
||||
}}
|
||||
className="p-1 hover:bg-white/5 rounded-lg transition-colors"
|
||||
className="p-3 hover:bg-slate-200 dark:hover:bg-white/10 rounded-2xl transition-all group active:scale-95"
|
||||
>
|
||||
<X size={20} />
|
||||
<X size={20} className="text-slate-400 group-hover:text-slate-900 dark:group-hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-8 space-y-6">
|
||||
<div className="p-8 space-y-8">
|
||||
{!bulkResults ? (
|
||||
<>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-500 dark:text-gray-400 mb-2">
|
||||
Ingresa las direcciones de correo (separadas por comas o saltos de línea)
|
||||
<label className="block text-xs font-black uppercase tracking-widest text-slate-400 dark:text-gray-500 mb-3">
|
||||
Enter email addresses (separated by commas or new lines)
|
||||
</label>
|
||||
<textarea
|
||||
value={bulkEmails}
|
||||
onChange={(e) => setBulkEmails(e.target.value)}
|
||||
placeholder="student1@example.com student2@example.com"
|
||||
className="w-full h-48 bg-slate-50 dark:bg-black/20 border border-slate-200 dark:border-white/10 rounded-xl p-4 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/50 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-gray-600 resize-none font-mono"
|
||||
className="w-full h-48 bg-slate-50 dark:bg-black/20 border border-slate-200 dark:border-white/10 rounded-3xl p-5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/50 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-gray-600 resize-none font-mono shadow-inner leading-relaxed"
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-blue-500/10 border border-blue-500/20 rounded-xl p-4 flex gap-3 italic text-sm text-blue-400">
|
||||
<AlertTriangle size={18} className="shrink-0" />
|
||||
Los estudiantes deben tener una cuenta en esta organización para ser inscritos.
|
||||
<div className="bg-blue-50 dark:bg-blue-500/10 border border-blue-100 dark:border-blue-500/20 rounded-2xl p-5 flex gap-4">
|
||||
<div className="w-10 h-10 rounded-xl bg-white dark:bg-black/20 flex items-center justify-center shrink-0 shadow-sm text-blue-500">
|
||||
<AlertTriangle size={20} />
|
||||
</div>
|
||||
<p className="text-xs text-blue-800/80 dark:text-blue-300 leading-relaxed font-bold uppercase tracking-tight">
|
||||
Students must already have an account in this organization directory to be successfully enrolled into the course.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="space-y-6">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="bg-green-500/10 border border-green-500/20 rounded-xl p-4 text-center">
|
||||
<div className="text-2xl font-black text-green-400">{bulkResults.successful_emails.length}</div>
|
||||
<div className="text-xs uppercase tracking-widest text-gray-500 font-bold mt-1">Enrolled</div>
|
||||
<div className="space-y-8">
|
||||
<div className="grid grid-cols-3 gap-6">
|
||||
<div className="bg-green-50 dark:bg-green-500/10 border border-green-100 dark:border-green-500/20 rounded-[2rem] p-6 text-center shadow-sm">
|
||||
<div className="text-3xl font-black text-green-600 dark:text-green-400">{bulkResults.successful_emails.length}</div>
|
||||
<div className="text-[10px] uppercase tracking-[0.2em] text-green-700/50 dark:text-gray-500 font-black mt-1">Enrolled</div>
|
||||
</div>
|
||||
<div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl p-4 text-center">
|
||||
<div className="text-2xl font-black text-yellow-400">{bulkResults.already_enrolled_emails.length}</div>
|
||||
<div className="text-xs uppercase tracking-widest text-gray-500 font-bold mt-1">Skipped</div>
|
||||
<div className="bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-100 dark:border-yellow-500/20 rounded-[2rem] p-6 text-center shadow-sm">
|
||||
<div className="text-3xl font-black text-yellow-600 dark:text-yellow-400">{bulkResults.already_enrolled_emails.length}</div>
|
||||
<div className="text-[10px] uppercase tracking-[0.2em] text-yellow-700/50 dark:text-gray-500 font-black mt-1">Skipped</div>
|
||||
</div>
|
||||
<div className="bg-red-500/10 border border-red-500/20 rounded-xl p-4 text-center">
|
||||
<div className="text-2xl font-black text-red-400">{bulkResults.failed_emails.length}</div>
|
||||
<div className="text-xs uppercase tracking-widest text-gray-500 font-bold mt-1">Failed</div>
|
||||
<div className="bg-red-50 dark:bg-red-500/10 border border-red-100 dark:border-red-500/20 rounded-[2rem] p-6 text-center shadow-sm">
|
||||
<div className="text-3xl font-black text-red-600 dark:text-red-400">{bulkResults.failed_emails.length}</div>
|
||||
<div className="text-[10px] uppercase tracking-[0.2em] text-red-700/50 dark:text-gray-500 font-black mt-1">Failed</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{bulkResults.failed_emails.length > 0 && (
|
||||
<div>
|
||||
<p className="text-xs font-bold text-gray-500 uppercase tracking-widest mb-2">Failed Emails (Not Found):</p>
|
||||
<div className="bg-black/20 rounded-xl p-3 text-xs text-red-400 max-h-32 overflow-y-auto font-mono">
|
||||
<div className="space-y-3">
|
||||
<p className="text-[10px] font-black text-red-500/60 dark:text-gray-500 uppercase tracking-[0.2em]">Failed Emails (Not Found):</p>
|
||||
<div className="bg-red-50/50 dark:bg-black/20 border border-red-100 dark:border-white/10 rounded-2xl p-5 text-xs text-red-600 dark:text-red-400 max-h-48 overflow-y-auto font-mono custom-scrollbar leading-relaxed">
|
||||
{bulkResults.failed_emails.map(e => (
|
||||
<div key={e}>{e}</div>
|
||||
<div key={e} className="py-1 border-b border-red-500/5 last:border-0">{e}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -234,21 +241,21 @@ export default function GradebookPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="p-6 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5 flex justify-end gap-3">
|
||||
<div className="p-8 bg-slate-50/50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5 flex justify-end items-center gap-4">
|
||||
{!bulkResults ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setShowBulkEnroll(false)}
|
||||
className="px-6 py-2 rounded-xl hover:bg-slate-200 dark:hover:bg-white/5 transition-colors font-medium text-slate-600 dark:text-gray-400"
|
||||
className="px-8 py-3 rounded-2xl hover:bg-slate-200 dark:hover:bg-white/5 transition-all font-black text-[10px] uppercase tracking-widest text-slate-400 dark:text-gray-400 active:scale-95"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleBulkEnroll}
|
||||
disabled={bulkLoading || !bulkEmails.trim()}
|
||||
className="btn-premium px-8 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="flex items-center gap-3 px-10 py-3 bg-blue-600 hover:bg-blue-500 disabled:bg-slate-200 dark:disabled:bg-white/5 text-white disabled:text-slate-400 rounded-2xl font-black text-[10px] uppercase tracking-[0.2em] shadow-xl shadow-blue-500/20 transition-all active:scale-95 disabled:shadow-none disabled:cursor-not-allowed group"
|
||||
>
|
||||
{bulkLoading ? <Loader2 className="animate-spin w-4 h-4" /> : 'Procesar Inscripción'}
|
||||
{bulkLoading ? <Loader2 className="animate-spin w-4 h-4" /> : <CheckCircle size={16} className="group-hover:scale-110 transition-transform" />} Procesar Inscripción
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
@@ -258,7 +265,7 @@ export default function GradebookPage() {
|
||||
setBulkResults(null);
|
||||
setBulkEmails("");
|
||||
}}
|
||||
className="btn-premium px-8"
|
||||
className="btn-premium px-12 py-3 rounded-2xl font-black text-[10px] uppercase tracking-widest active:scale-95 shadow-xl shadow-blue-500/20"
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
@@ -274,41 +281,41 @@ export default function GradebookPage() {
|
||||
Registro de Calificaciones
|
||||
</h2>
|
||||
{/* Controls & Stats */}
|
||||
<div className="flex flex-col md:flex-row gap-6 justify-between items-center bg-white/5 border border-white/10 rounded-2xl p-6">
|
||||
<div className="flex items-center gap-4 w-full md:w-auto">
|
||||
<div className="relative">
|
||||
{/* Controls & Stats */}
|
||||
<div className="flex flex-col md:flex-row gap-8 justify-between items-stretch bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-[2.5rem] p-8 shadow-sm">
|
||||
<div className="flex flex-col sm:flex-row items-center gap-4 flex-1">
|
||||
<div className="relative w-full sm:w-auto">
|
||||
<Users size={16} className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 dark:text-gray-500 pointer-events-none z-10" />
|
||||
<select
|
||||
value={selectedCohortId}
|
||||
onChange={(e) => setSelectedCohortId(e.target.value)}
|
||||
className="appearance-none bg-slate-100 dark:bg-black/20 text-slate-900 dark:text-white border border-slate-200 dark:border-white/10 rounded-xl pl-4 pr-10 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/50 min-w-[200px]"
|
||||
className="appearance-none bg-slate-50 dark:bg-black/20 text-slate-900 dark:text-white border border-slate-200 dark:border-white/10 rounded-2xl pl-11 pr-10 py-3.5 text-xs font-black uppercase tracking-widest focus:outline-none focus:ring-2 focus:ring-blue-500/50 min-w-full sm:min-w-[240px] shadow-inner cursor-pointer"
|
||||
>
|
||||
<option value="">All Cohorts</option>
|
||||
{cohorts.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
|
||||
</select>
|
||||
<div className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none text-gray-500">
|
||||
▼
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex-1 md:w-64">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 w-4 h-4" />
|
||||
<div className="relative w-full flex-1">
|
||||
<Search className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 dark:text-gray-500 w-4 h-4" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search students..."
|
||||
placeholder="Find a student fast..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full bg-slate-100 dark:bg-black/20 border border-slate-200 dark:border-white/10 rounded-xl pl-10 pr-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/50 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-gray-600"
|
||||
className="w-full bg-slate-50 dark:bg-black/20 border border-slate-200 dark:border-white/10 rounded-2xl pl-11 pr-4 py-3.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/50 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-gray-600 font-bold shadow-inner"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-8 border-l border-white/10 pl-8">
|
||||
<div className="flex gap-10 border-l border-slate-100 dark:border-white/10 pl-10 items-center">
|
||||
<div>
|
||||
<p className="text-xs font-bold text-slate-500 dark:text-gray-500 uppercase tracking-wider mb-1">Students</p>
|
||||
<p className="text-2xl font-black text-slate-900 dark:text-white">{filteredStudents.length}</p>
|
||||
<p className="text-[10px] font-black text-slate-400 dark:text-gray-500 uppercase tracking-[0.2em] mb-1.5">Total Enrollment</p>
|
||||
<p className="text-3xl font-black text-slate-900 dark:text-white uppercase tracking-tighter">{filteredStudents.length}</p>
|
||||
</div>
|
||||
<div className="w-px h-10 bg-slate-100 dark:bg-white/5" />
|
||||
<div>
|
||||
<p className="text-xs font-bold text-gray-500 uppercase tracking-wider mb-1">Avg Score</p>
|
||||
<p className={`text-2xl font-black ${averageScore < 0.7 ? 'text-orange-400' : 'text-green-400'}`}>
|
||||
<p className="text-[10px] font-black text-slate-400 dark:text-gray-500 uppercase tracking-[0.2em] mb-1.5">Avg Performance</p>
|
||||
<p className={`text-3xl font-black tracking-tighter ${averageScore < 0.7 ? 'text-orange-500' : 'text-blue-600'}`}>
|
||||
{(averageScore * 100).toFixed(0)}%
|
||||
</p>
|
||||
</div>
|
||||
@@ -316,45 +323,45 @@ export default function GradebookPage() {
|
||||
</div>
|
||||
|
||||
{/* Student List */}
|
||||
<div className="rounded-3xl border border-white/10 bg-white/[0.02] overflow-hidden">
|
||||
<div className="rounded-[2.5rem] border border-slate-200 dark:border-white/10 bg-white dark:bg-white/[0.02] overflow-hidden shadow-sm">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-white/5 border-b border-white/5">
|
||||
<th className="p-6 text-xs font-black uppercase tracking-widest text-gray-500">Student</th>
|
||||
<th className="p-6 text-xs font-black uppercase tracking-widest text-gray-500">Progress</th>
|
||||
<th className="p-6 text-xs font-black uppercase tracking-widest text-gray-500">Avg. Score</th>
|
||||
<th className="p-6 text-xs font-black uppercase tracking-widest text-gray-500">Last Active</th>
|
||||
<th className="p-6 text-xs font-black uppercase tracking-widest text-gray-500 text-right">Status</th>
|
||||
<tr className="bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/5">
|
||||
<th className="p-6 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 dark:text-gray-500">Student</th>
|
||||
<th className="p-6 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 dark:text-gray-500">Learning Progress</th>
|
||||
<th className="p-6 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 dark:text-gray-500">Score Rating</th>
|
||||
<th className="p-6 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 dark:text-gray-500">Activity</th>
|
||||
<th className="p-6 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 dark:text-gray-500 text-right">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/5">
|
||||
<tbody className="divide-y divide-slate-100 dark:divide-white/5">
|
||||
{filteredStudents.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={5} className="p-12 text-center text-gray-600 italic">No students found.</td>
|
||||
</tr>
|
||||
) : filteredStudents.map((s) => (
|
||||
<tr key={s.user_id} className="hover:bg-white/[0.02] transition-colors group">
|
||||
<tr key={s.user_id} className="hover:bg-slate-50 dark:hover:bg-white/[0.02] transition-colors group">
|
||||
<td className="p-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center text-gray-900 dark:text-white font-bold text-sm">
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center text-white font-black text-lg shadow-lg shadow-blue-500/20">
|
||||
{s.full_name.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-bold text-gray-900 dark:text-white group-hover:text-blue-400 transition-colors">{s.full_name}</div>
|
||||
<div className="text-xs text-gray-500 flex items-center gap-1 mt-0.5">
|
||||
<Mail size={10} /> {s.email}
|
||||
<div className="font-black text-slate-900 dark:text-white group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors uppercase tracking-tight text-sm">{s.full_name}</div>
|
||||
<div className="text-[11px] text-slate-400 dark:text-gray-500 flex items-center gap-1.5 mt-1 font-medium italic">
|
||||
<Mail size={12} className="text-blue-400" /> {s.email}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-6 align-middle">
|
||||
<div className="w-full max-w-[140px]">
|
||||
<div className="flex justify-between text-xs mb-1 font-bold text-gray-400">
|
||||
<span>{(s.progress * 100).toFixed(0)}%</span>
|
||||
<div className="w-full max-w-[160px]">
|
||||
<div className="flex justify-between text-[10px] mb-2 font-black text-slate-400 uppercase tracking-widest">
|
||||
<span>{(s.progress * 100).toFixed(0)}% Complete</span>
|
||||
</div>
|
||||
<div className="h-1.5 bg-white/10 rounded-full overflow-hidden">
|
||||
<div className="h-2 bg-slate-100 dark:bg-white/10 rounded-full overflow-hidden shadow-inner">
|
||||
<div
|
||||
className="h-full bg-blue-500 rounded-full"
|
||||
className="h-full bg-gradient-to-r from-blue-600 to-blue-400 rounded-full shadow-lg shadow-blue-500/30 transition-all duration-500"
|
||||
style={{ width: `${s.progress * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
@@ -362,31 +369,34 @@ export default function GradebookPage() {
|
||||
</td>
|
||||
<td className="p-6 align-middle">
|
||||
{s.average_score !== null ? (
|
||||
<span className={`font-black ${(s.average_score || 0) >= 0.8 ? 'text-green-400' : (s.average_score || 0) >= 0.6 ? 'text-yellow-400' : 'text-red-400'}`}>
|
||||
{((s.average_score || 0) * 100).toFixed(0)}%
|
||||
</span>
|
||||
<div className="flex flex-col">
|
||||
<span className={`text-lg font-black tracking-tighter ${(s.average_score || 0) >= 0.8 ? 'text-green-600 dark:text-green-400' : (s.average_score || 0) >= 0.6 ? 'text-orange-500' : 'text-red-500'}`}>
|
||||
{((s.average_score || 0) * 100).toFixed(0)}%
|
||||
</span>
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-slate-400 mt-0.5">Weighted Avg</span>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-gray-600 text-xs italic">No grades</span>
|
||||
<span className="text-slate-400 dark:text-gray-600 text-[10px] font-black uppercase tracking-widest italic bg-slate-100 dark:bg-white/5 px-2 py-1 rounded-md">Pending</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="p-6 align-middle">
|
||||
<div className="text-sm text-gray-400 flex items-center gap-2">
|
||||
<Clock size={14} />
|
||||
{s.last_active_at ? new Date(s.last_active_at).toLocaleDateString() : 'Never'}
|
||||
<div className="text-xs text-slate-500 dark:text-gray-400 font-bold flex items-center gap-2 uppercase tracking-tight">
|
||||
<Clock size={16} className="text-slate-400" />
|
||||
{s.last_active_at ? new Date(s.last_active_at).toLocaleDateString() : 'No Activity'}
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-6 text-right align-middle">
|
||||
{s.progress >= 1 ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest bg-green-500/10 text-green-400 border border-green-500/20">
|
||||
<CheckCircle size={12} /> Completed
|
||||
<span className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full text-[10px] font-black uppercase tracking-[0.2em] bg-green-500/10 text-green-600 dark:text-green-400 border border-green-500/20 shadow-sm">
|
||||
<CheckCircle size={12} /> Graduated
|
||||
</span>
|
||||
) : s.last_active_at && (Date.now() - new Date(s.last_active_at).getTime() > 7 * 24 * 60 * 60 * 1000) ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest bg-red-500/10 text-red-400 border border-red-500/20">
|
||||
<AlertCircle size={12} /> Inactive
|
||||
<span className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full text-[10px] font-black uppercase tracking-[0.2em] bg-red-500/10 text-red-600 dark:text-red-400 border border-red-500/20 shadow-sm">
|
||||
<AlertCircle size={12} /> At Risk
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
<GraduationCap size={12} /> Active
|
||||
<span className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full text-[10px] font-black uppercase tracking-[0.2em] bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/20 shadow-sm">
|
||||
<GraduationCap size={12} /> Engaged
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user