summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--public/js/calendar.js8
-rw-r--r--public/js/calendar_admin.js49
-rw-r--r--src/load-events.php108
3 files changed, 116 insertions, 49 deletions
diff --git a/public/js/calendar.js b/public/js/calendar.js
index af9ffb4..f1c55c4 100644
--- a/public/js/calendar.js
+++ b/public/js/calendar.js
@@ -5,6 +5,7 @@ document.addEventListener('DOMContentLoaded', function(){
5 const calendar = new FullCalendar.Calendar(calendarEl,{ 5 const calendar = new FullCalendar.Calendar(calendarEl,{
6 editable: true, 6 editable: true,
7 locale: 'fr', 7 locale: 'fr',
8 //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays
8 initialView: 'dayGridMonth', 9 initialView: 'dayGridMonth',
9 headerToolbar:{ 10 headerToolbar:{
10 left: 'prev,next today', 11 left: 'prev,next today',
@@ -32,6 +33,8 @@ document.addEventListener('DOMContentLoaded', function(){
32 slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés 33 slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés
33 allDayContent: 'Journée', // texte dans la case "toute la journée" 34 allDayContent: 'Journée', // texte dans la case "toute la journée"
34 nowIndicator: true, // barre rouge pour maintenant 35 nowIndicator: true, // barre rouge pour maintenant
36
37 events: '../src/load-events.php', // fichier PHP qui retourne les événements
35 38
36 select: function(info){ 39 select: function(info){
37 selected_start_string = info.startStr; // variable "globale" 40 selected_start_string = info.startStr; // variable "globale"
@@ -47,7 +50,7 @@ document.addEventListener('DOMContentLoaded', function(){
47 return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') 50 return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0')
48 + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); 51 + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'));
49 } 52 }
50 function getEndMinusOneDay(date){ 53 function minusOneDay(date){
51 date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur 54 date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur
52 return date; 55 return date;
53 } 56 }
@@ -56,7 +59,7 @@ document.addEventListener('DOMContentLoaded', function(){
56 const start_date = start.split('T')[0]; 59 const start_date = start.split('T')[0];
57 const start_hour = (info.event.allDay ? '' : '<br>à ' + start.split('T')[1]).replace(":", "h"); 60 const start_hour = (info.event.allDay ? '' : '<br>à ' + start.split('T')[1]).replace(":", "h");
58 const formated_start = 'le ' + start_date.split('-')[2] + '/' + start_date.split('-')[1] + '/' + start_date.split('-')[0] + start_hour; 61 const formated_start = 'le ' + start_date.split('-')[2] + '/' + start_date.split('-')[1] + '/' + start_date.split('-')[0] + start_hour;
59 const end = formatDate(info.event.allDay ? getEndMinusOneDay(info.event.end) : info.event.end, info.event.allDay); 62 const end = formatDate(info.event.allDay ? minusOneDay(info.event.end) : info.event.end, info.event.allDay);
60 const end_date = end.split('T')[0]; 63 const end_date = end.split('T')[0];
61 const end_hour = (info.event.allDay ? '' : '<br>à ' + end.split('T')[1]).replace(":", "h"); 64 const end_hour = (info.event.allDay ? '' : '<br>à ' + end.split('T')[1]).replace(":", "h");
62 const formated_end = 'le ' + end_date.split('-')[2] + '/' + end_date.split('-')[1] + '/' + end_date.split('-')[0] + end_hour; 65 const formated_end = 'le ' + end_date.split('-')[2] + '/' + end_date.split('-')[1] + '/' + end_date.split('-')[0] + end_hour;
@@ -78,7 +81,6 @@ document.addEventListener('DOMContentLoaded', function(){
78 } 81 }
79 }, 82 },
80 //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) 83 //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date)
81 events: '../src/load-events.php' // fichier PHP qui retourne les événements
82 }); 84 });
83 85
84 function hideModal(){ 86 function hideModal(){
diff --git a/public/js/calendar_admin.js b/public/js/calendar_admin.js
index 253d127..8fe91a3 100644
--- a/public/js/calendar_admin.js
+++ b/public/js/calendar_admin.js
@@ -1,10 +1,12 @@
1document.addEventListener('DOMContentLoaded', function(){ 1document.addEventListener('DOMContentLoaded', function(){
2 const calendarEl = document.getElementById('calendar'); 2 const calendarEl = document.getElementById('calendar');
3 let selected_start_string = null; 3 let selected_start_string = null;
4 let event_selected = false; // pour event.remove()
4 5
5 const calendar = new FullCalendar.Calendar(calendarEl,{ 6 const calendar = new FullCalendar.Calendar(calendarEl,{
6 editable: true, 7 editable: true,
7 locale: 'fr', 8 locale: 'fr',
9 //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays
8 initialView: 'dayGridMonth', 10 initialView: 'dayGridMonth',
9 headerToolbar:{ 11 headerToolbar:{
10 left: 'prev,next today', 12 left: 'prev,next today',
@@ -32,9 +34,12 @@ document.addEventListener('DOMContentLoaded', function(){
32 slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés 34 slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés
33 allDayContent: 'Journée', // texte dans la case "toute la journée" 35 allDayContent: 'Journée', // texte dans la case "toute la journée"
34 nowIndicator: true, // barre rouge pour maintenant 36 nowIndicator: true, // barre rouge pour maintenant
37
38 events: '../src/load-events.php', // fichier PHP qui retourne les événements
35 39
36 select: function(info){ 40 select: function(info){
37 selected_start_string = info.startStr; // variable "globale" 41 selected_start_string = info.startStr; // variable "globale"
42 event_selected = false;
38 const aside = document.querySelector('aside'); 43 const aside = document.querySelector('aside');
39 let checked = ''; 44 let checked = '';
40 let input = 'datetime-local'; 45 let input = 'datetime-local';
@@ -107,6 +112,7 @@ document.addEventListener('DOMContentLoaded', function(){
107 }, 112 },
108 //unselect: function(event, view){}, 113 //unselect: function(event, view){},
109 eventClick: function(info){ 114 eventClick: function(info){
115 event_selected = true; // variable "globale"
110 const aside = document.querySelector('aside'); 116 const aside = document.querySelector('aside');
111 const checked = info.event.allDay ? 'checked' : ''; 117 const checked = info.event.allDay ? 'checked' : '';
112 const input = info.event.allDay ? 'date' : 'datetime-local'; 118 const input = info.event.allDay ? 'date' : 'datetime-local';
@@ -116,13 +122,13 @@ document.addEventListener('DOMContentLoaded', function(){
116 return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') 122 return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0')
117 + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); 123 + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'));
118 } 124 }
119 function getEndMinusOneDay(date){ 125 function minusOneDay(date){
120 date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur 126 date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur
121 return date; 127 return date;
122 } 128 }
123 129
124 const formated_start = formatDate(info.event.start); 130 const formated_start = formatDate(info.event.start);
125 const formated_end = formatDate(info.event.allDay ? getEndMinusOneDay(info.event.end) : info.event.end, info.event.allDay); 131 const formated_end = formatDate(info.event.allDay ? minusOneDay(info.event.end) : info.event.end, info.event.allDay);
126 132
127 const aside_content = `<div class="form_event"> 133 const aside_content = `<div class="form_event">
128 <div class="event_title_box"> 134 <div class="event_title_box">
@@ -155,6 +161,7 @@ document.addEventListener('DOMContentLoaded', function(){
155 </div> 161 </div>
156 <button class="submit_update_event">Modifier</button> 162 <button class="submit_update_event">Modifier</button>
157 <button class="event_close_button">Annuler</button> 163 <button class="event_close_button">Annuler</button>
164 <button class="delete_event">Supprimer</button>
158 </div>`; 165 </div>`;
159 aside.innerHTML = aside_content; 166 aside.innerHTML = aside_content;
160 calendar.updateSize(); 167 calendar.updateSize();
@@ -165,11 +172,11 @@ document.addEventListener('DOMContentLoaded', function(){
165 } 172 }
166 }, 173 },
167 //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) 174 //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date)
168 events: '../src/load-events.php' // fichier PHP qui retourne les événements
169 }); 175 });
170 176
171 function hideModal(){ 177 function hideModal(){
172 const aside = document.querySelector('aside'); 178 const aside = document.querySelector('aside');
179 event_selected = false;
173 aside.innerHTML = ''; 180 aside.innerHTML = '';
174 calendar.updateSize(); 181 calendar.updateSize();
175 } 182 }
@@ -304,13 +311,44 @@ document.addEventListener('DOMContentLoaded', function(){
304 event_end_input.value = end + 'T11:00'; 311 event_end_input.value = end + 'T11:00';
305 } 312 }
306 } 313 }
314 function removeEvent(){
315 if(!confirm("Voulez-vous vraiment supprimer cet évènement du calendrier?")){
316 return;
317 }
318 const event_id = document.getElementById('event_id').value;
319 const event = calendar.getEventById(event_id);
320
321 fetch('../src/post-ajax.php', {
322 method: 'POST',
323 headers: {
324 'Content-Type': 'application/json',
325 },
326 body: JSON.stringify(event_id),
327 })
328 .then(response => response.json())
329 .then(data => {
330 if(data.success){
331 event.remove();
332 hideModal();
333 }
334 })
335 .catch((error) => {
336 console.error('Error:', error);
337 });
338 event_selected = false;
339 }
307 340
341 // touches de clavier
308 document.addEventListener('keydown', function(event){ 342 document.addEventListener('keydown', function(event){
309 if(event.key === 'Escape') { 343 if(event.key === 'Escape'){
310 hideModal(); 344 hideModal();
311 } 345 }
346 else if(event.key === 'Delete' && event_selected === true){
347 removeEvent();
348 }
312 }); 349 });
313 350
351 // boutons dans la "modale"
314 // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement 352 // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement
315 document.addEventListener('click', function(event){ 353 document.addEventListener('click', function(event){
316 if(event.target.classList.contains('event_close_button')){ 354 if(event.target.classList.contains('event_close_button')){
@@ -325,6 +363,9 @@ document.addEventListener('DOMContentLoaded', function(){
325 else if(event.target.classList.contains('submit_update_event')){ 363 else if(event.target.classList.contains('submit_update_event')){
326 submitEvent(false); 364 submitEvent(false);
327 } 365 }
366 else if(event.target.classList.contains('delete_event')){
367 removeEvent();
368 }
328 }); 369 });
329 370
330 calendar.render(); 371 calendar.render();
diff --git a/src/load-events.php b/src/load-events.php
index b997fce..5c71137 100644
--- a/src/load-events.php
+++ b/src/load-events.php
@@ -1,43 +1,67 @@
1<?php 1<?php
2$events = [ 2// réception de deux paramètres GET: 'start' et 'end'
3 [ 3
4 'id' => 1, 4if(isset($_GET['start']) && isset($_GET['end']) && empty($_POST)){
5 'title' => 'Évènement1', 5 // bornes début et fin du calendrier affiché à l'heure locale
6 'start' => '2025-06-03T05:00:00Z', // Z indique que l'heure est en UTC 6 // noter que la vue "planning" est similaire à la vue "semaine"
7 'end' => '2025-06-03T09:00:00Z', 7 $start = new DateTime($_GET['start']);
8 'allDay' => false, 8 $end = new DateTime($_GET['end']);
9 'color' => '#ffa500', // couleur hexa, éviter les couleurs CSS qui ne fonctionnent pas dans value="" en HTML 9 $start->setTimezone(new DateTimeZone('UTC'));
10 //'url' => 'https://dev.nageurs-bigoudens.fr', // comportement: https://fullcalendar.io/docs/eventClick 10 $end->setTimezone(new DateTimeZone('UTC'));
11 'description' => 'blablabla', 11
12 ], 12 // recherche des évènement en BDD avec ceci:
13 [ 13 // WHERE end >= :start AND start <= :end
14 'id' => 2, 14 // on prend les évènements se finissant après le début
15 'title' => 'Évènement2', 15 // ou commençant avant la fin de la fourchette
16 'start' => '2025-06-06T08:00:00Z', 16
17 'end' => '2025-06-07T08:00:00Z', 17 // affichage format ISO à l'heure UTC
18 'allDay' => false, 18 //$date->format('Y-m-d\TH:i:s\Z');
19 'color' => '#e01b24', 19
20 'description' => 'truc machin', 20 // chatgpt suggère l'utilisation d'un DTO
21 ], 21 // => une classe de données simple et tout "public" pour des évènements obtenables autant depuis la BDD que de fichiers .ics par exemple
22 [ 22
23 'id' => 3, 23 $events = [
24 'title' => 'Évènement3', 24 [
25 'start' => '2025-06-08', 25 'id' => 1,
26 'end' => '2025-06-09', 26 'title' => 'Évènement1',
27 'allDay' => true, // pas d'heure 27 'start' => '2025-06-03T05:00:00Z', // Z indique que l'heure est en UTC
28 'color' => '#008000', 28 'end' => '2025-06-03T09:00:00Z',
29 'description' => 'ça va chier', 29 'allDay' => false,
30 ], 30 'color' => '#ffa500', // couleur hexa, éviter les couleurs CSS qui ne fonctionnent pas dans value="" en HTML
31 // provoque une erreur, si allDay la fin ne peut être égale au début 31 //'url' => 'https://dev.nageurs-bigoudens.fr', // comportement: https://fullcalendar.io/docs/eventClick
32 /*[ 32 'description' => 'blablabla',
33 'id' => 4, 33 ],
34 'title' => 'Évènement4', 34 [
35 'start' => '2025-06-09', 35 'id' => 2,
36 'end' => '2025-06-09', 36 'title' => 'Évènement2',
37 'allDay' => true, 37 'start' => '2025-06-06T08:00:00Z',
38 'color' => '#1a5fb4', 38 'end' => '2025-06-07T08:00:00Z',
39 ],*/ 39 'allDay' => false,
40]; 40 'color' => '#e01b24',
41 41 'description' => 'truc machin',
42header('Content-Type: application/json'); 42 ],
43echo json_encode($events); 43 [
44 'id' => 3,
45 'title' => 'Évènement3',
46 'start' => '2025-06-08',
47 'end' => '2025-06-09',
48 'allDay' => true, // pas d'heure
49 'color' => '#008000',
50 'description' => 'ça va chier',
51 ],
52 // provoque une erreur, si allDay la fin ne peut être égale au début
53 /*[
54 'id' => 4,
55 'title' => 'Évènement4',
56 'start' => '2025-06-09',
57 'end' => '2025-06-09',
58 'allDay' => true,
59 'color' => '#1a5fb4',
60 ],*/
61 ];
62
63 header('Content-Type: application/json');
64 echo json_encode($events);
65}
66
67