From 69b9fcb5649b49f0e02c302bcfdcf3aa43bc2d1b Mon Sep 17 00:00:00 2001 From: Raed BOUAFIF Date: Mon, 24 Jun 2024 16:33:29 +0100 Subject: [PATCH 1/4] reporting new design v_1 --- package-lock.json | 34 ++++++++ package.json | 2 + .../assign-zone-project/AssignProject.jsx | 2 +- .../CompleteAffectation.jsx | 2 +- .../(dashboard)/planning/PlanningTable.jsx | 2 +- src/app/(dashboard)/reporting/page.jsx | 80 +++++++++++++++++-- src/app/ui/SideBar.jsx | 1 + src/middleware.js | 2 +- src/static/image/svg/desk-1.svg | 14 ++++ src/static/image/svg/project.svg | 1 + src/static/image/svg/statistics.svg | 23 ++++++ 11 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 src/static/image/svg/desk-1.svg create mode 100644 src/static/image/svg/project.svg create mode 100644 src/static/image/svg/statistics.svg diff --git a/package-lock.json b/package-lock.json index 4c126e3..459b222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "version": "0.1.0", "dependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", + "chroma-js": "^2.4.2", "jose": "^5.3.0", "js-cookie": "^3.0.5", "next": "14.2.3", "react": "^18", + "react-chartjs-2": "^5.2.0", "react-dom": "^18", "react-select": "^5.8.0" }, @@ -2330,6 +2332,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "peer": true + }, "node_modules/@next/env": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz", @@ -3536,6 +3544,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "peer": true, + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3570,6 +3590,11 @@ "node": ">= 6" } }, + "node_modules/chroma-js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", + "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -6501,6 +6526,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", diff --git a/package.json b/package.json index 7cf3ab1..f9e94e3 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,12 @@ }, "dependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", + "chroma-js": "^2.4.2", "jose": "^5.3.0", "js-cookie": "^3.0.5", "next": "14.2.3", "react": "^18", + "react-chartjs-2": "^5.2.0", "react-dom": "^18", "react-select": "^5.8.0" }, diff --git a/src/app/(dashboard)/assign-zone-project/AssignProject.jsx b/src/app/(dashboard)/assign-zone-project/AssignProject.jsx index 3c923a8..5566068 100644 --- a/src/app/(dashboard)/assign-zone-project/AssignProject.jsx +++ b/src/app/(dashboard)/assign-zone-project/AssignProject.jsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useRef } from 'react' 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 DeskIcon from "@/static/image/svg/desk-1.svg" import fetchRequest from "@/app/lib/fetchRequest"; diff --git a/src/app/(dashboard)/assign-zone-project/CompleteAffectation.jsx b/src/app/(dashboard)/assign-zone-project/CompleteAffectation.jsx index 76045fe..649f94f 100644 --- a/src/app/(dashboard)/assign-zone-project/CompleteAffectation.jsx +++ b/src/app/(dashboard)/assign-zone-project/CompleteAffectation.jsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useRef } from 'react' 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 DeskIcon from "@/static/image/svg/desk-1.svg" import AddIcon from "@/static/image/svg/add.svg" import fetchRequest from "@/app/lib/fetchRequest"; import Loader from '@/components/Loader/Loader' diff --git a/src/app/(dashboard)/planning/PlanningTable.jsx b/src/app/(dashboard)/planning/PlanningTable.jsx index 34228d7..0db1822 100644 --- a/src/app/(dashboard)/planning/PlanningTable.jsx +++ b/src/app/(dashboard)/planning/PlanningTable.jsx @@ -20,7 +20,7 @@ const PlanningTable = ({ data, typePresences, onTypePresenceChange, selectedProj }; return ( -
+
Réglez Tout sur : {typePresences.map((typePresence) => ( diff --git a/src/app/(dashboard)/reporting/page.jsx b/src/app/(dashboard)/reporting/page.jsx index 524f1e8..47058e4 100644 --- a/src/app/(dashboard)/reporting/page.jsx +++ b/src/app/(dashboard)/reporting/page.jsx @@ -7,6 +7,10 @@ import fetchRequest from '@/app/lib/fetchRequest'; import Loader from '@/components/Loader/Loader'; import { useNotification } from '@/context/NotificationContext'; import { extractDate, getDateRange, subtractDays } from '@/app/lib/DateHelper'; +import UserIcon from "@/static/image/svg/user.svg" +import ProjectIcon from "@/static/image/svg/project.svg" +import StatisticsIcon from "@/static/image/svg/statistics.svg" +import DeskIcon from "@/static/image/svg/desk-1.svg" const Reporting = () => { @@ -14,8 +18,36 @@ const Reporting = () => { const [chartDataProject, setChartDataProject] = useState(null) const [isLoadingZone, setIsLoadingZone] = useState(false) const [isLoadingProject, setIsLoadingProject] = useState(false) + const [ countUsers, setCountUsers ] = useState(0) + const [ countProjects, setCountProjects ] = useState(0) + const [ countPlaces, setCountPlaces ] = useState(0) const { toggleNotification } = useNotification() const [dates, setDates] = useState({ fromDate: extractDate(subtractDays(new Date(), 4)), toDate: extractDate(new Date()) }) + + useEffect(() => { + const getStats= async () => { + const { data, errors, isSuccess } = await fetchRequest(`/statistics/`, { + method: "GET", + }) + if (isSuccess) { + setCountUsers(data.user_count) + setCountProjects(data.project_count) + setCountPlaces(data.place_count) + } else { + console.log(errors); + toggleNotification({ + type: "error", + message: "Internal Server Error", + visible: true + }) + } + } + getStats() + }, []) + console.log(countPlaces) + console.log(countProjects) + console.log(countUsers) + useEffect(() => { const getZonesPresenceStatistic = async () => { setIsLoadingZone(true) @@ -115,15 +147,47 @@ const Reporting = () => { }, [chartDataZone, axisX]) return (
-
-
- - +
+
+

Collaborateurs

+
+ {countUsers} +
+ + +
+
+
+
+

Projets

+
+ {countProjects} +
+ + +
+
+
+
+

Places

+
+ {countPlaces} +
+ + +
+
-
- - - {/* */} +
+
+ + +
+
+ + + {/* */} +
{(isLoadingZone || isLoadingProject) ?
diff --git a/src/app/ui/SideBar.jsx b/src/app/ui/SideBar.jsx index 04c5c04..965352b 100644 --- a/src/app/ui/SideBar.jsx +++ b/src/app/ui/SideBar.jsx @@ -45,6 +45,7 @@ const SideBar = () => { { label: "Places", link: "/place", icon: , privilege: "place" }, { label: "Gestion des zones", link: "/assign-zone-project", icon: , privilege: "assign-zone-project" }, { label: "Consulter les réservations", link: "/consultation-reservations", icon: , privilege: "consultation-reservations" }, + { label: "Reporting", link: "/reporting", icon: , privilege: "reporting" }, ]; console.log('sessionDataSideBar', sessionData) diff --git a/src/middleware.js b/src/middleware.js index 817153c..4b0c14d 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -3,7 +3,7 @@ import { decrypt } from '@/app/lib/session' import { cookies } from 'next/headers' // 1. Specify protected and public routes -const protectedRoutes = ['/dashboard', '/auth/verif', '/users', '/privilege', '/projects', '/role', '/etage', '/place', '/zone', '/table', '/reservation', '/planning', '/planning/type-presence', '/assign-zone-project', '/consultation-reservations'] +const protectedRoutes = ['/reporting', '/dashboard', '/auth/verif', '/users', '/privilege', '/projects', '/role', '/etage', '/place', '/zone', '/table', '/reservation', '/planning', '/planning/type-presence', '/assign-zone-project', '/consultation-reservations'] const publicRoutes = ['/auth/login', '/auth/signup', 'auth/forgot-password', '/auth/change-password'] export default async function middleware(req) { diff --git a/src/static/image/svg/desk-1.svg b/src/static/image/svg/desk-1.svg new file mode 100644 index 0000000..3bfcdbd --- /dev/null +++ b/src/static/image/svg/desk-1.svg @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/src/static/image/svg/project.svg b/src/static/image/svg/project.svg new file mode 100644 index 0000000..db8fcbc --- /dev/null +++ b/src/static/image/svg/project.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/image/svg/statistics.svg b/src/static/image/svg/statistics.svg new file mode 100644 index 0000000..a84c165 --- /dev/null +++ b/src/static/image/svg/statistics.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + \ No newline at end of file -- GitLab From a06338a82cf4d9bbca6e98b77b4f37eff92983b9 Mon Sep 17 00:00:00 2001 From: Oussama El Benney Date: Mon, 24 Jun 2024 16:35:15 +0100 Subject: [PATCH 2/4] fixed header + sidebar + design --- package-lock.json | 34 +++++++++++++++++ package.json | 2 + src/app/no-access/page.jsx | 2 + src/app/ui/Header.jsx | 15 +++++--- src/app/ui/LogoutButton.js | 2 +- src/app/ui/SideBar.css | 47 +++++++++++++++++++++++ src/app/ui/SideBar.jsx | 18 +++++---- src/app/ui/SideBarLink.jsx | 59 ++++++++++++++++++----------- src/static/image/teamwill_logo.png | Bin 0 -> 2669 bytes tailwind.config.js | 2 +- 10 files changed, 142 insertions(+), 39 deletions(-) create mode 100644 src/app/ui/SideBar.css create mode 100644 src/static/image/teamwill_logo.png diff --git a/package-lock.json b/package-lock.json index 4c126e3..459b222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "version": "0.1.0", "dependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", + "chroma-js": "^2.4.2", "jose": "^5.3.0", "js-cookie": "^3.0.5", "next": "14.2.3", "react": "^18", + "react-chartjs-2": "^5.2.0", "react-dom": "^18", "react-select": "^5.8.0" }, @@ -2330,6 +2332,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "peer": true + }, "node_modules/@next/env": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz", @@ -3536,6 +3544,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "peer": true, + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3570,6 +3590,11 @@ "node": ">= 6" } }, + "node_modules/chroma-js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", + "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -6501,6 +6526,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", diff --git a/package.json b/package.json index 7cf3ab1..f9e94e3 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,12 @@ }, "dependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", + "chroma-js": "^2.4.2", "jose": "^5.3.0", "js-cookie": "^3.0.5", "next": "14.2.3", "react": "^18", + "react-chartjs-2": "^5.2.0", "react-dom": "^18", "react-select": "^5.8.0" }, diff --git a/src/app/no-access/page.jsx b/src/app/no-access/page.jsx index df86866..62db665 100644 --- a/src/app/no-access/page.jsx +++ b/src/app/no-access/page.jsx @@ -8,6 +8,8 @@ export default function NoAccess() { useEffect(() => { const interval = setInterval(() => { + // never allow countdown to go below 0 + if (countdown === 0) return; setCountdown(prevCountdown => prevCountdown - 1); }, 1000); diff --git a/src/app/ui/Header.jsx b/src/app/ui/Header.jsx index 4112e77..79c3de1 100644 --- a/src/app/ui/Header.jsx +++ b/src/app/ui/Header.jsx @@ -4,6 +4,8 @@ import Link from 'next/link'; import isAuthenticatedSSR from "@/app/lib/isAuthenticatedSSR"; import LogoutButton from "@/app/ui/LogoutButton"; import Burger from './Burger'; +import Image from "next/image"; +import logo from "@/static/image/teamwill_logo.png"; const Header = async () => { @@ -11,20 +13,21 @@ const Header = async () => { console.log('isAuth', isAuth) console.log('sessionData', sessionData) return ( -
+
- -

TeamBook

+ + logo +

TeamBook

return ( ); }; diff --git a/src/app/ui/SideBar.css b/src/app/ui/SideBar.css new file mode 100644 index 0000000..b471219 --- /dev/null +++ b/src/app/ui/SideBar.css @@ -0,0 +1,47 @@ +/*.relative::before {*/ +/* content: '';*/ +/* position: absolute;*/ +/* top: 50%;*/ +/* left: 0;*/ +/* height: 100%;*/ +/* width: 2px;*/ +/* background-color: #a6b764; !* Tailwind class 'sushi-400' color *!*/ +/* transform: translateY(-50%);*/ +/*}*/ + +/*.relative::after {*/ +/* content: '';*/ +/* position: absolute;*/ +/* top: 50%;*/ +/* left: -1px;*/ +/* width: 8px;*/ +/* height: 8px;*/ +/* background-color: #a6b764; !* Tailwind class 'sushi-400' color *!*/ +/* border-radius: 50%;*/ +/* transform: translate(-50%, -50%);*/ +/*}*/ + +input[type="radio"] { + appearance: none; + width: 16px; + height: 16px; + border: 2px solid #888888; /* Tailwind class 'sushi-400' color */ + border-radius: 50%; + position: relative; +} + +input[type="radio"]:checked { + border-color: #a6b764; /* Tailwind class 'sushi-400' color */ +} + +input[type="radio"]:checked::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 9px; + height: 9px; + background-color: #a6b764; /* Tailwind class 'sushi-400' color */ + border-radius: 50%; + transform: translate(-50%, -50%); +} \ No newline at end of file diff --git a/src/app/ui/SideBar.jsx b/src/app/ui/SideBar.jsx index 04c5c04..659c856 100644 --- a/src/app/ui/SideBar.jsx +++ b/src/app/ui/SideBar.jsx @@ -6,6 +6,8 @@ import LogoutButton from "./LogoutButton"; import isAuthenticated from "@/app/lib/isAuthenticated"; import {useEffect, useState} from "react"; import { usePathname } from "next/navigation"; +import './SideBar.css'; + const SideBar = () => { const [isAuth, setIsAuth] = useState(false); const [sessionData, setSessionData] = useState(null); @@ -24,7 +26,7 @@ const SideBar = () => { if (!isAuth || !sessionData) { return (