mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: planning events
This commit is contained in:
@ -43,6 +43,7 @@ INSTALLED_APPS = [
|
|||||||
'GestionMessagerie.apps.GestionMessagerieConfig',
|
'GestionMessagerie.apps.GestionMessagerieConfig',
|
||||||
'GestionNotification.apps.GestionNotificationConfig',
|
'GestionNotification.apps.GestionNotificationConfig',
|
||||||
'School.apps.SchoolConfig',
|
'School.apps.SchoolConfig',
|
||||||
|
'Planning.apps.PlanningConfig',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
|||||||
@ -45,6 +45,7 @@ urlpatterns = [
|
|||||||
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
||||||
path("School/", include(("School.urls", 'School'), namespace='School')),
|
path("School/", include(("School.urls", 'School'), namespace='School')),
|
||||||
path("DocuSeal/", include(("DocuSeal.urls", 'DocuSeal'), namespace='DocuSeal')),
|
path("DocuSeal/", include(("DocuSeal.urls", 'DocuSeal'), namespace='DocuSeal')),
|
||||||
|
path("Planning/", include(("Planning.urls", 'Planning'), namespace='Planning')),
|
||||||
# Documentation Api
|
# Documentation Api
|
||||||
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
|
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
|
||||||
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
||||||
|
|||||||
1
Back-End/Planning/__init__.py
Normal file
1
Back-End/Planning/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'Planning.apps.PlanningConfig'
|
||||||
3
Back-End/Planning/admin.py
Normal file
3
Back-End/Planning/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
7
Back-End/Planning/apps.py
Normal file
7
Back-End/Planning/apps.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class PlanningConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'Planning'
|
||||||
|
|
||||||
|
|
||||||
38
Back-End/Planning/models.py
Normal file
38
Back-End/Planning/models.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from School.models import Establishment
|
||||||
|
|
||||||
|
class RecursionType(models.IntegerChoices):
|
||||||
|
RECURSION_NONE = 0, _('Aucune')
|
||||||
|
RECURSION_DAILY = 1, _('Quotidienne')
|
||||||
|
RECURSION_WEEKLY = 2, _('Hebdomadaire')
|
||||||
|
RECURSION_MONTHLY = 3, _('Mensuel')
|
||||||
|
RECURSION_CUSTOM = 4, _('Personnalisé')
|
||||||
|
|
||||||
|
class Planning(models.Model):
|
||||||
|
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT)
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
description = models.TextField(default="", blank=True, null=True)
|
||||||
|
color= models.CharField(max_length=255, default="#000000")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'Planning for {self.user.username}'
|
||||||
|
|
||||||
|
|
||||||
|
class Events(models.Model):
|
||||||
|
planning = models.ForeignKey(Planning, on_delete=models.PROTECT)
|
||||||
|
title = models.CharField(max_length=255)
|
||||||
|
description = models.TextField()
|
||||||
|
start = models.DateTimeField()
|
||||||
|
end = models.DateTimeField()
|
||||||
|
recursionType = models.IntegerField(choices=RecursionType, default=0)
|
||||||
|
color= models.CharField(max_length=255)
|
||||||
|
location = models.CharField(max_length=255, default="", blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'Event for {self.user.username}'
|
||||||
13
Back-End/Planning/serializers.py
Normal file
13
Back-End/Planning/serializers.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from .models import Planning, Events
|
||||||
|
|
||||||
|
|
||||||
|
class PlanningSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Planning
|
||||||
|
fields = '__all__'
|
||||||
|
class EventsSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Events
|
||||||
|
fields = '__all__'
|
||||||
10
Back-End/Planning/urls.py
Normal file
10
Back-End/Planning/urls.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from django.urls import path, re_path
|
||||||
|
|
||||||
|
from Planning.views import PlanningView,PlanningWithIdView,EventsView,EventsWithIdView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^plannings$', PlanningView.as_view(), name="planning"),
|
||||||
|
re_path(r'^plannings/(?P<id>[0-9]+)$', PlanningWithIdView.as_view(), name="planning"),
|
||||||
|
re_path(r'^events$', EventsView.as_view(), name="events"),
|
||||||
|
re_path(r'^events/(?P<id>[0-9]+)$', EventsWithIdView.as_view(), name="events"),
|
||||||
|
]
|
||||||
89
Back-End/Planning/views.py
Normal file
89
Back-End/Planning/views.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
from django.http.response import JsonResponse
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from .models import Planning, Events
|
||||||
|
|
||||||
|
from .serializers import PlanningSerializer, EventsSerializer
|
||||||
|
|
||||||
|
from N3wtSchool import bdd
|
||||||
|
|
||||||
|
class PlanningView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
plannings=bdd.getAllObjects(Planning)
|
||||||
|
planning_serializer=PlanningSerializer(plannings, many=True)
|
||||||
|
|
||||||
|
return JsonResponse(planning_serializer.data, safe=False)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
planning_serializer = PlanningSerializer(data=request.data)
|
||||||
|
if planning_serializer.is_valid():
|
||||||
|
planning_serializer.save()
|
||||||
|
return JsonResponse(planning_serializer.data, status=201)
|
||||||
|
return JsonResponse(planning_serializer.errors, status=400)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PlanningWithIdView(APIView):
|
||||||
|
def get(self, request,id):
|
||||||
|
planning = Planning.objects.get(pk=id)
|
||||||
|
if planning is None:
|
||||||
|
return JsonResponse({"errorMessage":'Le dossier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
planning_serializer=PlanningSerializer(planning)
|
||||||
|
|
||||||
|
return JsonResponse(planning_serializer.data, safe=False)
|
||||||
|
|
||||||
|
def put(self, request, id):
|
||||||
|
try:
|
||||||
|
planning = Planning.objects.get(pk=id)
|
||||||
|
except Planning.DoesNotExist:
|
||||||
|
return JsonResponse({'error': 'Planning not found'}, status=404)
|
||||||
|
|
||||||
|
planning_serializer = PlanningSerializer(planning, data=request.data)
|
||||||
|
if planning_serializer.is_valid():
|
||||||
|
planning_serializer.save()
|
||||||
|
return JsonResponse(planning_serializer.data)
|
||||||
|
return JsonResponse(planning_serializer.errors, status=400)
|
||||||
|
|
||||||
|
def delete(self, request, id):
|
||||||
|
try:
|
||||||
|
planning = Planning.objects.get(pk=id)
|
||||||
|
except Planning.DoesNotExist:
|
||||||
|
return JsonResponse({'error': 'Planning not found'}, status=404)
|
||||||
|
|
||||||
|
planning.delete()
|
||||||
|
return JsonResponse({'message': 'Planning deleted'}, status=204)
|
||||||
|
|
||||||
|
class EventsView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
events = bdd.getAllObjects(Events)
|
||||||
|
events_serializer = EventsSerializer(events, many=True)
|
||||||
|
return JsonResponse(events_serializer.data, safe=False)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
events_serializer = EventsSerializer(data=request.data)
|
||||||
|
if events_serializer.is_valid():
|
||||||
|
events_serializer.save()
|
||||||
|
return JsonResponse(events_serializer.data, status=201)
|
||||||
|
return JsonResponse(events_serializer.errors, status=400)
|
||||||
|
|
||||||
|
class EventsWithIdView(APIView):
|
||||||
|
def put(self, request, id):
|
||||||
|
try:
|
||||||
|
event = Events.objects.get(pk=id)
|
||||||
|
except Events.DoesNotExist:
|
||||||
|
return JsonResponse({'error': 'Event not found'}, status=404)
|
||||||
|
|
||||||
|
events_serializer = EventsSerializer(event, data=request.data)
|
||||||
|
if events_serializer.is_valid():
|
||||||
|
events_serializer.save()
|
||||||
|
return JsonResponse(events_serializer.data)
|
||||||
|
return JsonResponse(events_serializer.errors, status=400)
|
||||||
|
|
||||||
|
def delete(self, request, id):
|
||||||
|
try:
|
||||||
|
event = Events.objects.get(pk=id)
|
||||||
|
except Events.DoesNotExist:
|
||||||
|
return JsonResponse({'error': 'Event not found'}, status=404)
|
||||||
|
|
||||||
|
event.delete()
|
||||||
|
return JsonResponse({'message': 'Event deleted'}, status=204)
|
||||||
@ -16,6 +16,7 @@ commands = [
|
|||||||
["python", "manage.py", "collectstatic", "--noinput"],
|
["python", "manage.py", "collectstatic", "--noinput"],
|
||||||
["python", "manage.py", "flush", "--noinput"],
|
["python", "manage.py", "flush", "--noinput"],
|
||||||
["python", "manage.py", "makemigrations", "Subscriptions", "--noinput"],
|
["python", "manage.py", "makemigrations", "Subscriptions", "--noinput"],
|
||||||
|
["python", "manage.py", "makemigrations", "Planning", "--noinput"],
|
||||||
["python", "manage.py", "makemigrations", "GestionNotification", "--noinput"],
|
["python", "manage.py", "makemigrations", "GestionNotification", "--noinput"],
|
||||||
["python", "manage.py", "makemigrations", "GestionMessagerie", "--noinput"],
|
["python", "manage.py", "makemigrations", "GestionMessagerie", "--noinput"],
|
||||||
["python", "manage.py", "makemigrations", "Auth", "--noinput"],
|
["python", "manage.py", "makemigrations", "Auth", "--noinput"],
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export default function Page() {
|
|||||||
start: '',
|
start: '',
|
||||||
end: '',
|
end: '',
|
||||||
location: '',
|
location: '',
|
||||||
scheduleId: '', // Enlever la valeur par défaut ici
|
planning: '', // Enlever la valeur par défaut ici
|
||||||
recurrence: 'none',
|
recurrence: 'none',
|
||||||
selectedDays: [],
|
selectedDays: [],
|
||||||
recurrenceEnd: '',
|
recurrenceEnd: '',
|
||||||
@ -32,7 +32,7 @@ export default function Page() {
|
|||||||
start: eventDate.toISOString(),
|
start: eventDate.toISOString(),
|
||||||
end: new Date(eventDate.getTime() + 2 * 60 * 60 * 1000).toISOString(),
|
end: new Date(eventDate.getTime() + 2 * 60 * 60 * 1000).toISOString(),
|
||||||
location: '',
|
location: '',
|
||||||
scheduleId: '', // Ne pas définir de valeur par défaut ici non plus
|
planning: '', // Ne pas définir de valeur par défaut ici non plus
|
||||||
recurrence: 'none',
|
recurrence: 'none',
|
||||||
selectedDays: [],
|
selectedDays: [],
|
||||||
recurrenceEnd: '',
|
recurrenceEnd: '',
|
||||||
|
|||||||
108
Front-End/src/app/actions/planningAction.js
Normal file
108
Front-End/src/app/actions/planningAction.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { BE_PLANNING_PLANNINGS_URL,
|
||||||
|
BE_PLANNING_EVENTS_URL
|
||||||
|
} from '@/utils/Url';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const requestResponseHandler = async (response) => {
|
||||||
|
const body = response.status !== 204 ? await response?.json() : {};
|
||||||
|
console.log(response)
|
||||||
|
if (response.ok) {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
// Throw an error with the JSON body containing the form errors
|
||||||
|
const error = new Error(body?.errorMessage || "Une erreur est survenue");
|
||||||
|
error.details = body;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getData = (url) => {
|
||||||
|
return fetch(`${url}`).then(requestResponseHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
const createDatas = (url, newData, csrfToken) => {
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
body: JSON.stringify(newData),
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(requestResponseHandler)
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateDatas = (url, updatedData, csrfToken) => {
|
||||||
|
return fetch(`${url}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
body: JSON.stringify(updatedData),
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(requestResponseHandler)
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeDatas = (url, csrfToken) => {
|
||||||
|
return fetch(`${url}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(requestResponseHandler)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const fetchPlannings = () => {
|
||||||
|
return getData(`${BE_PLANNING_PLANNINGS_URL}`)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getPlanning = (id) => {
|
||||||
|
return getData(`${BE_PLANNING_PLANNINGS_URL}/${id}`)
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createPlanning = (newData, csrfToken) => {
|
||||||
|
return createDatas(`${BE_PLANNING_PLANNINGS_URL}`, newData, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updatePlanning = (id,newData, csrfToken) => {
|
||||||
|
return updateDatas(`${BE_PLANNING_PLANNINGS_URL}/${id}`, newData, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deletePlanning = (id, csrfToken) => {
|
||||||
|
return removeDatas(`${BE_PLANNING_PLANNINGS_URL}/${id}`, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const fetchEvents = () => {
|
||||||
|
return getData(`${BE_PLANNING_EVENTS_URL}`)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getEvent = (id) => {
|
||||||
|
return getData(`${BE_PLANNING_EVENTS_URL}/${id}`)
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createEvent = (newData, csrfToken) => {
|
||||||
|
return createDatas(`${BE_PLANNING_EVENTS_URL}`, newData, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateEvent = (id,newData, csrfToken) => {
|
||||||
|
return updateDatas(`${BE_PLANNING_EVENTS_URL}/${id}`, newData, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteEvent = (id, csrfToken) => {
|
||||||
|
return removeDatas(`${BE_PLANNING_EVENTS_URL}/${id}`, csrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ const Calendar = ({ onDateClick, onEventClick }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// S'assurer que le filtrage est fait au niveau parent
|
// S'assurer que le filtrage est fait au niveau parent
|
||||||
const filtered = events.filter(event => !hiddenSchedules.includes(event.scheduleId));
|
const filtered = events?.filter(event => !hiddenSchedules.includes(event.planning));
|
||||||
setVisibleEvents(filtered);
|
setVisibleEvents(filtered);
|
||||||
logger.debug('Events filtrés:', filtered); // Debug
|
logger.debug('Events filtrés:', filtered); // Debug
|
||||||
}, [events, hiddenSchedules]);
|
}, [events, hiddenSchedules]);
|
||||||
|
|||||||
@ -3,18 +3,18 @@ import { format } from 'date-fns';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default function EventModal({ isOpen, onClose, eventData, setEventData }) {
|
export default function EventModal({ isOpen, onClose, eventData, setEventData }) {
|
||||||
const { addEvent, updateEvent, deleteEvent, schedules } = usePlanning();
|
const { addEvent, handleUpdateEvent, handleDeleteEvent, schedules } = usePlanning();
|
||||||
|
|
||||||
// S'assurer que scheduleId est défini lors du premier rendu
|
// S'assurer que planning est défini lors du premier rendu
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!eventData.scheduleId && schedules.length > 0) {
|
if (!eventData.planning && schedules.length > 0) {
|
||||||
setEventData(prev => ({
|
setEventData(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
scheduleId: schedules[0].id,
|
planning: schedules[0].id,
|
||||||
color: schedules[0].color
|
color: schedules[0].color
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, [schedules, eventData.scheduleId]);
|
}, [schedules, eventData.planning]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
@ -39,24 +39,24 @@ export default function EventModal({ isOpen, onClose, eventData, setEventData })
|
|||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!eventData.scheduleId) {
|
if (!eventData.planning) {
|
||||||
alert('Veuillez sélectionner un planning');
|
alert('Veuillez sélectionner un planning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedSchedule = schedules.find(s => s.id === eventData.scheduleId);
|
const selectedSchedule = schedules.find(s => s.id === eventData.planning);
|
||||||
|
|
||||||
if (eventData.id) {
|
if (eventData.id) {
|
||||||
updateEvent(eventData.id, {
|
handleUpdateEvent(eventData.id, {
|
||||||
...eventData,
|
...eventData,
|
||||||
scheduleId: eventData.scheduleId, // S'assurer que scheduleId est bien défini
|
planning: eventData.planning, // S'assurer que planning est bien défini
|
||||||
color: eventData.color || selectedSchedule?.color
|
color: eventData.color || selectedSchedule?.color
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addEvent({
|
addEvent({
|
||||||
...eventData,
|
...eventData,
|
||||||
id: `event-${Date.now()}`,
|
id: `event-${Date.now()}`,
|
||||||
scheduleId: eventData.scheduleId, // S'assurer que scheduleId est bien défini
|
planning: eventData.planning, // S'assurer que planning est bien défini
|
||||||
color: eventData.color || selectedSchedule?.color
|
color: eventData.color || selectedSchedule?.color
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ export default function EventModal({ isOpen, onClose, eventData, setEventData })
|
|||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (eventData.id && confirm('Êtes-vous sûr de vouloir supprimer cet événement ?')) {
|
if (eventData.id && confirm('Êtes-vous sûr de vouloir supprimer cet événement ?')) {
|
||||||
deleteEvent(eventData.id);
|
handleDeleteEvent(eventData.id);
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,12 +111,12 @@ export default function EventModal({ isOpen, onClose, eventData, setEventData })
|
|||||||
Planning
|
Planning
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={eventData.scheduleId || schedules[0]?.id}
|
value={eventData.planning || schedules[0]?.id}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const selectedSchedule = schedules.find(s => s.id === e.target.value);
|
const selectedSchedule = schedules.find(s => s.id === e.target.value);
|
||||||
setEventData({
|
setEventData({
|
||||||
...eventData,
|
...eventData,
|
||||||
scheduleId: e.target.value,
|
planning: e.target.value,
|
||||||
color: selectedSchedule?.color || '#10b981'
|
color: selectedSchedule?.color || '#10b981'
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@ -138,7 +138,7 @@ export default function EventModal({ isOpen, onClose, eventData, setEventData })
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
value={eventData.color || schedules.find(s => s.id === eventData.scheduleId)?.color || '#10b981'}
|
value={eventData.color || schedules.find(s => s.id === eventData.planning)?.color || '#10b981'}
|
||||||
onChange={(e) => setEventData({ ...eventData, color: e.target.value })}
|
onChange={(e) => setEventData({ ...eventData, color: e.target.value })}
|
||||||
className="w-full h-10 p-1 rounded border"
|
className="w-full h-10 p-1 rounded border"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { createContext, useContext, useState } from 'react';
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { mockEvents, mockSchedules } from '@/data/mockData';
|
import { createPlanning, fetchEvents, fetchPlannings, updatePlanning, createEvent, deleteEvent, updateEvent } from '@/app/actions/planningAction';
|
||||||
|
import { useCsrfToken } from './CsrfContext';
|
||||||
|
import { ESTABLISHMENT_ID } from '@/utils/Url';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contexte de planification pour gérer l'état global du planning
|
* Contexte de planification pour gérer l'état global du planning
|
||||||
@ -16,51 +21,90 @@ export function PlanningProvider({ children }) {
|
|||||||
// const [events, setEvents] = useState([]);
|
// const [events, setEvents] = useState([]);
|
||||||
// const [schedules, setSchedules] = useState([]);
|
// const [schedules, setSchedules] = useState([]);
|
||||||
// const [selectedSchedule, setSelectedSchedule] = useState(null);
|
// const [selectedSchedule, setSelectedSchedule] = useState(null);
|
||||||
const [events, setEvents] = useState(mockEvents);
|
const [events, setEvents] = useState([]);
|
||||||
const [schedules, setSchedules] = useState(mockSchedules);
|
const [schedules, setSchedules] = useState([]);
|
||||||
const [selectedSchedule, setSelectedSchedule] = useState(mockSchedules[0].id);
|
const [selectedSchedule, setSelectedSchedule] = useState(0);
|
||||||
const [currentDate, setCurrentDate] = useState(new Date());
|
const [currentDate, setCurrentDate] = useState(new Date());
|
||||||
const [viewType, setViewType] = useState('week'); // Changer 'month' en 'week'
|
const [viewType, setViewType] = useState('week'); // Changer 'month' en 'week'
|
||||||
const [hiddenSchedules, setHiddenSchedules] = useState([]);
|
const [hiddenSchedules, setHiddenSchedules] = useState([]);
|
||||||
|
|
||||||
|
const csrfToken = useCsrfToken();
|
||||||
|
useEffect(()=>{
|
||||||
|
|
||||||
|
fetchPlannings().then((data) => {
|
||||||
|
setSchedules(data)
|
||||||
|
setSelectedSchedule(data[0].id);
|
||||||
|
});
|
||||||
|
fetchEvents().then((data)=>{
|
||||||
|
setEvents(data);
|
||||||
|
});
|
||||||
|
},[]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const addEvent = (newEvent) => {
|
const addEvent = (newEvent) => {
|
||||||
setEvents((prevEvents) => [...prevEvents, newEvent]);
|
createEvent(newEvent).then((data) => {
|
||||||
|
setEvents((prevEvents) => [...prevEvents, data]);
|
||||||
|
});
|
||||||
|
console.log('newEvent',newEvent);
|
||||||
|
|
||||||
|
//dssetEvents((prevEvents) => [...prevEvents, newEvent]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateEvent = (id, updatedEvent) => {
|
const handleUpdateEvent = (id, updatedEvent) => {
|
||||||
setEvents((prevEvents) =>
|
updateEvent(id,updatedEvent,csrfToken).then((data) => {
|
||||||
prevEvents.map((event) => (event.id === id ? updatedEvent : event))
|
setEvents((prevEvents) =>
|
||||||
);
|
prevEvents.map((event) => (event.id === id ? updatedEvent : event))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteEvent = (id) => {
|
const handleDeleteEvent = (id) => {
|
||||||
setEvents((prevEvents) => prevEvents.filter((event) => event.id !== id));
|
deleteEvent(id,csrfToken).then((data) => {
|
||||||
|
setEvents((prevEvents) => prevEvents.filter((event) => event.id !== id));
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addSchedule = (newSchedule) => {
|
const addSchedule = (newSchedule) => {
|
||||||
setSchedules((prevSchedules) => [...prevSchedules, newSchedule]);
|
//FIXME:Gerenr lestablshment
|
||||||
|
logger.debug('newSchedule',newSchedule);
|
||||||
|
newSchedule.establishment = ESTABLISHMENT_ID;
|
||||||
|
|
||||||
|
createPlanning(newSchedule,csrfToken).then((data) => {
|
||||||
|
setSchedules((prevSchedules) => [...prevSchedules, data]);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSchedule = (id, updatedSchedule) => {
|
const updateSchedule = (id, updatedSchedule) => {
|
||||||
setSchedules((prevSchedules) =>
|
|
||||||
prevSchedules.map((schedule) =>
|
updatePlanning(id,updatedSchedule,csrfToken).then((data) => {
|
||||||
schedule.id === id ? updatedSchedule : schedule
|
setSchedules((prevSchedules) =>
|
||||||
)
|
prevSchedules.map((schedule) =>
|
||||||
);
|
schedule.id === id ? updatedSchedule : schedule
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteSchedule = (id) => {
|
const deleteSchedule = (id) => {
|
||||||
setSchedules((prevSchedules) =>
|
deletePlanning(id,csrfToken).then((data) => {
|
||||||
prevSchedules.filter((schedule) => schedule.id !== id)
|
setSchedules((prevSchedules) =>
|
||||||
|
prevSchedules.filter((schedule) => schedule.id !== id)
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleScheduleVisibility = (scheduleId) => {
|
const toggleScheduleVisibility = (planning) => {
|
||||||
setHiddenSchedules((prev) => {
|
setHiddenSchedules((prev) => {
|
||||||
const isHidden = prev.includes(scheduleId);
|
const isHidden = prev.includes(planning);
|
||||||
const newHiddenSchedules = isHidden
|
const newHiddenSchedules = isHidden
|
||||||
? prev.filter((id) => id !== scheduleId)
|
? prev.filter((id) => id !== planning)
|
||||||
: [...prev, scheduleId];
|
: [...prev, planning];
|
||||||
return newHiddenSchedules;
|
return newHiddenSchedules;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -73,8 +117,8 @@ export function PlanningProvider({ children }) {
|
|||||||
selectedSchedule,
|
selectedSchedule,
|
||||||
setSelectedSchedule,
|
setSelectedSchedule,
|
||||||
addEvent,
|
addEvent,
|
||||||
updateEvent,
|
handleUpdateEvent,
|
||||||
deleteEvent,
|
handleDeleteEvent,
|
||||||
addSchedule,
|
addSchedule,
|
||||||
updateSchedule,
|
updateSchedule,
|
||||||
deleteSchedule,
|
deleteSchedule,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export const mockEvents = [
|
|||||||
description: 'Cours de mathématiques avancées',
|
description: 'Cours de mathématiques avancées',
|
||||||
start: '2024-02-20T08:00:00',
|
start: '2024-02-20T08:00:00',
|
||||||
end: '2024-02-20T10:00:00',
|
end: '2024-02-20T10:00:00',
|
||||||
scheduleId: 'default',
|
planning: 'default',
|
||||||
location: 'Salle A101',
|
location: 'Salle A101',
|
||||||
color: '#10b981'
|
color: '#10b981'
|
||||||
},
|
},
|
||||||
@ -22,7 +22,7 @@ export const mockEvents = [
|
|||||||
description: 'Examen final de physique',
|
description: 'Examen final de physique',
|
||||||
start: '2024-02-21T14:00:00',
|
start: '2024-02-21T14:00:00',
|
||||||
end: '2024-02-21T16:00:00',
|
end: '2024-02-21T16:00:00',
|
||||||
scheduleId: 'exam',
|
planning: 'exam',
|
||||||
location: 'Amphithéâtre B',
|
location: 'Amphithéâtre B',
|
||||||
color: '#f59e0b'
|
color: '#f59e0b'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
export function useSchedules() {
|
|
||||||
const [schedules, setSchedules] = useState([
|
|
||||||
{ id: 'default', name: 'Planning principal', color: '#10b981' },
|
|
||||||
{ id: 'secondary', name: 'Planning secondaire', color: '#3b82f6' },
|
|
||||||
{ id: 'special', name: 'Événements spéciaux', color: '#ef4444' },
|
|
||||||
{ id: 'exam', name: 'Planning examens', color: '#f59e0b' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const addSchedule = (newSchedule) => {
|
|
||||||
setSchedules(prev => [...prev, {
|
|
||||||
...newSchedule,
|
|
||||||
id: `schedule-${Date.now()}`
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSchedule = (id, updates) => {
|
|
||||||
setSchedules(prev => prev.map(schedule =>
|
|
||||||
schedule.id === id ? { ...schedule, ...updates } : schedule
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteSchedule = (id) => {
|
|
||||||
setSchedules(prev => prev.filter(schedule => schedule.id !== id));
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
schedules,
|
|
||||||
addSchedule,
|
|
||||||
updateSchedule,
|
|
||||||
deleteSchedule
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useEvents(initialEvents = []) {
|
|
||||||
const [events, setEvents] = useState(initialEvents);
|
|
||||||
|
|
||||||
const addEvent = (newEvent) => {
|
|
||||||
setEvents(prev => [...prev, {
|
|
||||||
...newEvent,
|
|
||||||
id: `event-${Date.now()}`
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateEvent = (id, updates) => {
|
|
||||||
setEvents(prev => prev.map(event =>
|
|
||||||
event.id === id ? { ...event, ...updates } : event
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteEvent = (id) => {
|
|
||||||
setEvents(prev => prev.filter(event => event.id !== id));
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
events,
|
|
||||||
setEvents,
|
|
||||||
addEvent,
|
|
||||||
updateEvent,
|
|
||||||
deleteEvent
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { mockEvents, mockSchedules } from '@/data/mockData';
|
|
||||||
|
|
||||||
export default function useSchedules() {
|
|
||||||
const [schedules, setSchedules] = useState(mockSchedules);
|
|
||||||
const [events, setEvents] = useState(mockEvents);
|
|
||||||
const [selectedSchedule, setSelectedSchedule] = useState(mockSchedules[0].id);
|
|
||||||
|
|
||||||
const addEvent = async (eventData) => {
|
|
||||||
const newEvent = {
|
|
||||||
...eventData,
|
|
||||||
id: `event-${Date.now()}`,
|
|
||||||
color: schedules.find(s => s.id === eventData.scheduleId)?.color || '#10b981'
|
|
||||||
};
|
|
||||||
setEvents(prev => [...prev, newEvent]);
|
|
||||||
return newEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateEvent = async (eventId, updates) => {
|
|
||||||
setEvents(prev => prev.map(event =>
|
|
||||||
event.id === eventId ? { ...event, ...updates } : event
|
|
||||||
));
|
|
||||||
return updates;
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteEvent = async (eventId) => {
|
|
||||||
setEvents(prev => prev.filter(event => event.id !== eventId));
|
|
||||||
return eventId;
|
|
||||||
};
|
|
||||||
|
|
||||||
const addSchedule = (newSchedule) => {
|
|
||||||
setSchedules(prev => [...prev, {
|
|
||||||
...newSchedule,
|
|
||||||
id: `schedule-${Date.now()}`
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSchedule = (id, updates) => {
|
|
||||||
setSchedules(prev => prev.map(schedule =>
|
|
||||||
schedule.id === id ? { ...schedule, ...updates } : schedule
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteSchedule = (id) => {
|
|
||||||
setSchedules(prev => prev.filter(schedule => schedule.id !== id));
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
events,
|
|
||||||
schedules,
|
|
||||||
selectedSchedule,
|
|
||||||
setSelectedSchedule,
|
|
||||||
addEvent,
|
|
||||||
updateEvent,
|
|
||||||
deleteEvent,
|
|
||||||
addSchedule,
|
|
||||||
updateSchedule,
|
|
||||||
deleteSchedule
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -42,7 +42,13 @@ export const BE_SCHOOL_PAYMENT_PLANS_URL = `${BASE_URL}/School/paymentPlans`;
|
|||||||
export const BE_SCHOOL_PAYMENT_MODES_URL = `${BASE_URL}/School/paymentModes`;
|
export const BE_SCHOOL_PAYMENT_MODES_URL = `${BASE_URL}/School/paymentModes`;
|
||||||
export const BE_SCHOOL_ESTABLISHMENT_URL = `${BASE_URL}/School/establishments`;
|
export const BE_SCHOOL_ESTABLISHMENT_URL = `${BASE_URL}/School/establishments`;
|
||||||
|
|
||||||
// En attendant la gestion des sessions
|
|
||||||
|
// GESTION PLANNING
|
||||||
|
export const BE_PLANNING_PLANNINGS_URL = `${BASE_URL}/Planning/plannings`
|
||||||
|
export const BE_PLANNING_EVENTS_URL = `${BASE_URL}/Planning/events`
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME : En attendant la gestion des sessions
|
||||||
export const ESTABLISHMENT_ID = 1;
|
export const ESTABLISHMENT_ID = 1;
|
||||||
|
|
||||||
// GESTION MESSAGERIE
|
// GESTION MESSAGERIE
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export const DEFAULT_EVENT = {
|
|||||||
start: '',
|
start: '',
|
||||||
end: '',
|
end: '',
|
||||||
location: '',
|
location: '',
|
||||||
scheduleId: 'default',
|
planning: 'default',
|
||||||
color: '#10b981',
|
color: '#10b981',
|
||||||
recurrence: 'none',
|
recurrence: 'none',
|
||||||
selectedDays: [],
|
selectedDays: [],
|
||||||
|
|||||||
@ -85,7 +85,7 @@ export const getWeekEvents = (day, events) => {
|
|||||||
const start = startOfDay(day);
|
const start = startOfDay(day);
|
||||||
const end = endOfDay(day);
|
const end = endOfDay(day);
|
||||||
|
|
||||||
return events.filter(event => {
|
return events?.filter(event => {
|
||||||
const eventStart = new Date(event.start);
|
const eventStart = new Date(event.start);
|
||||||
const eventEnd = new Date(event.end);
|
const eventEnd = new Date(event.end);
|
||||||
|
|
||||||
@ -106,5 +106,5 @@ export const getWeekEvents = (day, events) => {
|
|||||||
* @returns {Array<Object>} Liste des événements filtrés
|
* @returns {Array<Object>} Liste des événements filtrés
|
||||||
*/
|
*/
|
||||||
export const filterEventsByVisibleSchedules = (events, hiddenSchedules) => {
|
export const filterEventsByVisibleSchedules = (events, hiddenSchedules) => {
|
||||||
return events.filter(event => !hiddenSchedules.includes(event.scheduleId));
|
return events.filter(event => !hiddenSchedules.includes(event.planning));
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user