mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-18 14:27:51 +00:00
- Alinha o visual das páginas com o padrão do StudentsPage - Ajusta espaçamentos, cores e tipografia - Melhora a consistência dos componentes de lista - Adiciona tratamento de erros uniforme - Padroniza os estados de loading e empty
121 lines
4.3 KiB
TypeScript
121 lines
4.3 KiB
TypeScript
import React from 'react';
|
|
import { Plus, Search, MoreVertical, GraduationCap } from 'lucide-react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useDatabase } from '../../../hooks/useDatabase';
|
|
import { supabase } from '../../../lib/supabase';
|
|
import type { Class } from '../../../types/database';
|
|
|
|
export function ClassesPage() {
|
|
const navigate = useNavigate();
|
|
const [classes, setClasses] = React.useState<Class[]>([]);
|
|
const [searchTerm, setSearchTerm] = React.useState('');
|
|
const [loading, setLoading] = React.useState(true);
|
|
const [error, setError] = React.useState<string | null>(null);
|
|
|
|
React.useEffect(() => {
|
|
const fetchClasses = async () => {
|
|
try {
|
|
const { data: { session } } = await supabase.auth.getSession();
|
|
if (!session?.user?.id) return;
|
|
|
|
const { data, error } = await supabase
|
|
.from('classes')
|
|
.select(`
|
|
*,
|
|
students:students(count),
|
|
teachers:teacher_classes(count)
|
|
`)
|
|
.eq('school_id', session.user.id);
|
|
|
|
if (error) throw error;
|
|
setClasses(data || []);
|
|
} catch (err) {
|
|
console.error('Erro ao buscar turmas:', err);
|
|
setError('Erro ao buscar turmas');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchClasses();
|
|
}, []);
|
|
|
|
const filteredClasses = classes.filter(classItem =>
|
|
classItem.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
classItem.grade.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<div className="flex justify-between items-center mb-6">
|
|
<h1 className="text-2xl font-bold text-gray-900">Turmas</h1>
|
|
<button
|
|
onClick={() => navigate('nova')}
|
|
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition"
|
|
>
|
|
<Plus className="h-5 w-5" />
|
|
Adicionar Turma
|
|
</button>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="mb-4 p-4 bg-red-50 text-red-600 rounded-lg">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
|
|
<div className="p-4 border-b border-gray-200">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-400" />
|
|
<input
|
|
type="text"
|
|
placeholder="Buscar turmas..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-purple-500 focus:border-purple-500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{loading ? (
|
|
<div className="p-8 text-center text-gray-500">Carregando...</div>
|
|
) : filteredClasses.length === 0 ? (
|
|
<div className="p-8 text-center text-gray-500">
|
|
{searchTerm ? 'Nenhuma turma encontrada' : 'Nenhuma turma cadastrada'}
|
|
</div>
|
|
) : (
|
|
<div className="divide-y divide-gray-200">
|
|
{filteredClasses.map((classItem) => (
|
|
<div
|
|
key={classItem.id}
|
|
className="p-4 hover:bg-gray-50 cursor-pointer"
|
|
onClick={() => navigate(`/dashboard/turmas/${classItem.id}`)}
|
|
>
|
|
<div className="flex justify-between items-center">
|
|
<div>
|
|
<h3 className="text-lg font-medium text-gray-900">
|
|
{classItem.name}
|
|
</h3>
|
|
<div className="flex items-center gap-2 text-sm text-gray-500">
|
|
<GraduationCap className="h-4 w-4" />
|
|
{classItem.grade} • {(classItem as any).students?.count || 0} alunos
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-6">
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
|
Ativo
|
|
</span>
|
|
<button className="p-2 hover:bg-gray-100 rounded-full">
|
|
<MoreVertical className="h-5 w-5 text-gray-400" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|