Files
webval/eleve/dashboard.php

451 lines
15 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Dashboard élève (classe fixe + libre)
* Fichier : eleve/dashboard.php
*/
require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../config/database.php';
// Vérifier l'authentification
if (!isLoggedIn()) {
header('Location: ../login.php');
exit;
}
$user = currentUser();
// Vérifier que c'est bien un élève
if (!isEleve()) {
header('Location: ../login.php');
exit;
}
$db = Database::getInstance();
// Déterminer le type d'élève
$isEleveLibre = ($user['id_type'] == 3);
$isEleveClasse = ($user['id_type'] == 2);
// Récupérer les évaluations disponibles
if ($isEleveLibre) {
// Élève libre : évaluations de type soutien uniquement
$queryEvals = "SELECT DISTINCT e.*,
COALESCE(t.statut, 'non_commence') as statut_tentative,
t.note as note_obtenue,
t.date_debut as date_tentative
FROM evaluations e
INNER JOIN acces_evaluations ae ON e.id_evaluation = ae.id_evaluation
INNER JOIN classes c ON ae.id_classe = c.id_classe
LEFT JOIN tentatives_eleves t ON e.id_evaluation = t.id_evaluation
AND t.id_eleve = ?
WHERE c.type_classe = 'soutien'
AND ae.actif = 1
AND NOW() BETWEEN ae.date_debut AND ae.date_fin
AND e.actif = 1
ORDER BY ae.date_fin ASC, e.titre ASC";
$evaluations = $db->fetchAll($queryEvals, [$user['id_utilisateur']]);
} else {
// Élève classe fixe : évaluations de sa classe
if ($user['id_classe']) {
$queryEvals = "SELECT DISTINCT e.*,
ae.date_debut as debut_acces,
ae.date_fin as fin_acces,
COALESCE(t.statut, 'non_commence') as statut_tentative,
t.note as note_obtenue,
t.date_debut as date_tentative
FROM evaluations e
INNER JOIN acces_evaluations ae ON e.id_evaluation = ae.id_evaluation
LEFT JOIN tentatives_eleves t ON e.id_evaluation = t.id_evaluation
AND t.id_eleve = ?
WHERE ae.id_classe = ?
AND ae.actif = 1
AND NOW() BETWEEN ae.date_debut AND ae.date_fin
AND e.actif = 1
ORDER BY ae.date_fin ASC, e.titre ASC";
$evaluations = $db->fetchAll($queryEvals, [$user['id_utilisateur'], $user['id_classe']]);
} else {
$evaluations = [];
}
}
// Récupérer les statistiques de l'élève
$queryStats = "SELECT
COUNT(DISTINCT t.id_evaluation) as nb_evaluations_passees,
COUNT(CASE WHEN t.statut = 'terminee' THEN 1 END) as nb_evaluations_terminees,
AVG(
CASE WHEN t.statut = 'terminee'
THEN CEILING((t.note / e.note_totale * 20) * 2) / 2
ELSE NULL END
) as moyenne_generale
FROM tentatives_eleves t
INNER JOIN evaluations e ON t.id_evaluation = e.id_evaluation
WHERE t.id_eleve = ?";
$stats = $db->fetchOne($queryStats, [$user['id_utilisateur']]) ?? [
'nb_evaluations_passees' => 0,
'nb_evaluations_terminees' => 0,
'moyenne_generale' => null
];
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Élève - <?= htmlspecialchars($user['prenom'] . ' ' . $user['nom']) ?></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #f5f7fa;
min-height: 100vh;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 40px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header-content {
max-width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
}
.user-info h1 {
font-size: 24px;
margin-bottom: 5px;
}
.user-info p {
opacity: 0.9;
font-size: 14px;
}
.badge {
background: rgba(255,255,255,0.2);
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.logout-btn {
background: rgba(255,255,255,0.2);
border: 2px solid white;
color: white;
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s;
}
.logout-btn:hover {
background: white;
color: #667eea;
}
.container {
max-width: 1200px;
margin: 30px auto;
padding: 0 20px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 25px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-left: 4px solid #667eea;
}
.stat-card h3 {
color: #666;
font-size: 14px;
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.stat-card .value {
font-size: 32px;
font-weight: 700;
color: #333;
}
.section {
background: white;
border-radius: 12px;
padding: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 30px;
}
.section-title {
font-size: 22px;
color: #333;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #f0f0f0;
}
.eval-grid {
display: grid;
gap: 15px;
}
.eval-card {
border: 2px solid #e0e0e0;
border-radius: 10px;
padding: 20px;
transition: all 0.3s;
display: flex;
justify-content: space-between;
align-items: center;
}
.eval-card:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
transform: translateY(-2px);
}
.eval-info h3 {
color: #333;
margin-bottom: 8px;
font-size: 18px;
}
.eval-info p {
color: #666;
font-size: 14px;
margin-bottom: 5px;
}
.eval-actions {
display: flex;
gap: 10px;
align-items: center;
}
.btn {
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
font-size: 14px;
transition: all 0.3s;
border: none;
cursor: pointer;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: #666;
}
.btn-secondary:hover {
background: #e0e0e0;
}
.status-badge {
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.status-non-commence {
background: #e3f2fd;
color: #1976d2;
}
.status-en-cours {
background: #fff3e0;
color: #f57c00;
}
.status-termine {
background: #e8f5e9;
color: #388e3c;
}
.note-display {
font-size: 24px;
font-weight: 700;
color: #667eea;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
}
.alert {
padding: 15px 20px;
border-radius: 8px;
margin-bottom: 20px;
border-left: 4px solid;
}
.alert-info {
background: #e3f2fd;
border-color: #2196f3;
color: #1565c0;
}
</style>
</head>
<body>
<div class="header">
<div class="header-content">
<div class="user-info">
<h1>👋 Bonjour, <?= htmlspecialchars($user['prenom']) ?> !</h1>
<p>
<?php if ($isEleveLibre): ?>
<span class="badge">🎯 Groupe de Soutien</span>
<?php else: ?>
Classe : <?= htmlspecialchars($user['nom_classe'] ?? 'Non assigné') ?>
(<?= htmlspecialchars($user['niveau'] ?? '') ?>)
<?php endif; ?>
</p>
</div>
<a href="../logout.php" class="logout-btn">Déconnexion</a>
</div>
</div>
<div class="container">
<!-- STATISTIQUES -->
<div class="stats-grid">
<div class="stat-card">
<h3>📚 Évaluations passées</h3>
<div class="value"><?= $stats['nb_evaluations_passees'] ?></div>
</div>
<div class="stat-card">
<h3>✅ Évaluations terminées</h3>
<div class="value"><?= $stats['nb_evaluations_terminees'] ?></div>
</div>
<div class="stat-card">
<h3>📊 Moyenne générale</h3>
<div class="value">
<?= $stats['moyenne_generale'] !== null
? number_format($stats['moyenne_generale'], 2) . '/20'
: '-' ?>
</div>
</div>
</div>
<!-- INFO ÉLÈVE LIBRE -->
<?php if ($isEleveLibre): ?>
<div class="alert alert-info">
<strong> Mode Soutien :</strong>
Vous êtes inscrit dans le groupe de soutien. Les évaluations que vous passez ne comptent
pas dans votre bulletin scolaire, elles sont là pour vous entraîner et progresser.
</div>
<?php endif; ?>
<!-- ÉVALUATIONS DISPONIBLES -->
<div class="section">
<h2 class="section-title">📝 Évaluations disponibles</h2>
<?php if (empty($evaluations)): ?>
<div class="empty-state">
<p style="font-size: 18px; margin-bottom: 10px;">
Aucune évaluation disponible pour le moment
</p>
<p>Les nouvelles évaluations apparaîtront ici lorsque votre enseignant les publiera.</p>
</div>
<?php else: ?>
<div class="eval-grid">
<?php foreach ($evaluations as $eval): ?>
<div class="eval-card">
<div class="eval-info">
<h3><?= htmlspecialchars($eval['titre']) ?></h3>
<?php if (!empty($eval['description'])): ?>
<p><?= htmlspecialchars($eval['description']) ?></p>
<?php endif; ?>
<p>
<strong>Chapitre :</strong> <?= htmlspecialchars($eval['chapitre'] ?? 'Non spécifié') ?>
| <strong>Durée :</strong> <?= $eval['duree_minutes'] ?? 'Libre' ?> min
| <strong>Note :</strong> /<?= $eval['note_totale'] ?? 20 ?>
</p>
<?php if (isset($eval['fin_acces'])): ?>
<p style="color: #f57c00;">
⏰ Disponible jusqu'au <?= date('d/m/Y H:i', strtotime($eval['fin_acces'])) ?>
</p>
<?php endif; ?>
</div>
<div class="eval-actions">
<?php
$statut = $eval['statut_tentative'] ?? 'non_commence';
?>
<?php if ($statut === 'terminee'): ?>
<span class="note-display">
<?= number_format($eval['note_obtenue'], 2) ?>/<?= $eval['note_totale'] ?? 20 ?>
</span>
<span class="status-badge status-termine">✅ Terminé</span>
<a href="../resultats.php?id_evaluation=<?= $eval['id_evaluation'] ?>"
class="btn btn-secondary">
Voir le résultat
</a>
<?php elseif ($statut === 'en_cours'): ?>
<span class="status-badge status-en-cours">⏳ En cours</span>
<a href="../passer_evaluation.php?id_evaluation=<?= $eval['id_evaluation'] ?>"
class="btn btn-primary">
Reprendre
</a>
<?php else: ?>
<span class="status-badge status-non-commence">🆕 Nouveau</span>
<a href="../passer_evaluation.php?id_evaluation=<?= $eval['id_evaluation'] ?>"
class="btn btn-primary">
Commencer
</a>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</body>
</html>