From f24a66943101928a6b7a2ca4b74a3b5ea80f72f2 Mon Sep 17 00:00:00 2001 From: Baligh ZOGHLAMI Date: Tue, 28 May 2024 17:59:17 +0100 Subject: [PATCH 1/3] feature: update user --- src/app/lib/constants.js | 3 +- src/app/projects/ProjectForm.jsx | 2 +- src/app/projects/ProjectList.jsx | 154 +++++++++++------------ src/app/projects/page.jsx | 17 +-- src/app/role/RoleTableRows.jsx | 4 +- src/app/user/CreateUserForm.jsx | 192 ++++++++++++++++------------- src/app/user/UpdateUserForm.jsx | 203 ++++++++++++++++++++++++++++++- src/app/user/UserTableRow.jsx | 10 +- src/app/user/page.jsx | 2 +- 9 files changed, 403 insertions(+), 184 deletions(-) diff --git a/src/app/lib/constants.js b/src/app/lib/constants.js index f4da663..889cdc8 100644 --- a/src/app/lib/constants.js +++ b/src/app/lib/constants.js @@ -1 +1,2 @@ -export const PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[^a-zA-Z\d\s]).*$/; \ No newline at end of file +export const PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[^a-zA-Z\d\s]).*$/; +export const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@teamwillgroup\.com$/ \ No newline at end of file diff --git a/src/app/projects/ProjectForm.jsx b/src/app/projects/ProjectForm.jsx index 350d3d0..e8a184e 100644 --- a/src/app/projects/ProjectForm.jsx +++ b/src/app/projects/ProjectForm.jsx @@ -72,7 +72,7 @@ const ProjectForm = ({ onAddProject, onEditProject, editingProject }) => { nomClient: clientName, dateDebut, dateFin, - users: userIds.map(user => user.id), + user_ids: userIds.map(user => user.id), }; if (editingProject) { diff --git a/src/app/projects/ProjectList.jsx b/src/app/projects/ProjectList.jsx index df3458c..16d3fe3 100644 --- a/src/app/projects/ProjectList.jsx +++ b/src/app/projects/ProjectList.jsx @@ -1,5 +1,5 @@ import ConfirmationModal from "@/app/ui/ConfirmationModal"; -import {useState} from "react"; +import { useState } from "react"; const ProjectList = ({ projects, onEdit, onDelete, onHandlePageUrl }) => { const [isModalOpen, setModalOpen] = useState(false); @@ -18,90 +18,90 @@ const ProjectList = ({ projects, onEdit, onDelete, onHandlePageUrl }) => { <> - - - - - - + + + + + + - {projects - .sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)) - .map((project, index) => ( - - - - - - - ))} + {projects + .sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)) + .map((project, index) => ( + + + + + + + ))}
ProjetMembres de léquipeNom du clientActions
ProjetMembres de léquipeNom du clientActions
{project.nom}{project.users.length}{project.nomClient} - - -
{project.nom}{project.users.length}{project.nomClient} + + +
{/* Pagination */} {projects.count && -
-
    -
  1. - -
  2. -
  3. - 1 -
  4. -
  5. - +
  6. +
  7. + 1 +
  8. +
  9. + -
  10. -
-
+ Next Page + + + + + + + } {/* Confirmation Modal */} { const [pageUrl, setPageUrl] = useState('/projects/'); const [projects, setProjects] = useState([]); const [editingProject, setEditingProject] = useState(null); - {/* errors from request*/} + {/* errors from request*/ } const [errors, setErrors] = useState(); const [loading, setLoading] = useState(false); const fetchProjects = async () => { - const { isSuccess, errors , data } = await fetchRequest(pageUrl); + const { isSuccess, errors, data } = await fetchRequest(pageUrl); if (isSuccess) { setProjects(data); setErrors(null); @@ -23,16 +23,16 @@ const Projects = () => { setErrors(errors) } }; - useEffect( () => { + useEffect(() => { - fetchProjects(); + fetchProjects(); }, [pageUrl]); // pageURL const handleAddProject = async (project) => { setLoading(true); - const { isSuccess, errors , data } = await fetchRequest('/projects/', { + const { isSuccess, errors, data } = await fetchRequest('/projects/', { method: 'POST', body: JSON.stringify(project), }); @@ -42,6 +42,7 @@ const Projects = () => { setEditingProject(null); setErrors(null); } else { + console.log(errors); console.error("Failed to add project"); setErrors(errors) } @@ -50,7 +51,7 @@ const Projects = () => { const handleEditProject = async (id, updatedProject) => { setLoading(true); - const { isSuccess, errors , data } = await fetchRequest(`/projects/${id}/`, { + const { isSuccess, errors, data } = await fetchRequest(`/projects/${id}/`, { method: 'PUT', body: JSON.stringify(updatedProject), }); @@ -94,7 +95,7 @@ const Projects = () => { return (
- +
diff --git a/src/app/role/RoleTableRows.jsx b/src/app/role/RoleTableRows.jsx index 5c44906..c937dc0 100644 --- a/src/app/role/RoleTableRows.jsx +++ b/src/app/role/RoleTableRows.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react' +import React, { useState } from 'react' import fetchRequest from '../lib/fetchRequest' import DeleteIcon from "@/static/image/svg/delete.svg" import EditIcon from "@/static/image/svg/edit.svg" @@ -50,7 +50,7 @@ const RoleTableRows = ({ name, setRoles, id, privileges, setRoleToUpdate }) => { <> -

{name}

+

{name}

diff --git a/src/app/user/CreateUserForm.jsx b/src/app/user/CreateUserForm.jsx index f06c5ca..a3346f5 100644 --- a/src/app/user/CreateUserForm.jsx +++ b/src/app/user/CreateUserForm.jsx @@ -3,6 +3,7 @@ import Loader from '@/components/Loader/Loader' import fetchRequest from '../lib/fetchRequest' import { useNotification } from '@/context/NotificationContext' import CancelIcon from "@/static/image/svg/cancel.svg" +import { EMAIL_REGEX } from '../lib/constants' @@ -35,7 +36,7 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => { const [isLoading, setIsLoading] = useState(false) const [selectedRole, setSelectedRole] = useState(null) const { toggleNotification } = useNotification() - const [selectProjects, setSelectedProjects] = useState([]) + const [selectedProject, setSelectedProject] = useState([]) const [roles, setRoles] = useState(null) const [projects, setProjects] = useState(null) @@ -70,103 +71,109 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => { getRoles() getProjects() }, []) - const handleFieldChange = (event) => setUserData({ ...userData, [event.target.name]: event.target.value }) - + const handleFieldChange = (event) => { + setUserData({ ...userData, [event.target.name]: event.target.value }) + setErrors({ ...errors, [event.target.name]: "" }) + } + const [errors, setErrors] = useState({ first_name: "", last_name: "", email: "", role: "" }) const [userData, setUserData] = useState({ email: "", password: generateRandomPassword(), first_name: "", last_name: "" }) + + const isValidFields = () => { + const localErrors = { first_name: "", last_name: "", email: "", role: "" } + if (userData.first_name === "") localErrors.first_name = "Le prénom doit être spécifier." + if (userData.last_name === "") localErrors.last_name = "Le nom doit être spécifier." + if (!selectedRole) localErrors.role = "Le rôle doit être spécifier." + if (!userData.email) localErrors.email = "L'email doit être spécifier." + else if (!EMAIL_REGEX.test(userData.email)) localErrors.email = "Votre adresse email n'est pas valide." + setErrors({ ...localErrors }) + return Object.values(localErrors).find((element) => element !== "") === undefined + } const handleSubmit = async (event) => { event.preventDefault() - setIsLoading(true) - const { data, errors, isSuccess, status } = await fetchRequest("/users/", { - method: "POST", - body: JSON.stringify({ ...userData, username: userData.email, role: selectedRole.id, project_ids: selectProjects.map((element) => element.id) }) - }) - if (isSuccess) { - setIsLoading(false) - setSelectedRole(null) - appendUser(data.data) - toggleNotification({ - visible: true, - message: "Le rôle a été créé avec succès", - type: "success" + if (isValidFields()) { + setIsLoading(true) + const { data, errors: requestErrors, isSuccess, status } = await fetchRequest("/users/", { + method: "POST", + body: JSON.stringify({ ...userData, username: userData.email, role: selectedRole, projects: selectedProject }) }) - setIsOpen(false) - } else { - setIsLoading(false) - if (errors.type === "ValidationError") { - if (errors.detail.name) { - toggleNotification({ - visible: true, - message: "Le rôle existe déjà", - type: "warning" - }) + if (isSuccess) { + setIsLoading(false) + setSelectedRole(null) + appendUser(data) + toggleNotification({ + visible: true, + message: "L'utilisateur a été créé avec succès", + type: "success" + }) + setIsOpen(false) + } else { + setIsLoading(false) + if (requestErrors.type === "ValidationError") { + if (requestErrors.detail.email) { + setErrors({ ...errors, email: "Cette adresse email est déjà utilisée." }) + } + else if (requestErrors.detail.role) { + toggleNotification({ + visible: true, + message: "Erreur de validation de rôle (le rôle peut être supprimé)", + type: "warning" + }) + } + else { + toggleNotification({ + visible: true, + message: "Erreur de validation de utilisateur", + type: "warning" + }) + setIsOpen(false) + } } else { toggleNotification({ visible: true, - message: "Erreur de validation de rôle", - type: "warning" + message: "Internal Server Error", + type: "error" }) setIsOpen(false) } + console.log(requestErrors) } - else if (status === 409) { - toggleNotification({ - visible: true, - message: "role created with 2 or more same privileges", - type: "error" - }) - setIsOpen(false) - } else if (errors.detail === "Privilege matching query does not exist.") { - toggleNotification({ - visible: true, - message: "Des privilèges que vous avez utilisés ont été supprimés.", - type: "warning" - }) - setIsOpen(false) - } else { - toggleNotification({ - visible: true, - message: "Internal Server Error", - type: "error" - }) - setIsOpen(false) - } - console.log(errors) } + } - const handleRoleClick = (newRole) => { - if (selectedRole?.id === newRole.id) { - setSelectedRole(null) - } else { - setSelectedRole(newRole) - } + const handleRoleChange = (event) => { + setErrors({ ...errors, role: "" }) + if (event.target.value) + setSelectedRole(event.target.value) + else setSelectedRole(null) } - const handleProjectClick = (project) => { - if (selectProjects.find((element) => element.id === project.id)) { - setSelectedProjects(selectProjects.filter((element) => element.id !== project.id)) - } else { - setSelectedProjects([...selectProjects, project]) - } + const handleProjectChange = (event) => { + if (event.target.value) + setSelectedProject([event.target.value]) + else setSelectedProject([]) } return (
setIsOpen(false)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" />
-

Ajout d utilisateur

+

Ajout d'utilisateur

- - + + +

{errors.last_name}

- - + + +

{errors.first_name}

- + +

{errors.email}

@@ -176,30 +183,43 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {
-
- {roles.length !== 0 ? roles?.map((role) => { - const isSelected = selectedRole?.id === role.id - return
handleRoleClick(role)} key={role.id} className={`${!isSelected ? 'text-neutral-400 hover:border-neutral-400 hover:text-neutral-500 border-neutral-300 bg-neutral-100' : 'text-indigo-500 hover:border-indigo-500 hover:text-indigo-500 border-indigo-400 bg-indigo-100'} will-change-contents h-6 text-sm flex items-center justify-center duration-150 delay-75 cursor-pointer text-semibold leading-[0] border-2 py-0.5 rounded-full w-fit px-2`}> - {role.name} +
+ {roles.length !== 0 ? +
+ +

{errors.role}

- }) :
-

Pas encore des habilitations

-
} + :
+

Pas encore des rôles

+
}
:
} {(projects) ?
- +
-
- {projects.length !== 0 ? projects?.map((project) => { - const isSelected = selectProjects.find((element) => element.id === project.id) !== undefined - return
handleProjectClick(project)} key={project.id} className={`${!isSelected ? 'text-neutral-400 hover:border-neutral-400 hover:text-neutral-500 border-neutral-300 bg-neutral-100' : 'text-indigo-500 hover:border-indigo-500 hover:text-indigo-500 border-indigo-400 bg-indigo-100'} will-change-contents h-6 text-sm flex items-center justify-center duration-150 delay-75 cursor-pointer text-semibold leading-[0] border-2 py-0.5 rounded-full w-fit px-2`}> - {project.nom} +
+ {projects.length !== 0 ? +
+
- }) :
-

Pas encore des projets

-
} + :
+

Pas encore des projets

+
}
:
}
diff --git a/src/app/user/UpdateUserForm.jsx b/src/app/user/UpdateUserForm.jsx index d214f18..8d06a96 100644 --- a/src/app/user/UpdateUserForm.jsx +++ b/src/app/user/UpdateUserForm.jsx @@ -1,8 +1,205 @@ -import React from 'react' +import React, { useState, useEffect } from 'react' +import Loader from '@/components/Loader/Loader' +import fetchRequest from '../lib/fetchRequest' +import { useNotification } from '@/context/NotificationContext' +import CancelIcon from "@/static/image/svg/cancel.svg" +import { EMAIL_REGEX } from '../lib/constants' -const UpdateUserForm = () => { + +const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => { + const [isLoading, setIsLoading] = useState(false) + const [selectedRole, setSelectedRole] = useState(userToUpdate.role?.id || null) + const { toggleNotification } = useNotification() + const [selectedProject, setSelectedProject] = useState(userToUpdate.projects?.length ? [userToUpdate.projects[0].id] : []) + + const [roles, setRoles] = useState(null) + const [projects, setProjects] = useState(null) + useEffect(() => { + const getRoles = async () => { + const { data, errors, isSuccess } = await fetchRequest("/roles/") + if (isSuccess) { + setRoles(data) + } else { + setRoles([]) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + console.log(errors) + } + } + const getProjects = async () => { + const { isSuccess, errors, data } = await fetchRequest("/projects/"); + if (isSuccess) { + setProjects(data); + } else { + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + console.log(errors) + } + } + getRoles() + getProjects() + }, []) + const handleFieldChange = (event) => { + setUserData({ ...userData, [event.target.name]: event.target.value }) + setErrors({ ...errors, [event.target.name]: "" }) + } + const [errors, setErrors] = useState({ first_name: "", last_name: "", email: "", role: "" }) + const [userData, setUserData] = useState({ email: userToUpdate.email, first_name: userToUpdate.first_name, last_name: userToUpdate.last_name }) + + const isValidFields = () => { + const localErrors = { first_name: "", last_name: "", email: "", role: "" } + if (userData.first_name === "") localErrors.first_name = "Le prénom doit être spécifier." + if (userData.last_name === "") localErrors.last_name = "Le nom doit être spécifier." + if (!selectedRole) localErrors.role = "Le rôle doit être spécifier." + if (!userData.email) localErrors.email = "L'email doit être spécifier." + else if (!EMAIL_REGEX.test(userData.email)) localErrors.email = "Votre adresse email n'est pas valide." + setErrors({ ...localErrors }) + return Object.values(localErrors).find((element) => element !== "") === undefined + } + const handleSubmit = async (event) => { + event.preventDefault() + if (isValidFields()) { + setIsLoading(true) + const { data, errors: requestErrors, isSuccess, status } = await fetchRequest(`/users/${userToUpdate.id}/`, { + method: "PATCH", + body: JSON.stringify({ ...userData, username: userData.email, role: selectedRole, projects: selectedProject }) + }) + if (isSuccess) { + setUsers((users) => users.map((element) => element.id === userToUpdate.id ? data : element)) + setIsLoading(false) + setSelectedRole(null) + toggleNotification({ + visible: true, + message: "L'utilisateur a été modifié avec succès", + type: "success" + }) + setUserToUpdate(null) + } else { + setIsLoading(false) + if (requestErrors.type === "ValidationError") { + if (requestErrors.detail.email) { + setErrors({ ...errors, email: "Cette adresse email est déjà utilisée." }) + } + else if (requestErrors.detail.role) { + toggleNotification({ + visible: true, + message: "Erreur de validation de rôle (le rôle peut être supprimé)", + type: "warning" + }) + } + else { + toggleNotification({ + visible: true, + message: "Erreur de validation de utilisateur", + type: "warning" + }) + setUserToUpdate(null) + } + } + else { + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + setUserToUpdate(null) + } + console.log(requestErrors) + } + } + + } + const handleRoleChange = (event) => { + setErrors({ ...errors, role: "" }) + if (event.target.value) + setSelectedRole(event.target.value) + else setSelectedRole(null) + } + const handleProjectChange = (event) => { + if (event.target.value) + setSelectedProject([event.target.value]) + else setSelectedProject([]) + } return ( -
UpdateUserForm
+
+
+ setUserToUpdate(null)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> + +

Modification d'utilisateur

+
+
+ + +

{errors.last_name}

+
+
+ + +

{errors.first_name}

+
+
+
+ + +

{errors.email}

+
+ {(roles) ?
+
+ +
+
+ {roles.length !== 0 ? +
+ +

{errors.role}

+
+ :
+

Pas encore des rôles

+
} +
+
:
} + {(projects) ?
+
+ +
+
+ {projects.length !== 0 ? +
+ +
+ :
+

Pas encore des projets

+
} +
+
:
} +
+ +
+ +
+
) } diff --git a/src/app/user/UserTableRow.jsx b/src/app/user/UserTableRow.jsx index 1860ee8..e057532 100644 --- a/src/app/user/UserTableRow.jsx +++ b/src/app/user/UserTableRow.jsx @@ -5,7 +5,7 @@ import ConfirmationModal from '../ui/ConfirmationModal' import { useNotification } from '@/context/NotificationContext' import fetchRequest from '../lib/fetchRequest' -const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projects }) => { +const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projects, setUserToUpdate }) => { const { toggleNotification } = useNotification() const [isModalOpen, setModalOpen] = useState(false); const showDeletePopup = () => { @@ -23,13 +23,13 @@ const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projec } else if (status == 404) { toggleNotification({ visible: true, - message: "L'utilisateur n'a pas été trouvé", + message: "L'utilisateur n'a pas été trouvé", type: "warning" }) - } else if (errors.detail?.indexOf("Cannot delete some instances of model 'Role'") !== -1) { + } else if (errors.detail?.indexOf("Cannot delete some instances of model") !== -1) { toggleNotification({ visible: true, - message: "Impossible de supprimer cet utilisateur car il est attribué à des utilisateurs", + message: "Impossible de supprimer cet utilisateur car il est attribué à d'autre objets", type: "warning" }) } @@ -66,7 +66,7 @@ const UserTableRow = ({ email, last_name, first_name, id, setUsers, role, projec
-
- + :
}
) diff --git a/src/app/role/UpdateRoleForm.jsx b/src/app/role/UpdateRoleForm.jsx index e980dbf..348ebfc 100644 --- a/src/app/role/UpdateRoleForm.jsx +++ b/src/app/role/UpdateRoleForm.jsx @@ -109,13 +109,13 @@ const UpdateRoleForm = ({ setRoleToUpdate, setRoles, roles, privileges: rolePriv
setRoleToUpdate(null)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> -
+ {(privileges) ?

Modification de Rôle

- {(privileges) ?
+
{!isAllSelected ? "Sélectionner tout" : "désélectionner"}
@@ -128,13 +128,13 @@ const UpdateRoleForm = ({ setRoleToUpdate, setRoles, roles, privileges: rolePriv

Pas encore des habilitations

}
-
:
} +
- + :
}
) diff --git a/src/app/user/CreateUserForm.jsx b/src/app/user/CreateUserForm.jsx index a3346f5..1b4540d 100644 --- a/src/app/user/CreateUserForm.jsx +++ b/src/app/user/CreateUserForm.jsx @@ -156,7 +156,7 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {
setIsOpen(false)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> -
+ {(roles && projects) ?

Ajout d'utilisateur

@@ -179,7 +179,7 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {
- {(roles) ?
+
@@ -200,8 +200,8 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {

Pas encore des rôles

}
-
:
} - {(projects) ?
+
+
@@ -221,13 +221,13 @@ const CreateUserForm = ({ setIsOpen, appendUser }) => {

Pas encore des projets

}
-
:
} +
- + :
}
) diff --git a/src/app/user/UpdateUserForm.jsx b/src/app/user/UpdateUserForm.jsx index 8d06a96..1e62cce 100644 --- a/src/app/user/UpdateUserForm.jsx +++ b/src/app/user/UpdateUserForm.jsx @@ -130,7 +130,7 @@ const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => {
setUserToUpdate(null)} className="h-8 w-8 cursor-pointer absolute top-2 right-2 fill-neutral-600" /> -
+ {(roles && projects) ?

Modification d'utilisateur

@@ -149,7 +149,7 @@ const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => {

{errors.email}

- {(roles) ?
+
@@ -170,8 +170,8 @@ const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => {

Pas encore des rôles

}
-
:
} - {(projects) ?
+
+
@@ -191,13 +191,13 @@ const UpdateUserForm = ({ setUserToUpdate, userToUpdate, setUsers }) => {

Pas encore des projets

}
-
:
} +
- + :
}
) diff --git a/src/app/user/page.jsx b/src/app/user/page.jsx index edba6ff..de82ec7 100644 --- a/src/app/user/page.jsx +++ b/src/app/user/page.jsx @@ -1,5 +1,5 @@ 'use client'; -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useDeferredValue } from 'react' import CreateUserForm from './CreateUserForm' import UpdateUserForm from './UpdateUserForm' import AddIcon from "@/static/image/svg/add.svg" @@ -8,34 +8,49 @@ 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 getUsers = async () => { - const { data, errors, isSuccess } = await fetchRequest("/users") - setIsLoading(false) - if (isSuccess) { - console.log(data) - setUsers(data) - } else { - toggleNotification({ - visible: true, - message: "Internal Server Error", - type: "error" - }) - } + const controller = new AbortController() + const signal = controller.signal + getUsers(1, signal) + return () => { + controller.abort("fetching another users") } - getUsers() - }, []) + }, [query]) const appendUser = (newUser) => { setUsers([newUser, ...users]) } + + const handleSearchChange = (event) => { + setQuery(event.target.value) + } return (
@@ -48,12 +63,16 @@ const UserPage = () => {

Utilisateur

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

Pas encore des utilisateurs

- :
+ : +
@@ -66,8 +85,31 @@ const UserPage = () => { return })}
Nom
-
- }} +
} + + } +
+ {(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'> + +
} +
} +
diff --git a/src/static/image/svg/chevron-left.svg b/src/static/image/svg/chevron-left.svg new file mode 100644 index 0000000..bfbedda --- /dev/null +++ b/src/static/image/svg/chevron-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/image/svg/chevron-right.svg b/src/static/image/svg/chevron-right.svg new file mode 100644 index 0000000..49c8a53 --- /dev/null +++ b/src/static/image/svg/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file -- GitLab From 9d7d2ec8a5425284d29b16767a402da9a5ab3e3c Mon Sep 17 00:00:00 2001 From: Oussama El Benney Date: Fri, 31 May 2024 11:25:07 +0100 Subject: [PATCH 3/3] added scroll for users in projects --- src/app/projects/ProjectForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/projects/ProjectForm.jsx b/src/app/projects/ProjectForm.jsx index 425cb09..18005e6 100644 --- a/src/app/projects/ProjectForm.jsx +++ b/src/app/projects/ProjectForm.jsx @@ -87,7 +87,7 @@ const ProjectForm = ({ onAddProject, onEditProject, editingProject, setEditingPr }; return ( -
+