diff --git a/src/app/(dashboard)/planning/PlanningTable.jsx b/src/app/(dashboard)/planning/PlanningTable.jsx
index 0db1822080d008a6a286261b3dfbb57f361cd64f..2a958056b4269a714a7bda378ae5f6a63a24c7dc 100644
--- a/src/app/(dashboard)/planning/PlanningTable.jsx
+++ b/src/app/(dashboard)/planning/PlanningTable.jsx
@@ -1,26 +1,139 @@
import React, {useEffect, useState} from 'react';
import fetchRequest from "@/app/lib/fetchRequest";
import {useNotification} from "@/context/NotificationContext";
+import {blankData} from "@/app/lib/constants";
+import ConfirmationModal from "@/app/ui/ConfirmationModal";
+import ArrowUturnLeft from "@/static/image/svg/arrow-uturn-left.svg";
+import DeleteIcon from "@/static/image/svg/trash-bold.svg";
+import EditIcon from "@/static/image/svg/edit.svg";
-const PlanningTable = ({ data, typePresences, onTypePresenceChange, selectedProject }) => {
+const PlanningTable = ({ project, typePresences}) => {
// fetch type presence
const [errors, setErrors] = useState();
const [loading, setLoading] = useState(false);
const {toggleNotification} = useNotification()
const [selectedPresence, setSelectedPresence] = useState('');
+ const [planningData, setPlanningData] = useState(project.planning ? project.planning : blankData);
+ const [isModalOpen, setModalOpen] = useState(false);
+
+ const handleSave = async () => {
+ // verify if planing data has an empty value
+ const emptyValue = planningData.planning_data.some(week => week.days.some(day => day.nom === ''));
+ if (emptyValue) {
+ toggleNotification({
+ visible: true,
+ message: 'Veuillez remplir toutes les valeurs de planification',
+ type: 'error'
+ });
+ return;
+ }
+ setLoading(true);
+ const requestBody = {id_project: project.id, planning_data: planningData.planning_data};
+ console.log({id_project: project.id, planning_data: planningData.planning_data})
+ const {isSuccess, errors,data} = await fetchRequest(`/plannings/`, {
+ method: 'POST',
+ body: JSON.stringify(requestBody)
+ });
+ setLoading(false);
+ if (isSuccess) {
+ toggleNotification({
+ visible: true,
+ message: 'Données de planification enregistrées avec succès',
+ type: 'success'
+ });
+ setPlanningData(data);
+ } else {
+ setErrors(errors);
+ toggleNotification({
+ visible: true,
+ message: 'Échec de lenregistrement des données de planification',
+ type: 'error'
+ });
+ }
+ };
+
+ const handleUpdate = async () => {
+ setLoading(true);
+ const requestBody = {id_project: project.id, planning_data: planningData.planning_data};
+ const {isSuccess, errors} = await fetchRequest(`/plannings/${planningData.id}/`, {
+ method: 'PUT',
+ body: JSON.stringify(requestBody)
+ });
+ setLoading(false);
+ if (isSuccess) {
+ toggleNotification({
+ visible: true,
+ message: 'Données de planification mises à jour avec succès',
+ type: 'success'
+ });
+ } else {
+ setErrors(errors);
+ toggleNotification({
+ visible: true,
+ message: 'Échec de la mise à jour des données de planification',
+ type: 'error'
+ });
+ }
+ }
+
+ const handleDelete = async () => {
+ setLoading(true);
+ // delete by planning id not project id
+ const {isSuccess, errors} = await fetchRequest(`/plannings/${planningData.id}/`, {
+ method: 'DELETE'
+ });
+ setLoading(false);
+ if (isSuccess) {
+ setPlanningData(blankData);
+ toggleNotification({
+ visible: true,
+ message: 'Données de planification supprimées avec succès',
+ type: 'success'
+ });
+ } else {
+ setErrors(errors);
+ toggleNotification({
+ visible: true,
+ message: 'Échec de la suppression des données de planification',
+ type: 'error'
+ });
+ }
+ };
+ const handleDeleteClick = () => {
+ setModalOpen(true);
+ };
+ const handleConfirmDelete = () => {
+ handleDelete();
+ setModalOpen(false);
+ };
+ const handleTypePresenceChange = (weekIndex, dayIndex, value) => {
+ // const updatedData = {...planningData};
+ // get the presence type by id (value is a string convert it to int
+ const typePresence = typePresences.find(typePresence => typePresence.id === parseInt(value));
+
+ // the value I want to add should be {"id": 1, "nom": "Travail à Temps Partiel"} and not just the id
+ // updatedData.planning_data[weekIndex].days[dayIndex] = typePresence;
+ // setPlanningData(updatedData);
+ setPlanningData((prevData) => { // prevData is the previous state of planningData
+ const updatedData = {...prevData};
+ updatedData.planning_data[weekIndex].days[dayIndex] = typePresence;
+ return updatedData;
+ });
+ };
const handleRadioChange = (e) => {
const newPresence = e.target.value;
setSelectedPresence(newPresence);
- data.forEach((row, rowIndex) => {
+ console.log('sata',planningData);
+ planningData?.planning_data.forEach((row, rowIndex) => {
row.days.forEach((day, dayIndex) => {
- onTypePresenceChange(rowIndex, dayIndex, newPresence);
+ handleTypePresenceChange(rowIndex, dayIndex, newPresence);
});
});
};
return (
-
+
Réglez Tout sur :
{typePresences.map((typePresence) => (
@@ -38,27 +151,27 @@ const PlanningTable = ({ data, typePresences, onTypePresenceChange, selectedProj
))}
-
-
- | Semaine/Jour |
- J1 |
- J2 |
- J3 |
- J4 |
- J5 |
+
+
+ | Semaine/Jour |
+ Lundi (J1) |
+ Mardi (J2) |
+ Mercredi (J3) |
+ Jeudi (J4) |
+ Vendredi (J5) |
- {data.map((row, rowIndex) => (
-
- | Semaine {row.week} |
+ {planningData?.planning_data.map((row, rowIndex) => (
+
+ | Semaine {row.week} |
{row.days.map((day, dayIndex) => (
-
+ |
|
+ {/* crud for buttons*/}
+
+
+ {planningData.id ?
+ <>
+
+
+ > :
+
+ }
+
+
+
+
setModalOpen(false)}
+ onConfirm={handleConfirmDelete}
+ message={`Etes-vous sûr de vouloir supprimer ces données de planification ?`}
+ />
);
};
diff --git a/src/app/(dashboard)/planning/page.jsx b/src/app/(dashboard)/planning/page.jsx
index f6dc6d33ac762cd5301da62de4c97a9ae1ac4785..e2237139c66fc0ede6705b67a7c5891851d1758a 100644
--- a/src/app/(dashboard)/planning/page.jsx
+++ b/src/app/(dashboard)/planning/page.jsx
@@ -1,34 +1,27 @@
'use client';
-import { useEffect, useState } from 'react';
+import React, {useEffect, useState} from 'react';
import Dropdown from "@/app/ui/Dropdown";
import PlanningTable from "@/app/(dashboard)/planning/PlanningTable";
import fetchRequest from "@/app/lib/fetchRequest";
-import { useNotification } from "@/context/NotificationContext";
+import {useNotification} from "@/context/NotificationContext";
import ConfirmationModal from "@/app/ui/ConfirmationModal";
+import ArrowUturnLeft from "@/static/image/svg/arrow-uturn-left.svg";
+import SearchIcon from "@/static/image/svg/search.svg";
+import AddChart from "@/static/image/svg/addchart.svg";
+import TypePresence from "@/app/(dashboard)/planning/type-presence/TypePresence";
+import Accordion from "@/app/ui/Accordion";
+import {blankData} from "@/app/lib/constants";
const PlanningPage = () => {
- const blankData = {
- planning_data: [
- { week: 1, days: [{"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}] },
- { week: 2, days: [{"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}] },
- { week: 3, days: [{"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}] },
- { week: 4, days: [{"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}] },
- { week: 5, days: [{"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}, {"id": 2, "nom": "Teletravail"}] },
- ]
- }
const [projects, setProjects] = useState([]);
- const [selectedProject, setSelectedProject] = useState('');
- const [planningData, setPlanningData] = useState(blankData);
+ const [selectedProject, setSelectedProject] = useState({});
const [errors, setErrors] = useState();
- const [loading, setLoading] = useState(false);
- const { toggleNotification } = useNotification();
const [typePresences, setTypePresences] = useState([]);
- const [isModalOpen, setModalOpen] = useState(false);
-
+ const [openPopup, setOpenPopup] = useState(false);
const fetchProjects = async () => {
- const { isSuccess, errors, data } = await fetchRequest('/projects/');
+ const {isSuccess, errors, data} = await fetchRequest('/projects/');
if (isSuccess) {
setProjects(data);
setErrors(null);
@@ -42,34 +35,17 @@ const PlanningPage = () => {
fetchProjects();
}, []);
- const handleProjectChange = (e) => setSelectedProject(e.target.value);
-
- const fetchPlanningData = async () => {
- if (!selectedProject) return;
-
- // const { isSuccess, errors, data } = await fetchRequest(`/planning/?project=${selectedProject}`);
- const { isSuccess, errors, data } = await fetchRequest(`/plannings/project/${selectedProject}/`);
- if (isSuccess) {
- // if the project have no data the response is [] in this case we should set the blankData
- if (data.length === 0) {
- setPlanningData(blankData);
- setErrors(null);
- return;
- }
- setPlanningData(data[0]);
- setErrors(null);
- } else {
- console.error("Failed to fetch planning data");
- setPlanningData(blankData)
- setErrors(errors);
+ const handleProjectChange = (e) => {
+ if (e.target.value === '') {
+ setSelectedProject({});
+ return;
}
- };
- useEffect(() => {
- fetchPlanningData();
- }, [selectedProject]);
+ const project = projects.find(project => project.id == e.target.value);
+ setSelectedProject(project);
+ }
const fetchTypePresences = async () => {
- const { isSuccess, errors, data } = await fetchRequest('/type-presences/');
+ const {isSuccess, errors, data} = await fetchRequest('/type-presences/');
if (isSuccess) {
setTypePresences(data);
setErrors(null);
@@ -82,169 +58,79 @@ const PlanningPage = () => {
fetchTypePresences()
}, []);
- const handleTypePresenceChange = (weekIndex, dayIndex, value) => {
- const updatedData = { ...planningData };
- // get the presence type by id (value is a string convert it to int
- const typePresence = typePresences.find(typePresence => typePresence.id === parseInt(value));
- console.log(typePresence)
-
- // the value I want to add should be {"id": 1, "nom": "Travail à Temps Partiel"} and not just the id
- updatedData.planning_data[weekIndex].days[dayIndex] = typePresence;
- setPlanningData(updatedData);
- console.log(value)
- console.log(updatedData);
- };
-
- const handleSave = async () => {
- if (!selectedProject) {
- toggleNotification({
- visible: true,
- message: 'Veuillez sélectionner un projet',
- type: 'error'
- });
- return;
- }
- // verify if planing data has an empty value
- const emptyValue = planningData.planning_data.some(week => week.days.some(day => day.nom === ''));
- if (emptyValue) {
- toggleNotification({
- visible: true,
- message: 'Veuillez remplir toutes les valeurs de planification',
- type: 'error'
- });
- return;
- }
- setLoading(true);
- const requestBody = { id_project: selectedProject, planning_data: planningData.planning_data };
- console.log({ id_project: selectedProject, planning_data: planningData.planning_data })
- const { isSuccess, errors } = await fetchRequest(`/plannings/`, {
- method: 'POST',
- body: JSON.stringify(requestBody)
- });
- setLoading(false);
- if (isSuccess) {
- toggleNotification({
- visible: true,
- message: 'Données de planification enregistrées avec succès',
- type: 'success'
- });
- fetchPlanningData()
- } else {
- setErrors(errors);
- toggleNotification({
- visible: true,
- message: 'Échec de lenregistrement des données de planification',
- type: 'error'
- });
- }
- };
-
- const handleUpdate = async () => {
- setLoading(true);
- const requestBody = {id_project: selectedProject, planning_data: planningData.planning_data};
- const {isSuccess, errors} = await fetchRequest(`/plannings/${planningData.id}/`, {
- method: 'PUT',
- body: JSON.stringify(requestBody)
- });
- setLoading(false);
- if (isSuccess) {
- toggleNotification({
- visible: true,
- message: 'Données de planification mises à jour avec succès',
- type: 'success'
- });
- } else {
- setErrors(errors);
- toggleNotification({
- visible: true,
- message: 'Échec de la mise à jour des données de planification',
- type: 'error'
- });
- }
- }
-
- const handleDelete = async () => {
- setLoading(true);
- // dlete by planning id not project id
- const { isSuccess, errors } = await fetchRequest(`/plannings/${planningData.id}/`, {
- method: 'DELETE'
- });
- setLoading(false);
- if (isSuccess) {
- setPlanningData(blankData);
- toggleNotification({
- visible: true,
- message: 'Données de planification supprimées avec succès',
- type: 'success'
- });
- } else {
- setErrors(errors);
- toggleNotification({
- visible: true,
- message: 'Échec de la suppression des données de planification',
- type: 'error'
- });
- }
- };
- const handleDeleteClick = () => {
- setModalOpen(true);
- };
-
- const handleConfirmDelete = () => {
- handleDelete();
- setModalOpen(false);
- };
-
return (
-
-
Planning
-
-
-
+ <>
+
+
Recherche
+
+
+
+
+
+
+
+
+
+
- {/* crud buttons*/}
-
-
- {planningData.id ?
- <>
-
-
- > :
-
- }
-
+
+
+
Planning
+
+
+ {/*iterate for projects */}
+
+ {selectedProject.id ? (
+
+ ) : projects.length === 0 ? (
+
+
Pas encore des projets
+
+ ) : (
+ projects.map(project => (
+
+ ))
+ )}
+
-
setModalOpen(false)}
- onConfirm={handleConfirmDelete}
- message={`Etes-vous sûr de vouloir supprimer ces données de planification ?`}
- />
-
+ {openPopup &&
}
+ >
);
};
diff --git a/src/app/(dashboard)/planning/type-presence/EntityForm.jsx b/src/app/(dashboard)/planning/type-presence/EntityForm.jsx
index 408e3a41c2afc4009945d83e6f1d7db4930c3f42..3397d1e53fd1c9984f3e2bba89b07027c2a1f333 100644
--- a/src/app/(dashboard)/planning/type-presence/EntityForm.jsx
+++ b/src/app/(dashboard)/planning/type-presence/EntityForm.jsx
@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import fetchRequest from "@/app/lib/fetchRequest";
import {useNotification} from "@/context/NotificationContext";
@@ -44,31 +44,32 @@ const EntityForm = ({ entity, id, onSaved, onCancel }) => {
};
return (
-
diff --git a/src/app/(dashboard)/projects/page.jsx b/src/app/(dashboard)/projects/page.jsx
index 463f4a2e1e8d3cb4e483c1af0b46907f3654144e..abdaafc760abb68f5abb39a8901e4e23e39a27f8 100644
--- a/src/app/(dashboard)/projects/page.jsx
+++ b/src/app/(dashboard)/projects/page.jsx
@@ -35,7 +35,7 @@ const Projects = () => {
const fetchProjects = async (pageNumber = 1, signal) => {
setLoading(true);
- const URLQuery = `?page=${pageNumber}&?nom=${(filter.name)}&user_count=${(filter.user_count)}&nomClient=${(filter.name_client)}&dateDebut=${(filter.date_debut)}&dateFin=${(filter.date_fin)}`
+ const URLQuery = `?page=${pageNumber}&nom=${(filter.name)}&user_count=${(filter.user_count)}&nomClient=${(filter.name_client)}&dateDebut=${(filter.date_debut)}&dateFin=${(filter.date_fin)}`
const {isSuccess, errors, data} = await fetchRequest(`/projects/pagination/${URLQuery}`,
{signal: signal})
setLoading(false);
diff --git a/src/app/auth/change-password/page.jsx b/src/app/auth/change-password/page.jsx
index 6bc46caa9f1a0aa71d39d43d249f2fb50b0bbafd..235d187eb54de5f548100a684bbd91bbf4e76883 100644
--- a/src/app/auth/change-password/page.jsx
+++ b/src/app/auth/change-password/page.jsx
@@ -2,11 +2,12 @@
import fetchRequest from '@/app/lib/fetchRequest'
import Image from 'next/image'
import Link from 'next/link'
-import React, { useEffect, useState } from 'react'
-import { useSearchParams } from 'next/navigation'
+import React, {useEffect, useState} from 'react'
+import {useSearchParams} from 'next/navigation'
import Loader from '@/components/Loader/Loader'
-import { PASSWORD_REGEX } from '@/app/lib/constants'
-import { useNotification } from '@/context/NotificationContext'
+import {PASSWORD_REGEX} from '@/app/lib/constants'
+import {useNotification} from '@/context/NotificationContext'
+import TeambookVertical from "@/static/image/teambook-vertical.png";
const ChangePassword = () => {
const [isSuccess, setIsSuccess] = useState(false)
@@ -15,11 +16,11 @@ const ChangePassword = () => {
const [confirmPassword, setConfirmPassword] = useState("")
const [isLoading, setIsLoading] = useState(false)
const params = useSearchParams();
- const { toggleNotification } = useNotification()
+ const {toggleNotification} = useNotification()
const handleChangePassword = async (event) => {
event.preventDefault()
setIsLoading(true)
- const { isSuccess, data, errors } = await fetchRequest(`/password_reset/confirm/?token=${params.get("token")}`, {
+ const {isSuccess, data, errors} = await fetchRequest(`/password_reset/confirm/?token=${params.get("token")}`, {
method: "POST",
body: JSON.stringify({
password,
@@ -28,21 +29,18 @@ const ChangePassword = () => {
})
if (isSuccess) {
setIsSuccess(true)
- }
- else {
+ } else {
console.log(errors)
setIsLoading(false)
if (errors.type === "ValidationError") {
if (errors.detail.token) {
setFormErrors(["Le lien que vous avez utilisé pour réinitialiser votre mot de passe est invalide"])
- }
- else {
+ } else {
setFormErrors(["Le Mot de passe est invalide"])
}
} else if (errors?.detail?.detail?.startsWith("The OTP password entered is not valid")) {
setFormErrors(["Le lien que vous avez utilisé pour réinitialiser votre mot de passe est déja utilisé"])
- }
- else {
+ } else {
toggleNotification({
type: "error",
message: "Internal Server Error",
@@ -66,60 +64,61 @@ const ChangePassword = () => {
setFormErrors(currentErrors)
}, [password, confirmPassword])
return (
-
-
-
-
-
-
- {(!isSuccess) &&
-
Change your password.
-
-
-
- - Le mot de passe doit contenir au moins 8 caractères
- - Le mot de passe doit contenir au moins un chiffre
- - Le mot de passe doit contenir au moins un caractère spécial
-
+
+
+
+
+ {(!isSuccess) &&
+
+
Changer votre Mot de passe
+
+
+
}
+ {(isSuccess) && (
+
+
The password has been changed!
+ log in
+ again?
-
-
+ )}
+
)
}
diff --git a/src/app/auth/forgot-password/page.jsx b/src/app/auth/forgot-password/page.jsx
index d74d5db9ab4b3f3bd45be27257ce6fead4b790b3..434c4237f9113dcd94ce2b11265a98e151ca0e4a 100644
--- a/src/app/auth/forgot-password/page.jsx
+++ b/src/app/auth/forgot-password/page.jsx
@@ -5,6 +5,8 @@ import { useNotification } from '@/context/NotificationContext'
import Image from 'next/image'
import Link from 'next/link'
import React, { useState } from 'react'
+import TeambookVertical from "@/static/image/teambook-vertical.png";
+import UserIcon from "@/static/image/svg/perm_identity.svg";
const ForgotPassword = () => {
const [email, setEmail] = useState("")
@@ -40,39 +42,31 @@ const ForgotPassword = () => {
}
}
return (
-
-
-
-
- {(!isSuccess) &&
-
-
Forgot your password!! No Problem
- Reset it here
+
+
+ {(!isSuccess) &&
+
+
Mot de passe oublié!! Aucun problème
+ Réinitialisez-le ici
-
}
{(isSuccess) &&
-
}
-
-
)
}
diff --git a/src/app/auth/layout.jsx b/src/app/auth/layout.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..27b0f05df286f35aa68a77ba58383b0f6aef9cbe
--- /dev/null
+++ b/src/app/auth/layout.jsx
@@ -0,0 +1,48 @@
+import React from "react";
+import Link from "next/link";
+import Image from "next/image";
+import Hero from "@/static/image/pc_phone.png";
+import LineWhite from "@/static/image/svg/line-white4.svg";
+import LineSushi from "@/static/image/svg/line-sushi.svg";
+
+const layout = ({children}) => {
+ return (
+ <>
+
+
+ {children}
+
+
+
+ Aide
+
+
+ Vos questions
+
+
+
+
+
+
+
+
+
+
+
+
+ Teambook 2024 ©
+
+
+ Politique de confidentialité
+
+
+ Termes et conditions
+
+
+
+
+ >
+ )
+}
+
+export default layout
\ No newline at end of file
diff --git a/src/app/auth/login/page.jsx b/src/app/auth/login/page.jsx
index 2bdb9a070baaa5983da96f4d5185e8c7919b7d6e..6ed5663b2f57400336156142df10496db5f2ef34 100644
--- a/src/app/auth/login/page.jsx
+++ b/src/app/auth/login/page.jsx
@@ -6,6 +6,10 @@ import Cookies from 'js-cookie';
import { createSession } from "@/app/lib/session";
import { useRouter } from 'next/navigation'
import Loader from '@/components/Loader/Loader';
+import UserIcon from "@/static/image/svg/perm_identity.svg";
+import VisibilityIcon from "@/static/image/svg/visibility_off.svg";
+import Image from "next/image";
+import TeambookVertical from "@/static/image/teambook-vertical.png";
const LoginPage = () => {
const [username, setUsername] = useState('');
@@ -48,17 +52,16 @@ const LoginPage = () => {
};
return (
<>
-