diff --git a/src/app/(dashboard)/assign_zone_project/AssignProject.jsx b/src/app/(dashboard)/assign_zone_project/AssignProject.jsx new file mode 100644 index 0000000000000000000000000000000000000000..60fd26de09e100d0897da893b01156694f9546a5 --- /dev/null +++ b/src/app/(dashboard)/assign_zone_project/AssignProject.jsx @@ -0,0 +1,358 @@ +"use client" +import React, { useState, useEffect, useRef } from 'react' +import Loader from '@/components/Loader/Loader' +import { useNotification } from '@/context/NotificationContext' +import CancelIcon from "@/static/image/svg/cancel.svg" +import UserIcon from "@/static/image/svg/user.svg" +import DeskIcon from "@/static/image/svg/study-desk.svg" +import AddIcon from "@/static/image/svg/add.svg" +import fetchRequest from "@/app/lib/fetchRequest"; + + +const AssignProject = ({ setIsOpen, listProjects }) => { + const [loading, setLoading] = useState(false) + const [projects, setProjects] = useState([]) + const [zones, setZones] = useState([]) + const [ selectedDay, setSelectedDay ] = useState('') + const [ selectedWeek, setSelectedWeek ] = useState('') + const [ selectedZone, setSelectedZone ] = useState(null) + const [ selectedProject, setSelectedProject ] = useState(null) + const [ places , setPlaces ] = useState([]) + const [ nbrCollabs, setNbrCollabs ] = useState(0) + const [ collabsAttributed, setCollabsAttributed ] = useState(0) + const [ selectedOtherZone, setSelectedOtherZone ] = useState(null) + const [ otherPlaces, setOtherPlaces ] = useState([]) + + const { toggleNotification } = useNotification() + + const attributedCollabsRef = useRef() + + useEffect(() => { + const fetchProjectsandZones = async () => { + setLoading(true) + try { + const {isSuccess, errors, data} = await fetchRequest(`/zoaning/affectingProject/${selectedWeek}/${selectedDay}`, {method: 'GET'}) + if(isSuccess){ + setCollabsAttributed(0) + setNbrCollabs(0) + setPlaces([]) + if ( (data.projects && data.projects.length === 0) && (data.zones && data.zones.length === 0)){ + toggleNotification({ + visible: true, + message: "Il y'a pas de projets et de zones pour cette semaine et ce jour.", + type: "warning" + }) + setProjects([]) + setZones([]) + }else{ + if(data.projects && data.projects.length === 0){ + toggleNotification({ + visible: true, + message: "Il y'a pas de projets pour cette semaine et ce jour.", + type: "warning" + }) + setProjects([]) + }else{ + setProjects(data.projects) + } + if(data.zones && data.zones.length === 0){ + toggleNotification({ + visible: true, + message: "Il y'a pas de zones pour cette semaine et ce jour.", + type: "warning" + }) + setZones([]) + }else{ + setZones(data.zones) + } + } + }else{ + // handle error + setLoading(false) + } + } catch (error) { + console.log(error) + toggleNotification({ title: 'Erreur', content: error.message, type: 'error' }) + } finally { + setLoading(false) + } + } + if(selectedDay && selectedWeek) fetchProjectsandZones() + }, [selectedDay, selectedWeek]) + + const handleZoneSelection = async (e) => { + const zone_id = e.target.value + try{ + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/countingPlaces/${zone_id}`, {method: 'GET'}) + if(isSuccess){ + setSelectedZone(zone_id) + setPlaces(data.places) + setOtherPlaces([]) + setSelectedOtherZone(null) + }else{ + // handle error + setPlaces([]) + } + }catch(error){ + console.log(error) + } + } + + const handleProjectSelection = async (e) => { + const project_id = e.target.value + try{ + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/countingCollabs/${project_id}`, {method: 'GET'}) + if(isSuccess){ + setSelectedProject(project_id) + setNbrCollabs(data.user_count) + setOtherPlaces([]) + setSelectedOtherZone(null) + }else{ + // handle error + setNbrCollabs(0) + } + }catch(error){ + console.log(error) + } + } + + useEffect( () => { + if(nbrCollabs > 0 && places.length > 0){ + if( nbrCollabs <= places.length){ + setCollabsAttributed(nbrCollabs) + attributedCollabsRef.current = nbrCollabs + }else{ + setCollabsAttributed(places.length) + attributedCollabsRef.current = places.length + } + } + }, [nbrCollabs, places]) + + + const handleAddCollab = () =>{ + setCollabsAttributed(collabsAttributed + 1) + attributedCollabsRef.current = collabsAttributed + 1 + } + + const handleMinusCollab = () =>{ + setCollabsAttributed(collabsAttributed - 1) + attributedCollabsRef.current = collabsAttributed - 1 + } + + + + + const handleOtherZoneSelection = async (e) => { + const zone_id = e.target.value + setSelectedOtherZone(zone_id) + try{ + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/countingPlaces/${zone_id}`, {method: 'GET'}) + if(isSuccess){ + setOtherPlaces(data.places) + }else{ + // handle error + } + }catch(error){ + console.log(error) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + + useEffect( () => { + if( (collabsAttributed - places.length) <= 0 && selectedOtherZone ) { + setSelectedOtherZone(null) + setOtherPlaces([]) + } + }, [collabsAttributed]) + + + const handleAssignProject = async () => { + const finalData = { + id_zone: selectedZone, + id_project: selectedProject, + jour: selectedDay, + semaine: selectedWeek, + nombre_personnes: collabsAttributed, + places_disponibles: (collabsAttributed > places.length) ? 0 : places.length - collabsAttributed, + places_occuper: (collabsAttributed > places.length) ? places.length : collabsAttributed, + places: (collabsAttributed > places.length) ? places.map( (element) => element.id) : places.map( (element, index) => index < collabsAttributed && element.id).filter(id => id !== false) + } + if( selectedOtherZone && otherPlaces.length > 0){ + finalData.otherZone = { + id_zone: selectedOtherZone, + places_disponibles: ( (collabsAttributed - places.length ) > otherPlaces.length ) ? 0 : otherPlaces.length - (collabsAttributed - places.length), + places_occuper: ( (collabsAttributed - places.length ) > otherPlaces.length ) ? otherPlaces.length : collabsAttributed - places.length, + places: ( (collabsAttributed - places.length ) > otherPlaces.length ) ? otherPlaces.map( (element) => element.id) : otherPlaces.map( (element, index) => (index < (collabsAttributed - places.length)) && element.id).filter(id => id !== false) + } + } + try{ + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/affectingProject`, {method: 'POST', body: JSON.stringify(finalData)}) + if(isSuccess){ + listProjects( (prevListProjects) => [...prevListProjects, data.main_zone, ...(data.second_zone ? [data.second_zone] : [])]) + toggleNotification({ + visible: true, + message: "Projet affecté avec succès.", + type: "success" + }) + closePopup(false) + }else{ + console.log(errors) + toggleNotification({ + visible: true, + message: "Erreur lors de l'affectation du projet", + type: "error" + }) + } + }catch(error){ + console.log(error) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + + } + + const closePopup = () => { + setIsOpen() + setSelectedWeek('') + setSelectedDay('') + setSelectedProject(null) + setSelectedZone(null) + setCollabsAttributed(0) + setPlaces([]) + setNbrCollabs(0) + setSelectedOtherZone(null) + setOtherPlaces([]) + setProjects([]) + setZones([]) + setLoading(false) + + + } + + + console.log("other zone ::::" , selectedOtherZone) + return ( +
+
+

Attribuer un projet à une zone.

+ {setIsOpen(false)}} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> +
+
+

Veuillez sélectionner une date

+
+
+ +
+
+ +
+
+
+
+
+ {(!loading && (projects && projects.length)) ? + + : +
+ Aucun projet disponible +
+ } +
+

: {nbrCollabs}

+
+
+
+ {(!loading && (zones && zones.length)) ? + + : +
+ Aucune zone disponible +
+ } +
+

: {places.length}

+
+
+ {collabsAttributed > 0 && + <> +
+ Collaborateurs attribués +
+ {collabsAttributed} +
+ + +
+
+
+
+
+
0) ? "text-red-400" : "text-sushi-500"}`}>{nbrCollabs - collabsAttributed}
+ 0) ? "fill-red-400" : "fill-sushi-500"}`} /> +
+
+
0) ? "text-red-400" : "text-sushi-500"}`}>{(places.length+ otherPlaces.length) - collabsAttributed}
+ 0) ? "fill-red-400" : "fill-sushi-500"}`} /> +
+
+ restant +
+
+ {((collabsAttributed - places.length) > 0) &&
+

Veuillez sélectionner une autre zonne pour compléter l'affectation (optionnel)

+
+ +
+

: {otherPlaces.length}

+
+
+
} + + } +
+ +
+
+
+
+
+ ) +} + +export default AssignProject \ No newline at end of file diff --git a/src/app/(dashboard)/assign_zone_project/page.jsx b/src/app/(dashboard)/assign_zone_project/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..1c49160c614f62e7ae5a1f286291846479c80d8c --- /dev/null +++ b/src/app/(dashboard)/assign_zone_project/page.jsx @@ -0,0 +1,230 @@ +"use client" +import React, { useEffect, useState } from 'react'; +import AddIcon from "@/static/image/svg/add.svg"; +import AssignProject from './AssignProject'; +import { useNotification } from '@/context/NotificationContext' + +import Loader from '@/components/Loader/Loader' +import EditIcon from "@/static/image/svg/edit.svg"; +import DeleteIcon from "@/static/image/svg/delete.svg"; +import fetchRequest from "@/app/lib/fetchRequest"; +import ConfirmationModal from "@/app/ui/ConfirmationModal"; + + + + +const AffectingZoneProject = () => { + const [isOpen, setIsOpen] = useState(false) + const [ listProjectsAffected, setListProjectsAffected ] = useState([]) + const [ isLoadingListProjects, setIsLoadingListProjects ] = useState(false) + const { toggleNotification } = useNotification() + const [ selectedWeek, setSelectedWeek ] = useState(null) + const [ selectedDay, setSelectedDay ] = useState(null) + const [ selectedAffectaionToDelete, setSelectedAffectationToDelete ] = useState(null) + const [isModalOpen, setModalOpen] = useState(false); + + + useEffect(() => { + const getListOfAffectedProjects = async () => { + setIsLoadingListProjects(true) + try{ + if(selectedDay && selectedWeek){ + var { isSuccess, errors, data } = await fetchRequest(`/zoaning/getListAffectedProjects/${selectedDay}/${selectedWeek}/`, {method: 'GET'}) + }else if (selectedWeek){ + var { isSuccess, errors, data } = await fetchRequest(`/zoaning/getListAffectedProjectsByWeek/${selectedWeek}/`, {method: 'GET'}) + }else if (selectedDay){ + var { isSuccess, errors, data } = await fetchRequest(`/zoaning/getListAffectedProjectsByDay/${selectedDay}/`, {method: 'GET'}) + }else{ + var { isSuccess, errors, data } = await fetchRequest(`/zoaning/getListAffectedProjects/`, {method: 'GET'}) + } + if(isSuccess){ + setListProjectsAffected(data) + }else{ + toggleNotification({ + visible: true, + message: errors[0].message, + type: "error" + }) + } + setIsLoadingListProjects(false) + }catch(error){ + setIsLoadingListProjects(false) + console.log(error) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + getListOfAffectedProjects() + }, [selectedDay, selectedWeek]) + + + const handleOpenAssignProject = () => { + setIsOpen(!isOpen) + } + + const handleDeleteAffectation = async () => { + try{ + console.log("qsdsqdqsdsqdq") + var { isSuccess, errors, data, status } = await fetchRequest(`/zoaning/deteleAffectedProject/${selectedAffectaionToDelete.id}`, {method: 'DELETE'}) + if(isSuccess){ + toggleNotification({ + visible: true, + message: "Affectation supprimer avec succès", + type: "success" + }) + setListProjectsAffected(listProjectsAffected.filter(affected => affected.id !== selectedAffectaionToDelete.id)) + }else if(status === 404){ + toggleNotification({ + visible: true, + message: "Affectation introuvable", + type: "error" + }) + }else{ + toggleNotification({ + visible: true, + message: errors[0].message, + type: "error" + }) + } + }catch(error){ + console.log(error) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + + const handleDeleteClick = (element) => { + setSelectedAffectationToDelete(element) + setModalOpen(true); + } + + + const handleConfirmDelete = () => { + console.log("qsdsq") + handleDeleteAffectation(); + console.log("fdsfsd") + setModalOpen(false); + setSelectedAffectationToDelete(null); + + }; + + return ( +
+
+ {isOpen && } +

List des Projets attribuer

+
+ Il y a des projets qui ne sont pas complètement affecter. + +
+
+ +
+ +
+
+ +
+ { (!isLoadingListProjects) ? + (listProjectsAffected && listProjectsAffected.length > 0) ? + + + + + + + + + + + + + + { (listProjectsAffected.map( (element, index) => + + {/* */} + + + + + + + + + ))} + +
+ Date + + Plateau + + Projet + + Places occupées + + Nombre des personnes + + Places disponible + + Actions +
+ Semaine: {element.semaine} - Jour: {element.jour} + + {element.id_zone.nom}-{element.id_zone.id_etage.numero} + + {element.id_project.nom} + + {element.places_occuper} + + {element.nombre_personnes} + + {element.places_disponibles} + +
+
handleDeleteClick(element)} class="font-medium text-blue-600 dark:text-blue-500 hover:underline">
+
+ : +
+ Aucun projet affecter +
+ : +
+ } + setModalOpen(false)} + onConfirm={handleConfirmDelete} + message={`Êtes-vous sûr de vouloir supprimer l'affectation "${selectedAffectaionToDelete?.id_project.nom}"?`} + /> +
+ + ); +} + + +export default AffectingZoneProject; \ No newline at end of file diff --git a/src/app/etage/AddEtageComponent.jsx b/src/app/(dashboard)/etage/AddEtageComponent.jsx similarity index 66% rename from src/app/etage/AddEtageComponent.jsx rename to src/app/(dashboard)/etage/AddEtageComponent.jsx index 17e46b843081b8f393bfe43dafda977e01f81b3f..42cfdcaca0e4ebc0d9a637b119290c15672a0543 100644 --- a/src/app/etage/AddEtageComponent.jsx +++ b/src/app/(dashboard)/etage/AddEtageComponent.jsx @@ -1,14 +1,14 @@ 'use client' import Loader from '@/components/Loader/Loader' import React, { useState, useRef } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import { useNotification } from '@/context/NotificationContext' -const AddEtageComponent = ({ etagesState })=> { - const [ numeroEtage, setNumeroEtage ] = useState("") +const AddEtageComponent = ({ etagesState }) => { + const [numeroEtage, setNumeroEtage] = useState("") const [isLoading, setIsLoading] = useState(false) const inputRef = useRef(null) const { toggleNotification } = useNotification() @@ -37,13 +37,13 @@ const AddEtageComponent = ({ etagesState })=> { }) } else { setIsLoading(false) - if(errors.type == "ValidationError") + if (errors.type == "ValidationError") toggleNotification({ type: "warning", message: "Le numéro détage déja existe.", visible: true, }) - else{ + else { toggleNotification({ type: "error", message: "Une erreur s'est produite lors de la création de la zone.", @@ -55,18 +55,18 @@ const AddEtageComponent = ({ etagesState })=> { } - return( + return (
Nouveau étage: -
- -
- +
+ +
+
- + ) } - -export default(AddEtageComponent) \ No newline at end of file + +export default (AddEtageComponent) \ No newline at end of file diff --git a/src/app/etage/page.jsx b/src/app/(dashboard)/etage/page.jsx similarity index 58% rename from src/app/etage/page.jsx rename to src/app/(dashboard)/etage/page.jsx index 94f79ae67d15916803b07c83badbdb8132e82404..ca6ba133d7e0f10a017ac734590659543769a18f 100644 --- a/src/app/etage/page.jsx +++ b/src/app/(dashboard)/etage/page.jsx @@ -1,7 +1,7 @@ "use client" import React from 'react' import AddEtageComponent from './AddEtageComponent' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import { useState, useEffect } from 'react'; import Loader from '@/components/Loader/Loader' import { useNotification } from '@/context/NotificationContext' @@ -10,9 +10,9 @@ import ConfirmationModal from "@/app/ui/ConfirmationModal"; -const Etage = ()=> { +const Etage = () => { const [etages, setEtages] = useState([]) - const [ isLoadingData, setIsLoadingData ] = useState(true) + const [isLoadingData, setIsLoadingData] = useState(true) const { toggleNotification } = useNotification() const [isModalOpen, setModalOpen] = useState(false); const [etageToDelete, setEtageToDelete] = useState(null); @@ -21,15 +21,15 @@ const Etage = ()=> { // Fetch data from external API useEffect(() => { const getAllEtages = async () => { - try{ - const {isSuccess, errors, data} = await fetchRequest('/zoaning/etages/', {method: 'GET'}) + try { + const { isSuccess, errors, data } = await fetchRequest('/zoaning/etages/', { method: 'GET' }) setIsLoadingData(false) - if(isSuccess){ + if (isSuccess) { setEtages(data) - }else{ + } else { setEtages([]) } - }catch(error){ + } catch (error) { setIsLoadingData(false) console.log(error) } @@ -37,13 +37,13 @@ const Etage = ()=> { getAllEtages() }, []) const handleDeleteEtage = async (etage) => { - try{ + try { console.log(etage) - const {isSuccess, errors, data} = await fetchRequest(`/zoaning/etages/${etage.id}/`, {method: "DELETE"}) + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/etages/${etage.id}/`, { method: "DELETE" }) console.log(isSuccess) console.log(errors) console.log(data) - if(isSuccess){ + if (isSuccess) { console.log(etages) console.log("etage: ", etage) setEtages((prevEtages) => prevEtages.filter((e) => e.id !== etage.id)); @@ -52,14 +52,14 @@ const Etage = ()=> { message: "L'étage a été supprimer avec succès.", visible: true, }) - }else{ + } else { toggleNotification({ type: "error", message: "Une erreur s'est produite lors de la suppression de l'étage.", visible: true, }) } - }catch(error){ + } catch (error) { toggleNotification({ type: "error", message: "Internal Server Error", @@ -79,7 +79,7 @@ const Etage = ()=> { setProjectToDelete(null); }; - return( + return (
@@ -87,24 +87,24 @@ const Etage = ()=> {
{(!isLoadingData) ? etages && etages?.length ?
    - {etages?.map((etage, index) => - ( -
  • - Etage numéro: {etage.numero} -
    {handleDeleteClick(etage)}}> - -
    -
  • - ) + {etages?.map((etage, index) => + ( +
  • + Etage numéro: {etage.numero} +
    { handleDeleteClick(etage) }}> + +
    +
  • + ) )} -
: -
- Aucun étage n'a été ajouté -
- : -
- -
+ : +
+ Aucun étage n'a été ajouté +
+ : +
+ +
}
@@ -117,7 +117,7 @@ const Etage = ()=> { message={`Êtes-vous sûr de vouloir supprimer l'étage numéro "${etageToDelete?.numero}"?`} />
- + ) } diff --git a/src/app/(dashboard)/layout.jsx b/src/app/(dashboard)/layout.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a4cd33784062f425514c26b2bc9f53734e97e629 --- /dev/null +++ b/src/app/(dashboard)/layout.jsx @@ -0,0 +1,20 @@ +import React from 'react' +import SideBar from '../ui/SideBar' +import Header from '../ui/Header' + +const layout = ({ children }) => { + return ( + <> +
+
+ +
+ {children} +
+
+ + + ) +} + +export default layout \ No newline at end of file diff --git a/src/app/place/CreateNewPlace.jsx b/src/app/(dashboard)/place/CreateNewPlace.jsx similarity index 73% rename from src/app/place/CreateNewPlace.jsx rename to src/app/(dashboard)/place/CreateNewPlace.jsx index 061a0cb3d4cad3464963e83934da27ff82441106..0d9a017202afd44ad8b0a253e31d899393c6fe22 100644 --- a/src/app/place/CreateNewPlace.jsx +++ b/src/app/(dashboard)/place/CreateNewPlace.jsx @@ -1,12 +1,12 @@ "use client" import React, { useState, useEffect, useRef } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import { Island_Moments } from 'next/font/google' import { useNotification } from '@/context/NotificationContext' -const CreateNewPlace = ({placesState, tables}) => { +const CreateNewPlace = ({ placesState, tables }) => { const [error, setError] = useState(null) const [isLoadingAction, setIsLoadingAction] = useState(false) const [numPlace, setNumPlace] = useState(null) @@ -27,7 +27,7 @@ const CreateNewPlace = ({placesState, tables}) => { }) if (isSuccess) { setIsLoadingAction(false) - placesState((prevPlaceState) => [...prevPlaceState, {...data, id_table: tables.find(table => table.id === data.id_table)}]); + placesState((prevPlaceState) => [...prevPlaceState, { ...data, id_table: tables.find(table => table.id === data.id_table) }]); inputRef.current.value = "" selectRef.current.value = "" setNumPlace(null) @@ -47,7 +47,7 @@ const CreateNewPlace = ({placesState, tables}) => { visible: true, }) } - }else{ + } else { toggleNotification({ type: "error", message: "Une erreur s'est produite lors de la création de la table.", @@ -65,7 +65,7 @@ const CreateNewPlace = ({placesState, tables}) => { } const handleChangeEtage = (event) => { - setError("") + setError("") setSelectedTable(event.target.value) } @@ -74,7 +74,7 @@ const CreateNewPlace = ({placesState, tables}) => { - return( + return (

Ajout d'une place

@@ -84,19 +84,19 @@ const CreateNewPlace = ({placesState, tables}) => {
- +

-
diff --git a/src/app/place/RowPlace.jsx b/src/app/(dashboard)/place/RowPlace.jsx similarity index 95% rename from src/app/place/RowPlace.jsx rename to src/app/(dashboard)/place/RowPlace.jsx index acb7a5beb3aab54b3c3c5e840ae8aa5207719ce8..3d22e4814ab1768ec4a874643ae45b3ce45d4ff8 100644 --- a/src/app/place/RowPlace.jsx +++ b/src/app/(dashboard)/place/RowPlace.jsx @@ -1,6 +1,6 @@ "use client" import React, { useState, useEffect, useRef } from 'react'; -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" @@ -42,7 +42,7 @@ const RowPlace = ({ id, numero, table, placesState, tables }) => { setLoadingStatus(false) if (isSuccess) { console.log(data) - if(data.message === "NO_CHANGES"){ + if (data.message === "NO_CHANGES") { toggleNotification({ visible: true, message: "Aucun changement n'a été effectué.", @@ -52,7 +52,7 @@ const RowPlace = ({ id, numero, table, placesState, tables }) => { return } console.log(data.data) - placesState((prevPlacesState) => prevPlacesState.map( (element) => element.id === id ? {...data.data, id_table: tables.find(table => table.id === data.data.id_table)} : element )) + placesState((prevPlacesState) => prevPlacesState.map((element) => element.id === id ? { ...data.data, id_table: tables.find(table => table.id === data.data.id_table) } : element)) setIsUpdating(false) toggleNotification({ visible: true, @@ -67,7 +67,7 @@ const RowPlace = ({ id, numero, table, placesState, tables }) => { message: "Le numéro de la place déjà existe.", visible: true, }) - }else if (errors.detail.non_field_errors) { + } else if (errors.detail.non_field_errors) { toggleNotification({ type: "warning", message: "Le numéro de la place saisie existe déjà.", @@ -174,17 +174,17 @@ const RowPlace = ({ id, numero, table, placesState, tables }) => { setModalOpen(false); }; - return( + return ( setNumPlace(event.target.value)} defaultValue={numero} type='text' className='disabled:bg-white border-0 rounded-md px-2 enabled:drop-shadow border-none enabled:bg-gray-100 duration-100 h-10 outline-none' /> {handleSearchingPlace(e)}} id="simple-search" class=" text-gray-900 text-sm block w-full ps-10 p-2.5 rounded-md px-3 duration-150 delay-75 focus:ring ring-offset-1 ring-sushi-200 border h-10 border-neutral-300 outline-none " placeholder="Chercher des places..." required /> + { handleSearchingPlace(e) }} id="simple-search" class=" text-gray-900 text-sm block w-full ps-10 p-2.5 rounded-md px-3 duration-150 delay-75 focus:ring ring-offset-1 ring-sushi-200 border h-10 border-neutral-300 outline-none " placeholder="Chercher des places..." required /> - {isArray(places) && places?.length !== 0 && isArray(tables) && tables?.length !== 0 ? + {isArray(places) && places?.length !== 0 && isArray(tables) && tables?.length !== 0 ?
- + @@ -92,18 +92,18 @@ const Place = ()=> { })}
TableTable Table-Zone-Etage Action
- : -
-

Pas encore des places

-
} + : +
+

Pas encore des places

+
} :
- } + } - + ) } diff --git a/src/app/planning/PlanningTable.jsx b/src/app/(dashboard)/planning/PlanningTable.jsx similarity index 91% rename from src/app/planning/PlanningTable.jsx rename to src/app/(dashboard)/planning/PlanningTable.jsx index 6b90c54e48199a56202614573a81d03384486426..2fbdf40d5f6aa1319a5736661724366f0343c158 100644 --- a/src/app/planning/PlanningTable.jsx +++ b/src/app/(dashboard)/planning/PlanningTable.jsx @@ -30,7 +30,8 @@ const PlanningTable = ({ data, typePresences, onTypePresenceChange }) => { {
+ onTypePresenceChange={handleTypePresenceChange} />
{/* crud buttons*/}
{planningData.id ? <> : } diff --git a/src/app/planning/type-presence/EntityForm.jsx b/src/app/(dashboard)/planning/type-presence/EntityForm.jsx similarity index 100% rename from src/app/planning/type-presence/EntityForm.jsx rename to src/app/(dashboard)/planning/type-presence/EntityForm.jsx diff --git a/src/app/planning/type-presence/EntityList.jsx b/src/app/(dashboard)/planning/type-presence/EntityList.jsx similarity index 85% rename from src/app/planning/type-presence/EntityList.jsx rename to src/app/(dashboard)/planning/type-presence/EntityList.jsx index 372907bca0bed35d0ba49c209a54a95dc87be3ae..b632780ce6d3b0304c2130c3d68dd62e326d2044 100644 --- a/src/app/planning/type-presence/EntityList.jsx +++ b/src/app/(dashboard)/planning/type-presence/EntityList.jsx @@ -32,15 +32,15 @@ const EntityList = ({ title, items, setState, handleDelete, handleEdit }) => { diff --git a/src/app/planning/type-presence/page.jsx b/src/app/(dashboard)/planning/type-presence/page.jsx similarity index 86% rename from src/app/planning/type-presence/page.jsx rename to src/app/(dashboard)/planning/type-presence/page.jsx index 2f383cf8af8fac1879dd2893cdcbb684ef6a662b..697ba16b789a4a93049d0aafee35cbcd1d1cbb07 100644 --- a/src/app/planning/type-presence/page.jsx +++ b/src/app/(dashboard)/planning/type-presence/page.jsx @@ -1,10 +1,10 @@ "use client"; -import {useEffect, useState} from 'react'; +import { useEffect, useState } from 'react'; import fetchRequest from "@/app/lib/fetchRequest"; -import EntityList from "@/app/planning/type-presence/EntityList"; -import EntityForm from "@/app/planning/type-presence/EntityForm"; -import {useNotification} from "@/context/NotificationContext"; +import EntityList from "@/app/(dashboard)/planning/type-presence/EntityList"; +import EntityForm from "@/app/(dashboard)/planning/type-presence/EntityForm"; +import { useNotification } from "@/context/NotificationContext"; const ManagePage = () => { const [typePresences, setTypePresences] = useState([]); @@ -22,7 +22,7 @@ const ManagePage = () => { }, []); const handleDelete = async (endpoint, id, setState, currentState) => { - const response = await fetchRequest(`/${endpoint}/${id}/`, {method: 'DELETE'}); + const response = await fetchRequest(`/${endpoint}/${id}/`, { method: 'DELETE' }); if (response.isSuccess) { setState(currentState.filter(item => item.id !== id)); toggleNotification({ @@ -35,7 +35,7 @@ const ManagePage = () => { }; return ( - <> +

Gérer Les Entités

@@ -55,7 +55,7 @@ const ManagePage = () => { />
- +
); }; diff --git a/src/app/privilege/CreatePrivilegeForm.jsx b/src/app/(dashboard)/privilege/CreatePrivilegeForm.jsx similarity index 93% rename from src/app/privilege/CreatePrivilegeForm.jsx rename to src/app/(dashboard)/privilege/CreatePrivilegeForm.jsx index d124e2edfbefad535461e370dcba8910952705f8..97c87c08ff9d329c7e61326cb8e94734351b040f 100644 --- a/src/app/privilege/CreatePrivilegeForm.jsx +++ b/src/app/(dashboard)/privilege/CreatePrivilegeForm.jsx @@ -1,8 +1,8 @@ 'use client' import Loader from '@/components/Loader/Loader' import React, { useRef, useState } from 'react' -import fetchRequest from '../lib/fetchRequest' -import {useNotification} from "@/context/NotificationContext"; +import fetchRequest from '../../lib/fetchRequest' +import { useNotification } from "@/context/NotificationContext"; const CreatePrivilegeForm = ({ appendPrivilege }) => { const [isLoading, setIsLoading] = useState(false) @@ -59,7 +59,7 @@ const CreatePrivilegeForm = ({ appendPrivilege }) => { } } return ( - +

Ajout d'habilitation

diff --git a/src/app/privilege/PrivilegeTableRow.jsx b/src/app/(dashboard)/privilege/PrivilegeTableRow.jsx similarity index 98% rename from src/app/privilege/PrivilegeTableRow.jsx rename to src/app/(dashboard)/privilege/PrivilegeTableRow.jsx index 7537e45773778a694de9fbe0655fdb37d9a04980..d0527ec777e59d06f3301aadc10b47744500378b 100644 --- a/src/app/privilege/PrivilegeTableRow.jsx +++ b/src/app/(dashboard)/privilege/PrivilegeTableRow.jsx @@ -1,13 +1,13 @@ 'use client' import React, { useEffect, useRef, useState } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" import CancelIcon from "@/static/image/svg/cancel.svg" import CheckIcon from "@/static/image/svg/check.svg" import { useNotification } from '@/context/NotificationContext' -import ConfirmationModal from '../ui/ConfirmationModal' +import ConfirmationModal from '../../ui/ConfirmationModal' const PrivilegeTableRow = ({ id, name, setPrivileges }) => { const [isUpdating, setIsUpdating] = useState(false) const [privilegeName, setPrivilegeName] = useState(name) diff --git a/src/app/(dashboard)/privilege/page.jsx b/src/app/(dashboard)/privilege/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..86fc11869c664d49065ab345449dccfe92aeef46 --- /dev/null +++ b/src/app/(dashboard)/privilege/page.jsx @@ -0,0 +1,83 @@ +'use client' +import React, { useEffect, useState } from 'react' +import CreatePrivilegeForm from './CreatePrivilegeForm' +import fetchRequest from '../../lib/fetchRequest' +import { isArray } from '../../lib/TypesHelper' +import PrivilegeTableRows from './PrivilegeTableRow' +import Loader from '@/components/Loader/Loader' +const Privilege = () => { + const [privileges, setPrivileges] = useState([]) + const [isLoading, setIsLoading] = useState(true) + useEffect(() => { + const getPrivileges = async () => { + const { data, errors, isSuccess } = await fetchRequest("/privileges") + setIsLoading(false) + if (isSuccess) { + setPrivileges(data) + } else { + console.log(errors) + } + } + getPrivileges() + }, []) + const appendPrivilege = (privilege) => { + setPrivileges((data) => [privilege, ...data]) + } + return ( +
+ +

List des habilitations

+ {isLoading &&
} + {!isLoading && <> {(!isArray(privileges) || privileges?.length === 0) + ?
+

Pas encore des habilitations

+
+ :
+ + + + + + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + {privileges.map((element) => { + return + })} + +
HabilitationAction
+
+ }} +
+ ) +} + +export default Privilege \ No newline at end of file diff --git a/src/app/projects/ProjectForm.jsx b/src/app/(dashboard)/projects/ProjectForm.jsx similarity index 97% rename from src/app/projects/ProjectForm.jsx rename to src/app/(dashboard)/projects/ProjectForm.jsx index 18005e6203bf2c0ae17d46755108a4dcc293d547..65c06c0ce5b3c5aeb31f07cbcbd7781393cba287 100644 --- a/src/app/projects/ProjectForm.jsx +++ b/src/app/(dashboard)/projects/ProjectForm.jsx @@ -148,7 +148,7 @@ const ProjectForm = ({ onAddProject, onEditProject, editingProject, setEditingPr
  • !isUserChosen(user) && handleUserSelect(user)} - className={`px-3 py-2 border-b border-chicago-200 ${isUserChosen(user) ? 'bg-gray-200 cursor-not-allowed' : 'hover:bg-sushi-200 cursor-pointer'}`} + className={`px-3 py-2 border-b border-chicago-200 ${isUserChosen(user) ? 'bg-chicago-100 cursor-not-allowed' : 'hover:bg-sushi-200 cursor-pointer'}`} > {/*add tick is chosen*/} {isUserChosen(user) && '✔ '} @@ -164,7 +164,7 @@ const ProjectForm = ({ onAddProject, onEditProject, editingProject, setEditingPr type="text" value={`${user.first_name} ${user.last_name} (${user.role.name})`} readOnly - className="flex-1 px-3 py-2 bg-gray-200 border border-chicago-300 rounded-md" + className="flex-1 px-3 py-2 bg-chicago-100/50 border border-chicago-300 rounded-md" /> -
  • -
  • - 1 -
  • -
  • - -
  • - -
    - } {/* Confirmation Modal */} { - const [pageUrl, setPageUrl] = useState('/projects/'); + const [pageUrl, setPageUrl] = useState('/projects/pagination/'); const [projects, setProjects] = useState([]); const [editingProject, setEditingProject] = useState(null); const [errors, setErrors] = useState(); const [loading, setLoading] = useState(false); const [isFormOpen, setIsFormOpen] = useState(false); // State for accordion + const [searchQuery, setSearchQuery] = useState(''); // State for search query + const [pagination, setPagination] = useState({}); // State for pagination const { toggleNotification } = useNotification(); - const fetchProjects = async () => { - const { isSuccess, errors, data } = await fetchRequest(pageUrl); + const fetchProjects = async (url = pageUrl) => { + const { isSuccess, errors, data } = await fetchRequest(url); if (isSuccess) { - setProjects(data); + setProjects(data.results); + setPagination({ + currentPage: data.currentPage, + pagesNumber: Math.ceil(data.count / PAGINATION_SIZE), + next: data.next, + previous: data.previous, + count: data.count + }); setErrors(null); } else { console.error("Failed to fetch projects"); @@ -27,6 +38,26 @@ const Projects = () => { } }; + const handleSearch = async (query) => { + setLoading(true); + const { isSuccess, errors, data } = await fetchRequest(`/search-projects/?q=${query}`); + if (isSuccess) { + setProjects(data.results); + setPagination({ + currentPage: data.currentPage, + pagesNumber: Math.ceil(data.count / PAGINATION_SIZE), + next: data.next, + previous: data.previous, + count: data.count + }); + setErrors(null); + } else { + console.error("Failed to search projects"); + setErrors(errors); + } + setLoading(false); + }; + useEffect(() => { fetchProjects(); }, [pageUrl]); @@ -47,7 +78,7 @@ const Projects = () => { setProjects([...projects, data]); setEditingProject(null); setErrors(null); - setIsFormOpen(false); // Close the form on success + // setIsFormOpen(false); // Close the form on success } else { console.error("Failed to add project"); setErrors(errors); @@ -74,7 +105,7 @@ const Projects = () => { setProjects(updatedProjects); setEditingProject(null); setErrors(null); - setIsFormOpen(false); // Close the form on success + // setIsFormOpen(false); // Close the form on success } else { console.error("Failed to edit project"); setErrors(errors); @@ -113,25 +144,43 @@ const Projects = () => { setIsFormOpen(!isFormOpen); // Toggle the form visibility }; + const handleSearchInputChange = (e) => { + const query = e.target.value; + setSearchQuery(query); + handleSearch(query); // Trigger search on input change + }; + + const handlePageChange = (url) => { + setPageUrl(url); + }; + return ( -
    -
    - -
    +
    +
    +
    +
    +

    Projets + {loading ? ... : null} +

    + {/* Accordion Toggle Button */} + +
    -
    -
    -
    -

    Projets - {loading ? ... : null}

    - {/* Accordion Toggle Button */} - +
    +
    + {/* Accordion Content */} {isFormOpen && ( { projects={projects} onEdit={handleEditClick} onDelete={handleDeleteProject} - onHandlePageUrl={setPageUrl} + onHandlePageUrl={handlePageChange} /> +
    diff --git a/src/app/role/CreateRoleForm.jsx b/src/app/(dashboard)/role/CreateRoleForm.jsx similarity index 97% rename from src/app/role/CreateRoleForm.jsx rename to src/app/(dashboard)/role/CreateRoleForm.jsx index d7c479d0ba974ae82aebbaddb6c4d8f8ae95cfa8..223840e892de01ba2b72044e0f6fb5f0fd108897 100644 --- a/src/app/role/CreateRoleForm.jsx +++ b/src/app/(dashboard)/role/CreateRoleForm.jsx @@ -1,6 +1,6 @@ import Loader from '@/components/Loader/Loader' import React, { useState, useRef, useEffect, useMemo } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '@/app/lib/fetchRequest' import { useNotification } from '@/context/NotificationContext' import CancelIcon from "@/static/image/svg/cancel.svg" const CreateRoleForm = ({ appendRole, setIsOpen }) => { @@ -108,7 +108,7 @@ const CreateRoleForm = ({ appendRole, setIsOpen }) => { var isAllSelected = useMemo(() => privileges ? privileges.every((element) => selectedPrivileges.find((priv) => priv.id === element.id)) : false, [selectedPrivileges, privileges]) return (
    -
    +
    setIsOpen(false)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> {(privileges) ?

    Ajout de Rôle

    diff --git a/src/app/role/RoleTableRows.jsx b/src/app/(dashboard)/role/RoleTableRows.jsx similarity index 97% rename from src/app/role/RoleTableRows.jsx rename to src/app/(dashboard)/role/RoleTableRows.jsx index c937dc003abaa06eb94bcdebe535b758c83843a7..89fcaa45b8e4eaf4466e9d033513258e420b7d66 100644 --- a/src/app/role/RoleTableRows.jsx +++ b/src/app/(dashboard)/role/RoleTableRows.jsx @@ -1,9 +1,9 @@ import React, { useState } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '@/app/lib/fetchRequest' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" import { useNotification } from '@/context/NotificationContext' -import ConfirmationModal from '../ui/ConfirmationModal' +import ConfirmationModal from '@/app/ui/ConfirmationModal' const RoleTableRows = ({ name, setRoles, id, privileges, setRoleToUpdate }) => { const { toggleNotification } = useNotification() diff --git a/src/app/role/UpdateRoleForm.jsx b/src/app/(dashboard)/role/UpdateRoleForm.jsx similarity index 96% rename from src/app/role/UpdateRoleForm.jsx rename to src/app/(dashboard)/role/UpdateRoleForm.jsx index 348ebfce5dc70d57d41f4157b2bb2579c29dafca..685b2ede7813493c55a0491e79b97b190bd48887 100644 --- a/src/app/role/UpdateRoleForm.jsx +++ b/src/app/(dashboard)/role/UpdateRoleForm.jsx @@ -1,9 +1,9 @@ import { useNotification } from '@/context/NotificationContext' import React, { useState, useRef, useEffect, useMemo } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '@/app/lib/fetchRequest' import Loader from '@/components/Loader/Loader' import CancelIcon from "@/static/image/svg/cancel.svg" -import { isArray } from '../lib/TypesHelper' +import { isArray } from '../../lib/TypesHelper' const UpdateRoleForm = ({ setRoleToUpdate, setRoles, roles, privileges: rolePrivileges, name, id }) => { const { toggleNotification } = useNotification() const [loadingStatus, setLoadingStatus] = useState(false) @@ -107,7 +107,7 @@ const UpdateRoleForm = ({ setRoleToUpdate, setRoles, roles, privileges: rolePriv var isAllSelected = useMemo(() => privileges ? privileges.every((element) => selectedPrivileges.find((priv) => priv.id === element.id)) : false, [selectedPrivileges, privileges]) return (
    -
    +
    setRoleToUpdate(null)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> {(privileges) ?

    Modification de Rôle

    diff --git a/src/app/(dashboard)/role/page.jsx b/src/app/(dashboard)/role/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..7e682d2905b647ab1d5de30aeed5354f4ac24a67 --- /dev/null +++ b/src/app/(dashboard)/role/page.jsx @@ -0,0 +1,71 @@ +'use client' +import React, { useState, useEffect } from 'react' +import CreateRoleForm from './CreateRoleForm' +import Loader from '@/components/Loader/Loader' +import RoleTableRows from './RoleTableRows' +import fetchRequest from '@/app/lib/fetchRequest' +import { isArray } from '../../lib/TypesHelper' +import AddIcon from "@/static/image/svg/add.svg" +import UpdateRoleForm from './UpdateRoleForm' +import { useNotification } from '@/context/NotificationContext' +const Role = () => { + const [roles, setRoles] = useState([]) + const [isLoading, setIsLoading] = useState(true) + const [openCreatePopup, setOpenCreatePopup] = useState(null) + const [roleToUpdate, setRoleToUpdate] = useState(null) + const { toggleNotification } = useNotification() + useEffect(() => { + const getRoles = async () => { + const { data, errors, isSuccess } = await fetchRequest("/roles") + setIsLoading(false) + if (isSuccess) { + console.log(data) + setRoles(data) + } else { + console.log(errors) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + getRoles() + }, []) + const appendRole = (newRole) => { + setRoles([newRole, ...roles]) + } + return ( +
    + {openCreatePopup && } + {roleToUpdate && } +
    +

    List des Roles

    + +
    + {isLoading &&
    } + {!isLoading && <> {(!isArray(roles) || roles?.length === 0) + ?
    +

    Pas encore des roles

    +
    + :
    + + + + + + + {roles?.map((element) => { + return + })} +
    RôleHabilitationsAction
    +
    + }} +
    + ) +} + +export default Role \ No newline at end of file diff --git a/src/app/table/CreateNewTable.jsx b/src/app/(dashboard)/table/CreateNewTable.jsx similarity index 75% rename from src/app/table/CreateNewTable.jsx rename to src/app/(dashboard)/table/CreateNewTable.jsx index fc2f3cf647b5ae1d91d7ef0550b455bc98169476..50c0f90b4c82a71065008b09c2a6389c9ffb4cf3 100644 --- a/src/app/table/CreateNewTable.jsx +++ b/src/app/(dashboard)/table/CreateNewTable.jsx @@ -1,6 +1,6 @@ "use client" import React, { useState, useEffect, useRef } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import { Island_Moments } from 'next/font/google' import { useNotification } from '@/context/NotificationContext' @@ -27,7 +27,7 @@ const CreateNewTable = ({ tablesState, zones }) => { }) if (isSuccess) { setIsLoadingAction(false) - tablesState((prevTableState) => [...prevTableState, {...data, id_zone: zones.find(zone => zone.id === data.id_zone)}]); + tablesState((prevTableState) => [...prevTableState, { ...data, id_zone: zones.find(zone => zone.id === data.id_zone) }]); inputRef.current.value = "" selectRef.current.value = "" setNumeroTable(null) @@ -47,7 +47,7 @@ const CreateNewTable = ({ tablesState, zones }) => { visible: true, }) } - }else{ + } else { toggleNotification({ type: "error", message: "Une erreur s'est produite lors de la création de la table.", @@ -72,7 +72,7 @@ const CreateNewTable = ({ tablesState, zones }) => { - return( + return (

    Ajout d'une table

    @@ -82,19 +82,19 @@ const CreateNewTable = ({ tablesState, zones }) => {
    - +

    -
    diff --git a/src/app/table/RowTable.jsx b/src/app/(dashboard)/table/RowTable.jsx similarity index 94% rename from src/app/table/RowTable.jsx rename to src/app/(dashboard)/table/RowTable.jsx index 939d879766957433e271007c4277397f96a944cf..7e16dd22846c0ee0572a6af8ee6f90572fbb3639 100644 --- a/src/app/table/RowTable.jsx +++ b/src/app/(dashboard)/table/RowTable.jsx @@ -1,6 +1,6 @@ "use client" import React, { useState, useEffect, useRef } from 'react'; -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" @@ -42,16 +42,16 @@ const RowZone = ({ id, numero, zone, tablesState, zones }) => { }) setLoadingStatus(false) if (isSuccess) { - if(data.message === "NO_CHANGES"){ + if (data.message === "NO_CHANGES") { toggleNotification({ visible: true, message: "Aucun changement n'a été effectué.", type: "warning" }) setIsUpdating(false) - return + return } - tablesState((prevTableState) => prevTableState.map( (element) => element.id === id ? {...data.data, id_zone: zones.find(zone => zone.id === data.data.id_zone)} : element )) + tablesState((prevTableState) => prevTableState.map((element) => element.id === id ? { ...data.data, id_zone: zones.find(zone => zone.id === data.data.id_zone) } : element)) setIsUpdating(false) toggleNotification({ visible: true, @@ -66,7 +66,7 @@ const RowZone = ({ id, numero, zone, tablesState, zones }) => { message: "Le numero de la table existe déjà", visible: true, }) - }else if (errors.detail.non_field_errors) { + } else if (errors.detail.non_field_errors) { toggleNotification({ type: "warning", message: "Le numero de la table saisie déjà existe.", @@ -173,15 +173,15 @@ const RowZone = ({ id, numero, zone, tablesState, zones }) => { setModalOpen(false); }; - return( + return ( setTableNum(event.target.value)} defaultValue={numero} type='text' className='disabled:bg-white border-0 rounded-md px-2 enabled:drop-shadow border-none enabled:bg-gray-100 duration-100 h-10 outline-none' /> {handleSearchingTable(e)}} id="simple-search" class=" text-gray-900 text-sm block w-full ps-10 p-2.5 rounded-md px-3 duration-150 delay-75 focus:ring ring-offset-1 ring-sushi-200 border h-10 border-neutral-300 outline-none " placeholder="Chercher des tables..." required /> + { handleSearchingTable(e) }} id="simple-search" class=" text-gray-900 text-sm block w-full ps-10 p-2.5 rounded-md px-3 duration-150 delay-75 focus:ring ring-offset-1 ring-sushi-200 border h-10 border-neutral-300 outline-none " placeholder="Chercher des tables..." required />
    - - {isArray(tables) && tables?.length !== 0 && isArray(zones) && zones?.length !== 0 ? + + {isArray(tables) && tables?.length !== 0 && isArray(zones) && zones?.length !== 0 ?
    - + @@ -91,18 +91,18 @@ const Table = ()=> { })}
    TableTable Zone-Etage Action
    - : -
    -

    Pas encore des tables

    -
    } + : +
    +

    Pas encore des tables

    +
    } :
    - } + }
    - + ) } diff --git a/src/app/user/CreateUserForm.jsx b/src/app/(dashboard)/user/CreateUserForm.jsx similarity index 96% rename from src/app/user/CreateUserForm.jsx rename to src/app/(dashboard)/user/CreateUserForm.jsx index 1b4540dded96560ea804cbd0e84475a0e820fc27..90b1799188babe16e5bd34edb82d23fff6f07fbd 100644 --- a/src/app/user/CreateUserForm.jsx +++ b/src/app/(dashboard)/user/CreateUserForm.jsx @@ -1,9 +1,9 @@ import React, { useState, useEffect } from 'react' import Loader from '@/components/Loader/Loader' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import { useNotification } from '@/context/NotificationContext' import CancelIcon from "@/static/image/svg/cancel.svg" -import { EMAIL_REGEX } from '../lib/constants' +import { EMAIL_REGEX } from '../../lib/constants' @@ -154,8 +154,8 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => { } return (
    -
    - setIsOpen(false)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> +
    + setIsOpen(false)} className="h-8 w-8 cursor-pointer md:absolute fixed top-2 right-2 fill-neutral-600" /> {(roles && projects) ?

    Ajout d'utilisateur

    @@ -183,7 +183,7 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {
    -
    +
    {roles.length !== 0 ?
    @@ -171,7 +171,7 @@ const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => {
    }
    -
    +
    diff --git a/src/app/user/UserTableRow.jsx b/src/app/(dashboard)/user/UserTableRow.jsx similarity index 97% rename from src/app/user/UserTableRow.jsx rename to src/app/(dashboard)/user/UserTableRow.jsx index e0575321e03509d921e81fa70d03b2846fa3073a..b198fc89feb5e59f7676aefd48bc2d0d471c8440 100644 --- a/src/app/user/UserTableRow.jsx +++ b/src/app/(dashboard)/user/UserTableRow.jsx @@ -1,9 +1,9 @@ import React, { useState } from 'react' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" -import ConfirmationModal from '../ui/ConfirmationModal' +import ConfirmationModal from '../../ui/ConfirmationModal' import { useNotification } from '@/context/NotificationContext' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projects, setUserToUpdate }) => { const { toggleNotification } = useNotification() @@ -56,7 +56,7 @@ const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projec

    {role?.name || ""}

    - +
      {(!projects || projects.length === 0) &&

      -

      } {projects?.map((project) => { diff --git a/src/app/(dashboard)/user/page.jsx b/src/app/(dashboard)/user/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..faa6c8edee92016ceef322ba97bdd8dc1a4fe5fb --- /dev/null +++ b/src/app/(dashboard)/user/page.jsx @@ -0,0 +1,117 @@ +'use client'; +import React, { useEffect, useState } from 'react' +import CreateUserForm from './CreateUserForm' +import UpdateUserForm from './UpdateUserForm' +import AddIcon from "@/static/image/svg/add.svg" +import Loader from '@/components/Loader/Loader' +import fetchRequest from '../../lib/fetchRequest'; +import { isArray } from '../../lib/TypesHelper'; +import { useNotification } from '@/context/NotificationContext'; +import UserTableRow from './UserTableRow'; +import { PAGINATION_SIZE } from '../../lib/constants'; +import ArrowRightIcon from "@/static/image/svg/chevron-right.svg" +import ArrowLeftIcon from "@/static/image/svg/chevron-left.svg" +const UserPage = () => { + const [users, setUsers] = useState([]) + const [paginationData, setPaginationData] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const [openCreatePopup, setOpenCreatePopup] = useState(null) + const [userToUpdate, setUserToUpdate] = useState(null) + const { toggleNotification } = useNotification() + const [query, setQuery] = useState(''); + const getUsers = async (pageNumber = 1, signal) => { + setIsLoading(true) + if (search) var { data, errors, isSuccess } = await fetchRequest(`/users/?page=${pageNumber}&search=${query}`, { signal: signal }) + else var { data, errors, isSuccess } = await fetchRequest(`/users/?page=${pageNumber}`) + setIsLoading(false) + if (isSuccess) { + console.log(data) + setUsers(data.results) + setPaginationData({ pagesNumber: Math.ceil((data.count || 0) / PAGINATION_SIZE), currentPage: pageNumber }) + } else { + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + useEffect(() => { + const controller = new AbortController() + const signal = controller.signal + getUsers(1, signal) + return () => { + controller.abort("fetching another users") + } + }, [query]) + const appendUser = (newUser) => { + setUsers([newUser, ...users]) + } + + const handleSearchChange = (event) => { + setQuery(event.target.value) + } + return ( +
      + {openCreatePopup && } + {userToUpdate && } +
      + +
      +
      +

      List des Utilisateurs

      + +
      + {(isLoading) &&
      } + {(!isLoading) && <> {(!isArray(users) || users?.length === 0) + ?
      +

      Pas encore des utilisateurs

      +
      + : +
      + + + + + + + + + {users?.map((element) => { + return + })} + +
      NomEmailRôleProjectsAction
      +
      } + + } +
      + {(paginationData) &&
      + {(paginationData.currentPage > 1) &&
      getUsers(paginationData.currentPage - 1)} className='flex cursor-pointer hover:bg-neutral-200 duration-150 delay-75 h-8 w-9 items-center justify-center'> + +
      } + {paginationData && Array.from({ length: paginationData.pagesNumber }, (_, index) => index).map((element, index) => { + if (element + 1 === paginationData.currentPage + 3) return

      + ... +

      + else if (paginationData.currentPage === element + 1) return

      + {element + 1} +

      + else if (paginationData.currentPage < element + 3 && element - paginationData.currentPage < 3) return

      getUsers(element + 1)} key={element} className='h-8 w-9 hover:bg-neutral-200 cursor-pointer duration-150 delay-75 font-bold text-neutral-700 text-sm flex items-center justify-center' > + {element + 1} +

      + else return <> + })} + {(paginationData.currentPage !== paginationData.pagesNumber) &&
      getUsers(paginationData.currentPage + 1)} className='flex h-8 w-9 items-center hover:bg-neutral-200 duration-150 delay-75 cursor-pointer justify-center'> + +
      } +
      } +
      +
      + ) +} + +export default UserPage \ No newline at end of file diff --git a/src/app/zone/CreateNewZone.jsx b/src/app/(dashboard)/zone/CreateNewZone.jsx similarity index 74% rename from src/app/zone/CreateNewZone.jsx rename to src/app/(dashboard)/zone/CreateNewZone.jsx index 76b78c6076fb6c1c0d46c89848de0d8aca664fb9..ccd197d696d5495ceedb37510bf7c42e70c6c927 100644 --- a/src/app/zone/CreateNewZone.jsx +++ b/src/app/(dashboard)/zone/CreateNewZone.jsx @@ -1,6 +1,6 @@ "use client" import React, { useState, useEffect, useRef } from 'react' -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import { Island_Moments } from 'next/font/google' import { useNotification } from '@/context/NotificationContext' @@ -27,7 +27,7 @@ const CreateNewZone = ({ zoneState, etages }) => { }) if (isSuccess) { setIsLoadingAction(false) - zoneState((prevZoneValue) => [...prevZoneValue, {...data, id_etage: etages.find(etage => etage.id === data.id_etage)}]); + zoneState((prevZoneValue) => [...prevZoneValue, { ...data, id_etage: etages.find(etage => etage.id === data.id_etage) }]); inputRef.current.value = "" selectRef.current.value = "" setNomZone(null) @@ -47,7 +47,7 @@ const CreateNewZone = ({ zoneState, etages }) => { visible: true, }) } - }else{ + } else { toggleNotification({ type: "error", message: "Une erreur s'est produite lors de la création de la zone.", @@ -74,7 +74,7 @@ const CreateNewZone = ({ zoneState, etages }) => { - return( + return (

      Ajout d'une zone

      @@ -84,19 +84,19 @@ const CreateNewZone = ({ zoneState, etages }) => {
      - +

    -
    diff --git a/src/app/zone/RowZone.jsx b/src/app/(dashboard)/zone/RowZone.jsx similarity index 95% rename from src/app/zone/RowZone.jsx rename to src/app/(dashboard)/zone/RowZone.jsx index baebd3ac5f5fbc663a5c4c91e7f3931a51d67f14..bb1be7ddedb25427d3dcaaa274c23e8f98007fcb 100644 --- a/src/app/zone/RowZone.jsx +++ b/src/app/(dashboard)/zone/RowZone.jsx @@ -1,6 +1,6 @@ "use client" import React, { useState, useEffect, useRef } from 'react'; -import fetchRequest from '../lib/fetchRequest' +import fetchRequest from '../../lib/fetchRequest' import Loader from '@/components/Loader/Loader' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" @@ -42,7 +42,7 @@ const RowZone = ({ id, nom, etage, zonesState, etages }) => { setLoadingStatus(false) if (isSuccess) { console.log(data) - if(data.message === "NO_CHANGES"){ + if (data.message === "NO_CHANGES") { toggleNotification({ visible: true, message: "Aucun changement n'a été effectué.", @@ -52,7 +52,7 @@ const RowZone = ({ id, nom, etage, zonesState, etages }) => { return } console.log(data.data) - zonesState((prevZonesValue) => prevZonesValue.map( (element) => element.id === id ? {...data.data, id_etage: etages.find(etage => etage.id === data.data.id_etage)} : element )) + zonesState((prevZonesValue) => prevZonesValue.map((element) => element.id === id ? { ...data.data, id_etage: etages.find(etage => etage.id === data.data.id_etage) } : element)) setIsUpdating(false) toggleNotification({ visible: true, @@ -67,7 +67,7 @@ const RowZone = ({ id, nom, etage, zonesState, etages }) => { message: "Le nom de la zone existe déjà", visible: true, }) - }else if (errors.detail.non_field_errors) { + } else if (errors.detail.non_field_errors) { toggleNotification({ type: "warning", message: "Le nom de la zone saisie déjà existe.", @@ -174,15 +174,15 @@ const RowZone = ({ id, nom, etage, zonesState, etages }) => { setModalOpen(false); }; - return( + return ( setZoneName(event.target.value)} defaultValue={nom} type='text' className='disabled:bg-white border-0 rounded-md px-2 enabled:drop-shadow border-none enabled:bg-gray-100 duration-100 h-10 outline-none' /> - - - - - - - -
    -
    - -
    -
    -
    -
    -
    - -
    -

    : 50

    -
    -
    -
    - -
    -

    : 50

    -
    -
    -
    -
    - - -
    -
    -
    20
    - -
    - restant -
    -
    -
    -
    -

    Veuillez sélectionner une autre zonne (optionnel)

    -
    - -
    -

    Places: 50

    -
    -
    -
    -
    - -
    -
    - -
    -
    - ) -} - -export default AssignProject \ No newline at end of file diff --git a/src/app/assign_zone_project/page.jsx b/src/app/assign_zone_project/page.jsx deleted file mode 100644 index 02831647fd8869b268d4294c2d346193a01f1554..0000000000000000000000000000000000000000 --- a/src/app/assign_zone_project/page.jsx +++ /dev/null @@ -1,146 +0,0 @@ -"use client" -import React, { useState } from 'react'; -import AddIcon from "@/static/image/svg/add.svg"; -import AssignProject from './AssignProject'; - - -const AffectingZoneProject = () => { - const [isOpen, setIsOpen] = useState(false) - - - const handleOpenAssignProject = () => { - setIsOpen(!isOpen) - } - return ( -
    -
    - {isOpen && } -

    List des Projets attribuer

    -
    - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Date - - Plateau - - Projet - - Places occupées - - Nombre des personnes - - Places disponible - - Actions -
    - Apple MacBook Pro 17" - - Silver - - Laptop - - $2999 - - $2999 - - $2999 - - Edit -
    - Apple MacBook Pro 17" - - Silver - - Laptop - - $2999 - - $2999 - - $2999 - - Edit -
    - Apple MacBook Pro 17" - - Silver - - Laptop - - $2999 - - $2999 - - $2999 - - Edit -
    -
    - - ); -} - - -export default AffectingZoneProject; \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index 83bb86b29ca5fa8da57892f56d4c513438b7b93b..20a77109e6c82197c14a84e414576d61c368ee32 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -39,22 +39,27 @@ -o-transition: max-height .35s; transition: max-height .35s; } + /* :checked - resize to full height */ -.tab input:checked ~ .tab-content { +.tab input:checked~.tab-content { max-height: 100%; } + /* Label formatting when open */ -.tab input:checked + label{ +.tab input:checked+label { /*@apply text-xl p-5 border-l-2 border-indigo-500 bg-gray-100 text-indigo*/ - font-size: 1.25rem; /*.text-xl*/ - padding: 1.25rem; /*.p-5*/ + font-size: 1.25rem; + /*.text-xl*/ + padding: 1.25rem; + /*.p-5*/ /*border-left-width: 2px; !*.border-l-2*!*/ /*border-color: #93a84c; !*.border-indigo*!*/ /*color: #93a84c; !*.text-indigo*!*/ } + /* Icon */ .tab label::after { - float:right; + float: right; right: 0; top: 0; display: block; @@ -67,29 +72,133 @@ -o-transition: all .35s; transition: all .35s; } + /* Icon formatting - closed */ -.tab input[type=checkbox] + label::after { +.tab input[type=checkbox]+label::after { content: "+"; - font-weight:bold; /*.font-bold*/ - border-width: 1px; /*.border*/ - border-radius: 9999px; /*.rounded-full */ - border-color: #5c5c5c; /*.border-grey*/ + font-weight: bold; + /*.font-bold*/ + border-width: 1px; + /*.border*/ + border-radius: 9999px; + /*.rounded-full */ + border-color: #5c5c5c; + /*.border-grey*/ } -.tab input[type=radio] + label::after { + +.tab input[type=radio]+label::after { content: "\25BE"; - font-weight:bold; /*.font-bold*/ - border-width: 1px; /*.border*/ - border-radius: 9999px; /*.rounded-full */ - border-color: #5c5c5c; /*.border-grey*/ + font-weight: bold; + /*.font-bold*/ + border-width: 1px; + /*.border*/ + border-radius: 9999px; + /*.rounded-full */ + border-color: #5c5c5c; + /*.border-grey*/ } + /* Icon formatting - open */ -.tab input[type=checkbox]:checked + label::after { +.tab input[type=checkbox]:checked+label::after { transform: rotate(315deg); - background-color: #93a84c; /*.bg-indigo*/ - color: #f8fafc; /*.text-grey-lightest*/ + background-color: #93a84c; + /*.bg-indigo*/ + color: #f8fafc; + /*.text-grey-lightest*/ } -.tab input[type=radio]:checked + label::after { + +.tab input[type=radio]:checked+label::after { transform: rotateX(180deg); - background-color: #93a84c; /*.bg-indigo*/ - color: #f8fafc; /*.text-grey-lightest*/ + background-color: #93a84c; + /*.bg-indigo*/ + color: #f8fafc; + /*.text-grey-lightest*/ +} + +.burger.notActive { + height: 4px; + width: 17px; + border-radius: 5px; + background-color: white; + position: relative; + transition: all 0.2s; +} + +.burger.active { + height: 4px; + width: 17px; + border-radius: 5px; + position: relative; + transition: all 0.2s; + opacity: 1; +} + +.burger.active::before { + content: ""; + position: absolute; + top: 8px; + right: 0; + height: 4px; + width: 25px; + border-radius: 5px; + background-color: white; + transform: rotate(-45deg) translate(6px, -6px); + transition: transform 0.2s; +} + +.burger.active::after { + content: ""; + position: absolute; + top: -8px; + right: 0; + height: 4px; + width: 25px; + border-radius: 5px; + background-color: white; + transform: rotate(45deg) translate(5px, 6px); + transition: transform 0.2s; +} + +.burger.notActive::before { + content: ""; + position: absolute; + top: 8px; + right: 0; + height: 4px; + width: 25px; + border-radius: 5px; + background-color: white; + transform: rotate(0) translate(0, 0); + transition: transform 0.2s; +} + +.burger.notActive::after { + content: ""; + position: absolute; + top: -8px; + right: 0; + height: 4px; + width: 25px; + border-radius: 5px; + background-color: white; + transform: rotate(0) translate(0, 0); + transition: transform 0.2s; +} + +#sideBar { + white-space: no-wrap; + height: calc(100dvh - 3.5rem); +} + +@media screen and (max-width:767px) { + #sideBar.active { + width: 100%; + transition-duration: 300ms; + } + + + #sideBar.notActive { + width: 0; + transition-duration: 300ms + } } \ No newline at end of file diff --git a/src/app/layout.js b/src/app/layout.js index 45c21613310f3980d4975a0ebb436337cd7e5b89..52fe06b6e04cf038208f3a8d0927cf9ceeb9437c 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -14,7 +14,6 @@ export default function RootLayout({ children }) { return ( -
    {children} diff --git a/src/app/planning/layout.jsx b/src/app/planning/layout.jsx deleted file mode 100644 index 6386ecbf10b56086248866048fab55809866386e..0000000000000000000000000000000000000000 --- a/src/app/planning/layout.jsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import SideBar from "@/app/ui/SideBar"; -import ProjectForm from "@/app/projects/ProjectForm"; -import ProjectList from "@/app/projects/ProjectList"; - -// layout for the planning page -export default function PlanningLayout ({ children }) { - return ( -
    -
    - -
    - -
    -
    - {children} -
    -
    -
    - ); - -} - diff --git a/src/app/privilege/page.jsx b/src/app/privilege/page.jsx deleted file mode 100644 index 46c9515f8523b64d56f4b60cedc04afaffeaf2fb..0000000000000000000000000000000000000000 --- a/src/app/privilege/page.jsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client' -import React, { useEffect, useState } from 'react' -import CreatePrivilegeForm from './CreatePrivilegeForm' -import fetchRequest from '../lib/fetchRequest' -import { isArray } from '../lib/TypesHelper' -import PrivilegeTableRows from './PrivilegeTableRow' -import Loader from '@/components/Loader/Loader' -const Privilege = () => { - const [privileges, setPrivileges] = useState([]) - const [isLoading, setIsLoading] = useState(true) - useEffect(() => { - const getPrivileges = async () => { - const { data, errors, isSuccess } = await fetchRequest("/privileges") - setIsLoading(false) - if (isSuccess) { - setPrivileges(data) - } else { - console.log(errors) - } - } - getPrivileges() - }, []) - const appendPrivilege = (privilege) => { - setPrivileges((data) => [privilege, ...data]) - } - return ( -
    -
    -
    - -

    List des habilitations

    - {isLoading &&
    } - {!isLoading && <> {(!isArray(privileges) || privileges?.length === 0) - ?
    -

    Pas encore des habilitations

    -
    - :
    - - - - - - {privileges.map((element) => { - return - })} -
    HabilitationAction
    -
    - }} -
    -
    -
    - ) -} - -export default Privilege \ No newline at end of file diff --git a/src/app/role/page.jsx b/src/app/role/page.jsx deleted file mode 100644 index 411c32f224b7080f45d8f933a48805edd67ee899..0000000000000000000000000000000000000000 --- a/src/app/role/page.jsx +++ /dev/null @@ -1,75 +0,0 @@ -'use client' -import React, { useState, useEffect } from 'react' -import CreateRoleForm from './CreateRoleForm' -import Loader from '@/components/Loader/Loader' -import RoleTableRows from './RoleTableRows' -import fetchRequest from '../lib/fetchRequest' -import { isArray } from '../lib/TypesHelper' -import AddIcon from "@/static/image/svg/add.svg" -import UpdateRoleForm from './UpdateRoleForm' -import { useNotification } from '@/context/NotificationContext' -const Role = () => { - const [roles, setRoles] = useState([]) - const [isLoading, setIsLoading] = useState(true) - const [openCreatePopup, setOpenCreatePopup] = useState(null) - const [roleToUpdate, setRoleToUpdate] = useState(null) - const { toggleNotification } = useNotification() - useEffect(() => { - const getRoles = async () => { - const { data, errors, isSuccess } = await fetchRequest("/roles") - setIsLoading(false) - if (isSuccess) { - console.log(data) - setRoles(data) - } else { - console.log(errors) - toggleNotification({ - visible: true, - message: "Internal Server Error", - type: "error" - }) - } - } - getRoles() - }, []) - const appendRole = (newRole) => { - setRoles([newRole, ...roles]) - } - return ( -
    -
    -
    - {openCreatePopup && } - {roleToUpdate && } -
    -

    List des Roles

    - -
    - {isLoading &&
    } - {!isLoading && <> {(!isArray(roles) || roles?.length === 0) - ?
    -

    Pas encore des roles

    -
    - :
    - - - - - - - {roles?.map((element) => { - return - })} -
    RôleHabilitationsAction
    -
    - }} -
    -
    -
    - ) -} - -export default Role \ No newline at end of file diff --git a/src/app/ui/Burger.jsx b/src/app/ui/Burger.jsx new file mode 100644 index 0000000000000000000000000000000000000000..68fafffc6e1e517818b064b228030666f87365b6 --- /dev/null +++ b/src/app/ui/Burger.jsx @@ -0,0 +1,25 @@ +'use client' +import React from 'react' + +const Burger = () => { + const dislaySideBar = (event) => { + const target = event.currentTarget.firstChild + const sideBar = document.getElementById("sideBar") + if (target && sideBar) + if (target.classList.contains("active")) { + target.classList.replace("active", "notActive") + sideBar.classList.replace("active", "notActive") + } + else { + target.classList.replace("notActive", "active") + sideBar.classList.replace("notActive", "active") + } + } + return ( +
    +
    +
    + ) +} + +export default Burger \ No newline at end of file diff --git a/src/app/ui/Header.jsx b/src/app/ui/Header.jsx index bb048c4d74e5e6a2616f01a3b8ff78f878267458..4112e77a7e7f45f1b4649b876531e297915da56a 100644 --- a/src/app/ui/Header.jsx +++ b/src/app/ui/Header.jsx @@ -1,40 +1,35 @@ // 'use client'; -// import { useState, useEffect } from 'react'; import Link from 'next/link'; -// import isAuthenticated from "@/app/lib/isAuthenticated"; import isAuthenticatedSSR from "@/app/lib/isAuthenticatedSSR"; import LogoutButton from "@/app/ui/LogoutButton"; -// import fetchRequest from "@/app/lib/fetchRequest"; -// import Cookies from "js-cookie"; +import Burger from './Burger'; const Header = async () => { - const {isAuth, sessionData} = await isAuthenticatedSSR() + const { isAuth, sessionData } = await isAuthenticatedSSR() console.log('isAuth', isAuth) console.log('sessionData', sessionData) return ( -
    -
    +
    +

    TeamBook

    - ); } export default SideBar; \ No newline at end of file diff --git a/src/app/ui/SideBarLink.jsx b/src/app/ui/SideBarLink.jsx new file mode 100644 index 0000000000000000000000000000000000000000..33595a7106889a45543dde90a121d552c9274827 --- /dev/null +++ b/src/app/ui/SideBarLink.jsx @@ -0,0 +1,22 @@ +'use client' +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import React from 'react' +const SideBarLink = ({ link, label }) => { + const pathname = usePathname() + if (pathname && pathname.includes(link)) + return ( +
    + + {label} + +
    + ) + return
    + + {label} + +
    +} + +export default SideBarLink \ No newline at end of file diff --git a/src/app/user/page.jsx b/src/app/user/page.jsx deleted file mode 100644 index de82ec7b2e39c034cebdb294b46644b769a81f0a..0000000000000000000000000000000000000000 --- a/src/app/user/page.jsx +++ /dev/null @@ -1,119 +0,0 @@ -'use client'; -import React, { useEffect, useState, useDeferredValue } from 'react' -import CreateUserForm from './CreateUserForm' -import UpdateUserForm from './UpdateUserForm' -import AddIcon from "@/static/image/svg/add.svg" -import Loader from '@/components/Loader/Loader' -import fetchRequest from '../lib/fetchRequest'; -import { isArray } from '../lib/TypesHelper'; -import { useNotification } from '@/context/NotificationContext'; -import UserTableRow from './UserTableRow'; -import { PAGINATION_SIZE } from '../lib/constants'; -import ArrowRightIcon from "@/static/image/svg/chevron-right.svg" -import ArrowLeftIcon from "@/static/image/svg/chevron-left.svg" -const UserPage = () => { - const [users, setUsers] = useState([]) - const [paginationData, setPaginationData] = useState(null) - const [isLoading, setIsLoading] = useState(true) - const [openCreatePopup, setOpenCreatePopup] = useState(null) - const [userToUpdate, setUserToUpdate] = useState(null) - const { toggleNotification } = useNotification() - const [query, setQuery] = useState(''); - const getUsers = async (pageNumber = 1, signal) => { - setIsLoading(true) - if (search) var { data, errors, isSuccess } = await fetchRequest(`/users/?page=${pageNumber}&search=${query}`, { signal: signal }) - else var { data, errors, isSuccess } = await fetchRequest(`/users/?page=${pageNumber}`) - setIsLoading(false) - if (isSuccess) { - console.log(data) - setUsers(data.results) - setPaginationData({ pagesNumber: Math.ceil((data.count || 0) / PAGINATION_SIZE), currentPage: pageNumber }) - } else { - toggleNotification({ - visible: true, - message: "Internal Server Error", - type: "error" - }) - } - } - useEffect(() => { - const controller = new AbortController() - const signal = controller.signal - getUsers(1, signal) - return () => { - controller.abort("fetching another users") - } - }, [query]) - const appendUser = (newUser) => { - setUsers([newUser, ...users]) - } - - const handleSearchChange = (event) => { - setQuery(event.target.value) - } - return (
    -
    -
    - {openCreatePopup && } - {userToUpdate && } -
    -

    List des Utilisateurs

    - -
    -
    - -
    - {(isLoading) &&
    } - {(!isLoading) && <> {(!isArray(users) || users?.length === 0) - ?
    -

    Pas encore des utilisateurs

    -
    - : -
    - - - - - - - - - {users?.map((element) => { - return - })} -
    NomEmailRôleProjectsAction
    -
    } - - } -
    - {(paginationData) &&
    - {(paginationData.currentPage > 1) &&
    getUsers(paginationData.currentPage - 1)} className='flex cursor-pointer hover:bg-neutral-200 duration-150 delay-75 h-8 w-9 items-center justify-center'> - -
    } - {paginationData && Array.from({ length: paginationData.pagesNumber }, (_, index) => index).map((element, index) => { - if (element + 1 === paginationData.currentPage + 3) return

    - ... -

    - else if (paginationData.currentPage === element + 1) return

    - {element + 1} -

    - else if (paginationData.currentPage < element + 3 && element - paginationData.currentPage < 3) return

    getUsers(element + 1)} key={element} className='h-8 w-9 hover:bg-neutral-200 cursor-pointer duration-150 delay-75 font-bold text-neutral-700 text-sm flex items-center justify-center' > - {element + 1} -

    - else return <> - })} - {(paginationData.currentPage !== paginationData.pagesNumber) &&
    getUsers(paginationData.currentPage + 1)} className='flex h-8 w-9 items-center hover:bg-neutral-200 duration-150 delay-75 cursor-pointer justify-center'> - -
    } -
    } -
    -
    -
    -
    - ) -} - -export default UserPage \ No newline at end of file diff --git a/src/static/image/no-data.png b/src/static/image/no-data.png new file mode 100644 index 0000000000000000000000000000000000000000..90f0083b8a12e1f6b08f3dd3c2e301a81562afd4 Binary files /dev/null and b/src/static/image/no-data.png differ diff --git a/src/static/image/svg/logout.svg b/src/static/image/svg/logout.svg new file mode 100644 index 0000000000000000000000000000000000000000..932b461902b4b748292a2eea4dcbb18a26c78e0b --- /dev/null +++ b/src/static/image/svg/logout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/image/svg/role.svg b/src/static/image/svg/role.svg new file mode 100644 index 0000000000000000000000000000000000000000..d8f13942ea7db906be026abcc4c5d7cf50b481ca --- /dev/null +++ b/src/static/image/svg/role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/image/svg/simple-table.svg b/src/static/image/svg/simple-table.svg new file mode 100644 index 0000000000000000000000000000000000000000..178f298407e0fe124529c42a9332f8c95c84e0b3 --- /dev/null +++ b/src/static/image/svg/simple-table.svg @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file