push calendar
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
|
||||
require __DIR__ . '/../includes/db.php';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT id, event_date AS date, event_type AS type, person_id, duration FROM pf_events ORDER BY event_date");
|
||||
$events = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'events' => $events,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Erreur lors de la récupération des événements : ' . $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require __DIR__ . '/../includes/db.php';
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!isset($input['action']) || !isset($input['event_id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Action ou ID manquant.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $input['action'];
|
||||
$eventId = $input['event_id'];
|
||||
|
||||
try {
|
||||
if ($action === 'delete') {
|
||||
$stmt = $pdo->prepare("DELETE FROM pf_events WHERE id = ?");
|
||||
$stmt->execute([$eventId]);
|
||||
echo json_encode(['status' => 'success', 'message' => 'Événement supprimé.']);
|
||||
|
||||
} elseif ($action === 'update' && isset($input['new_type'])) {
|
||||
$stmt = $pdo->prepare("UPDATE pf_events SET event_type = ? WHERE id = ?");
|
||||
$stmt->execute([$input['new_type'], $eventId]);
|
||||
echo json_encode(['status' => 'success', 'message' => 'Événement mis à jour.']);
|
||||
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Action non valide ou données manquantes.']);
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require __DIR__ . '/../includes/db.php';
|
||||
|
||||
$eventsToSave = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($eventsToSave) || !is_array($eventsToSave)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Aucune donnée d\'événement reçue.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$inserted = [];
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$sql = "INSERT INTO pf_events (event_date, event_type, person_id, duration)
|
||||
VALUES (:event_date, :event_type, :person_id, :duration)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
foreach ($eventsToSave as $event) {
|
||||
$person_id = null;
|
||||
|
||||
// Si un nom de personne est fourni
|
||||
if (!empty($event['person'])) {
|
||||
$personStmt = $pdo->prepare("SELECT id FROM pf_people WHERE name = ?");
|
||||
$personStmt->execute([$event['person']]);
|
||||
$personRow = $personStmt->fetch();
|
||||
if ($personRow) {
|
||||
$person_id = $personRow['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$stmt->execute([
|
||||
':event_date' => $event['date'],
|
||||
':event_type' => $event['type'],
|
||||
':person_id' => $person_id,
|
||||
':duration' => $event['duration'] ?? 1.0,
|
||||
]);
|
||||
|
||||
$inserted[] = [
|
||||
'id' => $pdo->lastInsertId(),
|
||||
'date' => $event['date'],
|
||||
'type' => $event['type'],
|
||||
'duration' => $event['duration'] ?? 1.0,
|
||||
'person_id' => $person_id,
|
||||
];
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'inserted' => $inserted,
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
http_response_code(500);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Erreur lors de la sauvegarde : ' . $e->getMessage()]);
|
||||
}
|
||||
+128
-5
@@ -83,6 +83,31 @@ body {
|
||||
}
|
||||
|
||||
/* === CARDS & FLEX === */
|
||||
|
||||
.pf-card.pf-card--wide {
|
||||
min-width: 400px; /* tu peux monter à 500 ou 600 selon ton goût */
|
||||
flex: 1 1 400px; /* laisse la carte prendre plus de place dans la ligne */
|
||||
}
|
||||
/* Le tableau des vacances occupe toute la largeur disponible */
|
||||
#schoolHolidaysTable {
|
||||
width: auto;
|
||||
table-layout: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.pf-card.pf-card--wide .pf-table-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
/* En-têtes et cellules sans retour à la ligne */
|
||||
#schoolHolidaysTable th,
|
||||
#schoolHolidaysTable td {
|
||||
white-space: nowrap; /* pas de retour à la ligne dans les cellules */
|
||||
overflow: visible; /* pas de tronquage */
|
||||
padding: 4px 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pf-flex {
|
||||
display: flex;
|
||||
}
|
||||
@@ -121,6 +146,59 @@ label {
|
||||
}
|
||||
|
||||
/* === TABLES === */
|
||||
|
||||
/* Appliquer un layout fixe pour harmoniser la largeur des colonnes */
|
||||
#planningTable {
|
||||
table-layout: fixed;
|
||||
width: 100%; /* le tableau prend toute la largeur disponible */
|
||||
}
|
||||
|
||||
/* Colonnes : texte centré et césures possibles */
|
||||
#planningTable th,
|
||||
#planningTable td {
|
||||
text-align: center;
|
||||
white-space: nowrap; /* évite les retours à la ligne sauvages */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis; /* coupe avec "..." si le texte déborde */
|
||||
}
|
||||
|
||||
/* Colonnes "Mois" et "Semaine" un peu plus étroites */
|
||||
#planningTable th:nth-child(1),
|
||||
#planningTable td:nth-child(1) {
|
||||
width: 2%; /* Mois */
|
||||
}
|
||||
|
||||
#planningTable th:nth-child(2),
|
||||
#planningTable td:nth-child(2) {
|
||||
width: 2%; /* Semaine */
|
||||
}
|
||||
|
||||
/* Colonnes jours (Lundi à Vendredi) réparties sur une largeur raisonnable */
|
||||
#planningTable th:nth-child(3),
|
||||
#planningTable td:nth-child(3),
|
||||
#planningTable th:nth-child(4),
|
||||
#planningTable td:nth-child(4),
|
||||
#planningTable th:nth-child(5),
|
||||
#planningTable td:nth-child(5),
|
||||
#planningTable th:nth-child(6),
|
||||
#planningTable td:nth-child(6),
|
||||
#planningTable th:nth-child(7),
|
||||
#planningTable td:nth-child(7) {
|
||||
width: 2%; /* ajustable selon ton rendu */
|
||||
}
|
||||
|
||||
/* Colonnes de totaux (Off / Extra / Centre / Avis) un peu plus compactes */
|
||||
#planningTable th:nth-child(8),
|
||||
#planningTable td:nth-child(8),
|
||||
#planningTable th:nth-child(9),
|
||||
#planningTable td:nth-child(9),
|
||||
#planningTable th:nth-child(10),
|
||||
#planningTable td:nth-child(10),
|
||||
#planningTable th:nth-child(11),
|
||||
#planningTable td:nth-child(11) {
|
||||
width: 4%;
|
||||
}
|
||||
|
||||
.pf-table-wrapper {
|
||||
max-height: 600px;
|
||||
overflow: auto;
|
||||
@@ -166,11 +244,6 @@ input[type="number"] {
|
||||
background: #ffe0e0;
|
||||
}
|
||||
|
||||
/* Jour de vacances scolaires dans le calendrier */
|
||||
.fc-day--school-holiday {
|
||||
background-color: #fff5cc; /* choisis le jaune qui te convient */
|
||||
}
|
||||
|
||||
.fc-row--bank-holiday {
|
||||
background: #d9f7be;
|
||||
}
|
||||
@@ -242,3 +315,53 @@ input[type="number"] {
|
||||
background-color: #f0f4f8;
|
||||
border-color: #b0c4de;
|
||||
}
|
||||
|
||||
/* --- Couleurs de base pour la légende et les jours --- */
|
||||
.fc-day--school-holiday {
|
||||
background-color: #e5d9f2;
|
||||
}
|
||||
.fc-day--public-holiday {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
.fc-day--off-carole {
|
||||
background-color: #ffe9a7;
|
||||
}
|
||||
.fc-day--extra-off-carole {
|
||||
background-color: #ffd59b;
|
||||
}
|
||||
.fc-day--has-guard {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Bordure verte pour Centre */
|
||||
.fc-day--has-guard.fc-day--centre {
|
||||
border: 2px solid #4caf50;
|
||||
}
|
||||
/* Bordure bleue pour Avis */
|
||||
.fc-day--has-guard.fc-day--avis {
|
||||
border: 2px solid #2196f3;
|
||||
}
|
||||
|
||||
/* --- Combinaisons avec dégradés --- */
|
||||
/* Combinaison Vacances + Off Carole */
|
||||
.fc-day--school-holiday.fc-day--off-carole {
|
||||
background-image: linear-gradient(45deg, #e5d9f2 49%, #ffe9a7 51%);
|
||||
}
|
||||
/* Combinaison Vacances + Extra Off Carole */
|
||||
.fc-day--school-holiday.fc-day--extra-off-carole {
|
||||
background-image: linear-gradient(45deg, #e5d9f2 49%, #ffd59b 51%);
|
||||
}
|
||||
|
||||
/* Eléments pour la légende */
|
||||
.pf-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.pf-legend-color {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #ccc;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
+758
-399
File diff suppressed because it is too large
Load Diff
+80
-93
@@ -1,68 +1,98 @@
|
||||
<?php
|
||||
// debug temporaire si besoin
|
||||
// ini_set('display_errors', 1);
|
||||
// ini_set('display_startup_errors', 1);
|
||||
// error_reporting(E_ALL);
|
||||
// Active l'affichage des erreurs pour le développement
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// On se connecte à la base de données
|
||||
require __DIR__ . '/includes/db.php';
|
||||
|
||||
// --- On récupère TOUS les événements sauvegardés en base ---
|
||||
$stmt_events = $pdo->query("SELECT * FROM pf_events");
|
||||
$dbEvents = $stmt_events->fetchAll();
|
||||
|
||||
// --- Configuration de la page ---
|
||||
$pageTitle = "PachaFamily - Family Calendar";
|
||||
$activePage = "family-calendar";
|
||||
require __DIR__ . '/header.php';
|
||||
?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- INJECTION DES DONNÉES DU SERVEUR VERS JAVASCRIPT -->
|
||||
<!-- Cette variable `serverData` sera lue par le script JS au démarrage. -->
|
||||
<!-- ===================================================================== -->
|
||||
<script>
|
||||
const serverData = <?php echo json_encode($dbEvents, JSON_NUMERIC_CHECK); ?>;
|
||||
</script>
|
||||
|
||||
<h1>Family Calendar</h1>
|
||||
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- PANNEAU DE CONTRÔLE : Légende, Récapitulatif et Vacances -->
|
||||
<!-- ===================================================================== -->
|
||||
<section class="pf-section pf-section--panel">
|
||||
<div class="pf-flex pf-flex--wrap pf-gap-lg">
|
||||
|
||||
<!-- LÉGENDE -->
|
||||
<div class="pf-card pf-card--small">
|
||||
<h2 class="pf-card-title">Soldes initiaux</h2>
|
||||
<h2 class="pf-card-title">Légende</h2>
|
||||
<div class="pf-card-body">
|
||||
<p><strong>Alex</strong></p>
|
||||
<label>CP :
|
||||
<input id="alexCpInit" type="number" step="0.25" value="24.5">
|
||||
</label><br>
|
||||
<label>RTT :
|
||||
<input id="alexRttInit" type="number" step="0.25" value="1.5">
|
||||
</label><br>
|
||||
<label>JA :
|
||||
<input id="alexJaInit" type="number" step="0.25" value="1">
|
||||
</label>
|
||||
|
||||
<p><strong>Laia</strong></p>
|
||||
<label>CP :
|
||||
<input id="laiaCpInit" type="number" step="0.25" value="19">
|
||||
</label><br>
|
||||
<label>RTT :
|
||||
<input id="laiaRttInit" type="number" step="0.25" value="4">
|
||||
</label><br>
|
||||
<label>JA :
|
||||
<input id="laiaJaInit" type="number" step="0.25" value="4">
|
||||
</label>
|
||||
<div class="pf-legend-item">
|
||||
<div class="pf-legend-color fc-day--school-holiday"></div>
|
||||
<span>Vacances scolaires</span>
|
||||
</div>
|
||||
<div class="pf-legend-item">
|
||||
<div class="pf-legend-color fc-day--public-holiday"></div>
|
||||
<span>Jour férié</span>
|
||||
</div>
|
||||
<div class="pf-legend-item">
|
||||
<div class="pf-legend-color fc-day--off-carole"></div>
|
||||
<span>Off Carole</span>
|
||||
</div>
|
||||
<div class="pf-legend-item">
|
||||
<div class="pf-legend-color fc-day--extra-off-carole"></div>
|
||||
<span>Extra Off Carole</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RÉCAPITULATIF ANNUEL -->
|
||||
<div class="pf-card pf-card--small">
|
||||
<h2 class="pf-card-title">Filtres</h2>
|
||||
<div class="pf-card-body">
|
||||
<label>
|
||||
<input id="showOnlyCaroleOff" type="checkbox">
|
||||
Voir uniquement les semaines ou Carole est en conges
|
||||
</label><br>
|
||||
<label>
|
||||
<input id="showOnlySchoolHoliday" type="checkbox">
|
||||
Voir uniquement les vacances scolaires
|
||||
</label>
|
||||
<h2 class="pf-card-title">Récapitulatif annuel</h2>
|
||||
<div class="pf-card-body" id="globalSummary">
|
||||
<!-- Rempli par le JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pf-card pf-card--small">
|
||||
<h2 class="pf-card-title">Resume</h2>
|
||||
<div class="pf-card-body" id="summaryText">
|
||||
<!-- Rempli par JS -->
|
||||
</div>
|
||||
<!-- VACANCES SCOLAIRES -->
|
||||
<div class="pf-card pf-card--small pf-card--wide">
|
||||
<h2 class="pf-card-title">Vacances scolaires - Zone C (2025-2026)</h2>
|
||||
<div class="pf-card-body">
|
||||
<div class="pf-table-wrapper">
|
||||
<table id="schoolHolidaysTable" class="fc-holidays-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Période</th>
|
||||
<th>Du</th>
|
||||
<th>Au</th>
|
||||
<th>Zones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Rempli par JS -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- PLANNING PRINCIPAL -->
|
||||
<!-- ===================================================================== -->
|
||||
<section class="pf-section">
|
||||
<h2>Planning par semaine</h2>
|
||||
<div class="pf-table-wrapper">
|
||||
@@ -80,69 +110,26 @@ require __DIR__ . '/header.php';
|
||||
<th># Extra off Carole</th>
|
||||
<th>#Centre</th>
|
||||
<th>#Avis</th>
|
||||
<th colspan="2">Alex</th>
|
||||
<th colspan="2">Laia</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>jours</th>
|
||||
<th>jours</th>
|
||||
<th>jours</th>
|
||||
<th>jours</th>
|
||||
<th>Total</th>
|
||||
<th>Détail</th>
|
||||
<th>Total</th>
|
||||
<th>Détail</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="planningBody">
|
||||
<!-- Rempli par family-calendar.js -->
|
||||
<!-- Le contenu de ce tableau est entièrement généré par family-calendar.js -->
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="selectionMenu" class="fc-selection-menu">
|
||||
<div class="fc-menu-section">
|
||||
<strong>Congé Carole</strong>
|
||||
<button data-type="OFF_CAROLE"># Off Carole</button>
|
||||
<button data-type="EXTRA_OFF_CAROLE"># Extra off Carole</button>
|
||||
</div>
|
||||
<div class="fc-menu-section">
|
||||
<strong>Mode de Garde</strong>
|
||||
<button data-type="CENTRE"># Centre</button>
|
||||
<button data-type="AVIS"># Avis</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="pf-section">
|
||||
<h2>Vacances scolaires - Zone C (2025-2026)</h2>
|
||||
<p>Source : data.education.gouv.fr - calendrier officiel.</p>
|
||||
<div class="pf-table-wrapper">
|
||||
<table id="schoolHolidaysTable" class="fc-holidays-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Période</th>
|
||||
<th>Du</th>
|
||||
<th>Au</th>
|
||||
<th>Zones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Rempli par JS -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Le menu contextuel est caché par défaut et son contenu est généré par JS -->
|
||||
<div id="selectionMenu" class="fc-selection-menu"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- CHARGEMENT DU SCRIPT JAVASCRIPT PRINCIPAL -->
|
||||
<!-- ===================================================================== -->
|
||||
<script src="/assets/js/family-calendar.js"></script>
|
||||
|
||||
|
||||
<?php
|
||||
// Inclusion du pied de page
|
||||
require __DIR__ . '/footer.php';
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
// Activer erreurs
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Détection de l'environnement
|
||||
$isLocal = (strpos($_SERVER['HTTP_HOST'] ?? 'localhost', 'localhost') !== false ||
|
||||
strpos($_SERVER['HTTP_HOST'] ?? '', '127.0.0.1') !== false ||
|
||||
strpos($_SERVER['HTTP_HOST'] ?? '', '::1') !== false);
|
||||
|
||||
if ($isLocal) {
|
||||
// Configuration XAMPP local
|
||||
$host = 'localhost';
|
||||
$db = 'percolo314'; // Même nom que sur OVH pour simplifier
|
||||
$user = 'root';
|
||||
$pass = ''; // Généralement vide sur XAMPP
|
||||
} else {
|
||||
// Configuration serveur OVH
|
||||
$host = 'percolo314.mysql.db';
|
||||
$db = 'percolo314';
|
||||
$user = 'percolo314';
|
||||
$pass = 'Wxcvbn99';
|
||||
}
|
||||
|
||||
$charset = 'utf8mb4';
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_general_ci",
|
||||
PDO::ATTR_TIMEOUT => 30,
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
|
||||
// Forcer la collation
|
||||
$pdo->exec("SET collation_connection = utf8mb4_general_ci");
|
||||
$pdo->exec("SET collation_database = utf8mb4_general_ci");
|
||||
$pdo->exec("SET collation_server = utf8mb4_general_ci");
|
||||
|
||||
// Debug optionnel (à commenter en production)
|
||||
// $env = $isLocal ? 'LOCAL' : 'SERVEUR';
|
||||
// echo "<!-- Connecté en $env sur $host/$db -->";
|
||||
|
||||
} catch (\PDOException $e) {
|
||||
$environment = $isLocal ? 'local (XAMPP)' : 'serveur (OVH)';
|
||||
die("Erreur de connexion ($environment) : " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user