diff --git a/src/app/(dashboard)/reporting/BubbleStatistic.jsx b/src/app/(dashboard)/reporting/BubbleStatistic.jsx
index a3d82a4170b120a41d02a142c15a0ae90842637a..641e0c65ea3b587ca3975f136a50c40083c907ba 100644
--- a/src/app/(dashboard)/reporting/BubbleStatistic.jsx
+++ b/src/app/(dashboard)/reporting/BubbleStatistic.jsx
@@ -21,7 +21,6 @@ ChartJS.register(
const BubbleStatistic = React.memo(function BubbleStatistic({ axisX, data, title }) {
-
const colors = useMemo(() => data ? generateColors(data.length) : [], [data])
const options = {
responsive: true,
diff --git a/src/app/(dashboard)/reporting/page.jsx b/src/app/(dashboard)/reporting/page.jsx
index 22ca155804efd376b20ae37d7647109bf5bbcd82..a4ac8ab89ca19139c04684f788a3600b0d0506a8 100644
--- a/src/app/(dashboard)/reporting/page.jsx
+++ b/src/app/(dashboard)/reporting/page.jsx
@@ -1,18 +1,220 @@
-"use client"
+// "use client"
+
+
+// import React, { useState, useEffect, useRef, useMemo } from 'react'
+// import BubbleStatistic from './BubbleStatistic';
+// 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 = () => {
+// const [chartDataZone, setChartDataZone] = useState(null)
+// 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()
+// }, [])
+// useEffect(() => {
+// const getZonesPresenceStatistic = async () => {
+// setIsLoadingZone(true)
+// const { data, errors, isSuccess } = await fetchRequest(`/zoaning/zone-presence/`, {
+// method: "POST",
+// body: JSON.stringify({
+// from_date: dates.fromDate,
+// to_date: dates.toDate
+// })
+// })
+// setIsLoadingZone(false)
+// if (isSuccess) {
+// console.log("Zones presences :", data)
+// setChartDataZone(data);
+// } else {
+// console.log(errors);
+// toggleNotification({
+// type: "error",
+// message: "Internal Server Error",
+// visible: true
+// })
+// }
+// }
+// getZonesPresenceStatistic()
+// // eslint-disable-next-line react-hooks/exhaustive-deps
+// }, [dates.fromDate, dates.toDate])
+
+
+// useEffect(() => {
+// const getProjectsPresenceStatistic = async () => {
+// setIsLoadingProject(true)
+// const { data, errors, isSuccess } = await fetchRequest(`/zoaning/project-presence/`, {
+// method: "POST",
+// body: JSON.stringify({
+// from_date: dates.fromDate,
+// to_date: dates.toDate
+// })
+// })
+// setIsLoadingProject(false)
+// if (isSuccess) {
+// console.log(data);
+// setChartDataProject(data);
+// } else {
+// console.log(errors);
+// toggleNotification({
+// type: "error",
+// message: "Internal Server Error",
+// visible: true
+// })
+// }
+// }
+// getProjectsPresenceStatistic()
+// // eslint-disable-next-line react-hooks/exhaustive-deps
+// }, [dates.fromDate, dates.toDate])
+// const handleDateChange = (event) => {
+// console.log("week selection",event.target.value)
+// const name = event.target.name
+// const value = event.target.value
+// if (value) {
+// setDates({ ...dates, [name]: value })
+// return;
+// }
+// else if (!value && name === "fromDate") setDates({ ...dates, "fromDate": extractDate(subtractDays(dates.toDate, 5)) })
+// else if (!value && name === "toDate") setDates({ ...dates, "toDate": extractDate(new Date()) })
+// }
+// console.log(dates)
+// const axisX = useMemo(() => getDateRange(dates.fromDate, dates.toDate), [dates.fromDate, dates.toDate])
+// const processedProjectData = useMemo(() => {
+// return chartDataProject?.map((project, index) => (
+// {
+// label: project.label,
+// data: [...project.data.map((element) => (
+// {
+// x: element.date.split("-").reverse().join("-"),
+// y: element.pourcentage, r: (index * 2) + 6
+// }
+// )), ...axisX.filter((element) => !project.data.find((elm) => elm.date.split("-").reverse().join("-") === element)).map((element) => ({
+// x: element,
+// y: 0,
+// r: (index * 2) + 6
+// }))]
+// }))
+// }, [chartDataProject, axisX])
+
+// const processedZoneData = useMemo(() => {
+// return chartDataZone?.map((zone, index) => (
+// {
+// label: "Zone " + zone.label,
+// data: [...zone.data.map((element) => (
+// {
+// x: element.date.split("-").reverse().join("-"),
+// y: element.pourcentage, r: (index * 2) + 6
+// }
+// )), ...axisX.filter((element) => !zone.data.find((elm) => elm.date.split("-").reverse().join("-") === element)).map((element) => ({
+// x: element,
+// y: 0,
+// r: (index * 2) + 6
+// }))]
+// }))
+// }, [chartDataZone, axisX])
+// return (
+//
+//
+//
+//
Collaborateurs
+//
+//
{countUsers}
+//
+//
+//
+//
+//
+//
+//
+//
Projets
+//
+//
{countProjects}
+//
+//
+//
+//
+//
Places
+//
+//
{countPlaces}
+//
+//
+//
+//
+//
+//
+//
+//
+// {(isLoadingZone || isLoadingProject) ?
+//
+//
:
+//
+//
+//
}
+//
+// )
+// }
+
+// export default Reporting
+
+"use client"
import React, { useState, useEffect, useRef, useMemo } from 'react'
import BubbleStatistic from './BubbleStatistic';
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 { getWeeksBetween, getWeekRange, extractDate } 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 = () => {
const [chartDataZone, setChartDataZone] = useState(null)
const [chartDataProject, setChartDataProject] = useState(null)
@@ -22,7 +224,20 @@ const Reporting = () => {
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()) })
+
+ const getCurrentWeekString = () => {
+ const currentDate = new Date();
+ const year = currentDate.getFullYear();
+ const week = getWeekNumber(currentDate);
+ return `${year}-W${week.toString().padStart(2, '0')}`;
+ }
+
+ const currentWeekString = getCurrentWeekString();
+
+ const [weeks, setWeeks] = useState({
+ fromWeek: getCurrentWeekString(), // Initialize with current week
+ toWeek: getCurrentWeekString()
+ });
useEffect(() => {
const getStats = async () => {
@@ -44,22 +259,22 @@ const Reporting = () => {
}
getStats()
}, [])
- console.log(countPlaces)
- console.log(countProjects)
- console.log(countUsers)
useEffect(() => {
const getZonesPresenceStatistic = async () => {
setIsLoadingZone(true)
+ const { weekStart: from_date, weekEnd: to_date } = getWeekRange(weeks.fromWeek);
+ const { weekStart: end_from_date, weekEnd: end_to_date } = getWeekRange(weeks.toWeek);
const { data, errors, isSuccess } = await fetchRequest(`/zoaning/zone-presence/`, {
method: "POST",
body: JSON.stringify({
- from_date: dates.fromDate,
- to_date: dates.toDate
+ from_date: from_date,
+ to_date: end_to_date
})
})
setIsLoadingZone(false)
if (isSuccess) {
+ console.log("zones presences :", data)
setChartDataZone(data);
} else {
console.log(errors);
@@ -71,23 +286,23 @@ const Reporting = () => {
}
}
getZonesPresenceStatistic()
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [dates.fromDate, dates.toDate])
-
+ }, [weeks.fromWeek, weeks.toWeek])
useEffect(() => {
const getProjectsPresenceStatistic = async () => {
setIsLoadingProject(true)
+ const { weekStart: from_date, weekEnd: to_date } = getWeekRange(weeks.fromWeek);
+ const { weekStart: end_from_date, weekEnd: end_to_date } = getWeekRange(weeks.toWeek);
const { data, errors, isSuccess } = await fetchRequest(`/zoaning/project-presence/`, {
method: "POST",
body: JSON.stringify({
- from_date: dates.fromDate,
- to_date: dates.toDate
+ from_date: from_date,
+ to_date: end_to_date
})
})
setIsLoadingProject(false)
if (isSuccess) {
- console.log(data);
+ console.log("projects presences :", data)
setChartDataProject(data);
} else {
console.log(errors);
@@ -99,29 +314,31 @@ const Reporting = () => {
}
}
getProjectsPresenceStatistic()
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [dates.fromDate, dates.toDate])
+ }, [weeks.fromWeek, weeks.toWeek])
+
const handleDateChange = (event) => {
const name = event.target.name
const value = event.target.value
if (value) {
- setDates({ ...dates, [name]: value })
+ setWeeks({ ...weeks, [name]: value })
return;
}
- else if (!value && name === "fromDate") setDates({ ...dates, "fromDate": extractDate(subtractDays(dates.toDate, 5)) })
- else if (!value && name === "toDate") setDates({ ...dates, "toDate": extractDate(new Date()) })
+ else if (!value && name === "fromWeek") setWeeks({ ...weeks, "fromWeek": currentWeekString })
+ else if (!value && name === "toWeek") setWeeks({ ...weeks, "toWeek": currentWeekString })
}
- const axisX = useMemo(() => getDateRange(dates.fromDate, dates.toDate), [dates.fromDate, dates.toDate])
+
+ const axisX = useMemo(() => getWeeksBetween(weeks.fromWeek, weeks.toWeek).map(week => week.axisX), [weeks.fromWeek, weeks.toWeek]);
+
const processedProjectData = useMemo(() => {
return chartDataProject?.map((project, index) => (
{
label: project.label,
data: [...project.data.map((element) => (
{
- x: element.date.split("-").reverse().join("-"),
+ x: element.start_date_week+' -- '+element.end_date_week,
y: element.pourcentage, r: (index * 2) + 6
}
- )), ...axisX.filter((element) => !project.data.find((elm) => elm.date.split("-").reverse().join("-") === element)).map((element) => ({
+ )), ...axisX.filter((element) => !project.data.find((elm) => elm.start_date_week == element.split('--')[0].trim())).map((element) => ({
x: element,
y: 0,
r: (index * 2) + 6
@@ -135,16 +352,17 @@ const Reporting = () => {
label: "Zone " + zone.label,
data: [...zone.data.map((element) => (
{
- x: element.date.split("-").reverse().join("-"),
+ x: element.start_date_week+' -- '+element.end_date_week,
y: element.pourcentage, r: (index * 2) + 6
}
- )), ...axisX.filter((element) => !zone.data.find((elm) => elm.date.split("-").reverse().join("-") === element)).map((element) => ({
+ )), ...axisX.filter((element) => !zone.data.find((elm) => elm.start_date_week == element.split('--')[0].trim())).map((element) => ({
x: element,
y: 0,
r: (index * 2) + 6
}))]
}))
}, [chartDataZone, axisX])
+
return (
@@ -180,13 +398,12 @@ const Reporting = () => {
@@ -200,4 +417,17 @@ const Reporting = () => {
)
}
-export default Reporting
\ No newline at end of file
+export default Reporting
+
+/**
+ * Get the ISO week number of a date.
+ * @param {Date} date - The date to get the week number for.
+ * @returns {number} The ISO week number.
+ */
+const getWeekNumber = (date) => {
+ const tempDate = new Date(date.getTime());
+ tempDate.setHours(0, 0, 0, 0);
+ tempDate.setDate(tempDate.getDate() + 3 - ((tempDate.getDay() + 6) % 7));
+ const week1 = new Date(tempDate.getFullYear(), 0, 4);
+ return 1 + Math.round(((tempDate.getTime() - week1.getTime()) / 86400000 - 3 + ((week1.getDay() + 6) % 7)) / 7);
+};
diff --git a/src/app/lib/DateHelper.js b/src/app/lib/DateHelper.js
index f4aac7651c2645bb2c14673c40a1bfa538c50039..a056401f635a4d48bcc3a3baec2a57c99ec4be23 100644
--- a/src/app/lib/DateHelper.js
+++ b/src/app/lib/DateHelper.js
@@ -1,32 +1,120 @@
-export const subtractDays = (date, numberOfDays) => {
- const result = new Date(date);
- result.setDate(result.getDate() - numberOfDays);
- return result;
+// export const subtractDays = (date, numberOfDays) => {
+// const result = new Date(date);
+// result.setDate(result.getDate() - numberOfDays);
+// return result;
+// };
+
+// /**
+// * date {Date}
+// * @return 2024-10-12
+// */
+// export const extractDate = (date) => {
+// if (date instanceof Date)
+// return date.toJSON().split("T")[0]
+// else throw new Error("date isn't instance of Date in extractDate Util function")
+// }
+
+
+// export const getDateRange = (fromDate, toDate) => {
+// const startDate = new Date(fromDate);
+// const endDate = new Date(toDate);
+
+// const dateArray = [];
+
+// let currentDate = startDate;
+// while (currentDate <= endDate) {
+// dateArray.push(currentDate.toISOString().split('T')[0].split("-").reverse().join("-"));
+
+// currentDate.setDate(currentDate.getDate() + 1);
+// }
+
+// return dateArray;
+// }
+
+/**
+ * Convert a week string (YYYY-W##) to a date object representing the first day of that week.
+ * @param {string} weekString - The week string in format 'YYYY-W##'.
+ * @returns {Date} The date object representing the first day of the week.
+ */
+const getFirstDayOfWeek = (weekString) => {
+ const [year, week] = weekString.split('-W').map(Number);
+ const simple = new Date(year, 0, 1 + (week - 1) * 7);
+ const dow = simple.getDay();
+ let ISOweekStart = new Date(simple);
+
+ if (dow <= 4) {
+ ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
+ } else {
+ ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
+ }
+
+ // Adjust for time zone offset to ensure consistency
+ ISOweekStart.setHours(0, 0, 0, 0);
+
+ return ISOweekStart;
+};
+/**
+ * Get the start and end dates of the week given a week string (YYYY-W##).
+ * @param {string} weekString - The week string in format 'YYYY-W##'.
+ * @returns {Object} An object with `weekStart` and `weekEnd` dates.
+ */
+export const getWeekRange = (weekString) => {
+ const startDate = getFirstDayOfWeek(weekString);
+ const endDate = new Date(startDate);
+ endDate.setDate(startDate.getDate() + 6);
+
+ // Adjust for time zone offset to ensure consistency
+ endDate.setHours(23, 59, 59, 999);
+
+ return {
+ weekStart: extractDate(startDate),
+ weekEnd: extractDate(endDate)
+ };
};
/**
- * date {Date}
- * @return 2024-10-12
+ * Extract the date in 'YYYY-MM-DD' format.
+ * @param {Date} date - The date to format.
+ * @returns {string} The formatted date string.
+ * @throws {Error} If the input is not an instance of Date.
*/
export const extractDate = (date) => {
- if (date instanceof Date)
- return date.toJSON().split("T")[0]
- else throw new Error("date isn't instance of Date in extractDate Util function")
-}
+ if (date instanceof Date) {
+ return date.toJSON().split("T")[0];
+ } else {
+ throw new Error("date isn't instance of Date in extractDate Util function");
+ }
+};
+/**
+ * Get the weeks between two week strings (YYYY-W##).
+ * @param {string} fromWeek - The start week string in format 'YYYY-W##'.
+ * @param {string} toWeek - The end week string in format 'YYYY-W##'.
+ * @returns {Array} An array of objects containing the start and end dates of each week.
+ */
+export const getWeeksBetween = (fromWeek, toWeek) => {
+ const fromDate = getFirstDayOfWeek(fromWeek);
+ const toDate = getFirstDayOfWeek(toWeek);
+ const weeks = [];
-export const getDateRange = (fromDate, toDate) => {
- const startDate = new Date(fromDate);
- const endDate = new Date(toDate);
+ let currentDate = fromDate;
+ while (currentDate <= toDate) {
+ const weekEnd = new Date(currentDate);
+ weekEnd.setDate(currentDate.getDate() + 6);
- const dateArray = [];
+ // Adjust for time zone offset to ensure consistency
+ weekEnd.setHours(23, 59, 59, 999);
- let currentDate = startDate;
- while (currentDate <= endDate) {
- dateArray.push(currentDate.toISOString().split('T')[0].split("-").reverse().join("-"));
+ const adjustedStartDate = new Date(currentDate);
+ adjustedStartDate.setDate(currentDate.getDate() + 1);
+ weeks.push({
+ axisX: `${extractDate(adjustedStartDate)} -- ${extractDate(weekEnd)}`,
+ weekStart: extractDate(currentDate),
+ weekEnd: extractDate(weekEnd)
+ });
- currentDate.setDate(currentDate.getDate() + 1);
+ currentDate.setDate(currentDate.getDate() + 7);
}
- return dateArray;
-}
\ No newline at end of file
+ return weeks;
+};
\ No newline at end of file