feat: adiciona página de conquistas do aluno

- Cria componente AchievementsPage para exibir conquistas do aluno
- Implementa componentes Card e Badge para UI
- Adiciona mock inicial de conquistas para demonstração
- Corrige caminhos de importação relativos
This commit is contained in:
Lucas Santana 2024-12-20 18:01:12 -03:00
parent 5573274ad4
commit f70585e9c1
8 changed files with 238 additions and 23 deletions

View File

@ -0,0 +1,41 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
export function StudentDashboardNavbar() {
const location = useLocation();
return (
<nav className="bg-white border-b border-gray-200">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<div className="flex items-center gap-8">
<Link
to="/aluno"
className={`text-gray-900 hover:text-purple-600 ${
location.pathname === '/aluno' ? 'text-purple-600' : ''
}`}
>
Dashboard
</Link>
<Link
to="/aluno/historias"
className={`text-gray-900 hover:text-purple-600 ${
location.pathname.includes('/aluno/historias') ? 'text-purple-600' : ''
}`}
>
Histórias
</Link>
<Link
to="/aluno/configuracoes"
className={`text-gray-900 hover:text-purple-600 ${
location.pathname === '/aluno/configuracoes' ? 'text-purple-600' : ''
}`}
>
Configurações
</Link>
</div>
</div>
</div>
</nav>
);
}

View File

@ -0,0 +1,34 @@
import React from 'react';
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: 'default' | 'success' | 'warning' | 'error' | 'secondary';
children: React.ReactNode;
}
const variantStyles = {
default: 'bg-primary text-primary-foreground',
success: 'bg-green-100 text-green-800',
warning: 'bg-yellow-100 text-yellow-800',
error: 'bg-red-100 text-red-800',
secondary: 'bg-gray-100 text-gray-800'
};
export function Badge({
variant = 'default',
className = '',
children,
...props
}: BadgeProps): JSX.Element {
return (
<div
className={`
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
${variantStyles[variant]}
${className}
`}
{...props}
>
{children}
</div>
);
}

View File

@ -0,0 +1,16 @@
import React from 'react';
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
}
export function Card({ className = '', children, ...props }: CardProps): JSX.Element {
return (
<div
className={`bg-white rounded-lg shadow-sm border border-gray-200 ${className}`}
{...props}
>
{children}
</div>
);
}

View File

@ -0,0 +1,14 @@
import { Outlet } from 'react-router-dom';
import { StudentDashboardNavbar } from '@/components/student/StudentDashboardNavbar';
import React from 'react';
export function StudentDashboardLayout() {
return (
<div className="min-h-screen bg-gray-50">
<StudentDashboardNavbar />
<main className="container mx-auto px-4 py-8">
<Outlet />
</main>
</div>
);
}

View File

@ -0,0 +1,86 @@
import React from 'react';
import { Card } from '../../components/ui/card';
import { Badge } from '../../components/ui/badge';
interface Achievement {
id: string;
titulo: string;
descricao: string;
icone: string;
conquistado: boolean;
dataConquista?: string;
progresso?: number;
}
const conquistas: Achievement[] = [
{
id: '1',
titulo: 'Primeira História',
descricao: 'Completou sua primeira história',
icone: '📚',
conquistado: true,
dataConquista: '2024-03-15',
},
{
id: '2',
titulo: 'Leitor Dedicado',
descricao: 'Leu histórias por 5 dias seguidos',
icone: '🌟',
conquistado: false,
progresso: 3,
},
{
id: '3',
titulo: 'Explorador de Mundos',
descricao: 'Leu histórias de 5 categorias diferentes',
icone: '🌍',
conquistado: false,
progresso: 2,
},
];
export function AchievementsPage(): JSX.Element {
return (
<div className="container mx-auto p-6">
<div className="mb-8">
<h1 className="text-3xl font-bold text-primary mb-2">Minhas Conquistas</h1>
<p className="text-gray-600">
Continue lendo e completando atividades para desbloquear mais conquistas!
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{conquistas.map((conquista) => (
<Card key={conquista.id} className={`p-6 ${!conquista.conquistado ? 'opacity-75' : ''}`}>
<div className="flex items-start justify-between mb-4">
<span className="text-4xl">{conquista.icone}</span>
{conquista.conquistado ? (
<Badge variant="success">Conquistado!</Badge>
) : (
<Badge variant="secondary">Em progresso</Badge>
)}
</div>
<h3 className="text-xl font-semibold mb-2">{conquista.titulo}</h3>
<p className="text-gray-600 mb-4">{conquista.descricao}</p>
{conquista.progresso !== undefined && (
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div
className="bg-primary h-2.5 rounded-full transition-all"
style={{ width: `${(conquista.progresso / 5) * 100}%` }}
/>
</div>
)}
{conquista.dataConquista && (
<p className="text-sm text-gray-500 mt-4">
Conquistado em: {new Date(conquista.dataConquista).toLocaleDateString('pt-BR')}
</p>
)}
</Card>
))}
</div>
</div>
);
}

View File

@ -17,10 +17,13 @@ import { SettingsPage } from './pages/dashboard/settings/SettingsPage';
import { StudentDashboardPage } from './pages/student-dashboard/StudentDashboardPage';
import { StudentDashboardLayout } from './pages/student-dashboard/StudentDashboardLayout';
import { StudentStoriesPage } from './pages/student-dashboard/StudentStoriesPage';
import { StudentSettingsPage } from './pages/student-dashboard/StudentSettingsPage';
import { CreateStoryPage } from './pages/student-dashboard/CreateStoryPage';
import { StoryPage } from './pages/student-dashboard/StoryPage';
import { ProtectedRoute } from './components/auth/ProtectedRoute';
import { UserManagementPage } from './pages/admin/UserManagementPage';
import { AchievementsPage } from './pages/student-dashboard/AchievementsPage';
import { StudentClassPage } from './pages/student-dashboard/StudentClassPage';
export const router = createBrowserRouter([
{
@ -155,6 +158,18 @@ export const router = createBrowserRouter([
element: <StoryPage />,
}
]
},
{
path: 'configuracoes',
element: <StudentSettingsPage />,
},
{
path: 'conquistas',
element: <AchievementsPage />,
},
{
path: 'turmas/:classId',
element: <StudentClassPage />,
}
]
},

View File

@ -19,6 +19,7 @@ import { StoryPage } from '../pages/story/StoryPage';
import { StudentSettingsPage } from '../pages/student-dashboard/StudentSettingsPage';
import { StudentDashboardLayout } from '../pages/student-dashboard/StudentDashboardLayout';
import { StudentDashboard, StudentClassPage } from '../pages/student-dashboard';
import { AchievementsPage } from '../pages/student-dashboard/AchievementsPage';
import React from 'react';
export const router = createBrowserRouter([
@ -35,7 +36,7 @@ export const router = createBrowserRouter([
element: <StoryPage demo={true} />
},
{
path: '/login',
path: 'login',
children: [
{
path: 'school',
@ -52,7 +53,7 @@ export const router = createBrowserRouter([
]
},
{
path: '/register',
path: 'register',
children: [
{
path: 'school',
@ -70,7 +71,7 @@ export const router = createBrowserRouter([
]
},
{
path: '/dashboard',
path: 'dashboard',
element: <DashboardLayout />,
children: [
{
@ -119,31 +120,39 @@ export const router = createBrowserRouter([
]
},
{
path: '/auth/callback',
path: 'auth/callback',
element: <AuthCallback />
},
{
path: '/story/:storyId',
path: 'story/:storyId',
element: <StoryPage />
},
],
},
{
path: '/aluno',
element: <StudentDashboardLayout />,
children: [
{
index: true,
element: <StudentDashboard />,
},
{
path: 'configuracoes',
element: <StudentSettingsPage />
},
{
path: 'turmas/:classId',
element: <StudentClassPage />
path: 'aluno',
element: <StudentDashboardLayout />,
children: [
{
index: true,
element: <StudentDashboard />,
},
{
path: 'configuracoes',
element: <StudentSettingsPage />,
},
{
path: 'conquistas',
element: <AchievementsPage />,
},
{
path: 'historias/:id',
element: <StoryPage />,
},
{
path: 'turmas/:classId',
element: <StudentClassPage />,
}
]
}
]
],
}
]);
]);