diff --git a/.vs/2024-DEV-BUT3/v17/.wsuo b/.vs/2024-DEV-BUT3/v17/.wsuo
index ac4359c..e30e1c1 100644
Binary files a/.vs/2024-DEV-BUT3/v17/.wsuo and b/.vs/2024-DEV-BUT3/v17/.wsuo differ
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
index c231ed8..dc91451 100644
Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ
diff --git a/src/api/authentication.js b/src/api/authentication.js
index b183005..2238843 100644
--- a/src/api/authentication.js
+++ b/src/api/authentication.js
@@ -6,7 +6,7 @@ export const isLoggedIn = async () => {
return response.data;
} catch (error) {
- return error.response.data;
+ return error.responseq;
}
};
@@ -15,7 +15,7 @@ export const login = async (username, password) => {
const response = await axios.post("/authenticate", { username, password });
return response.data;
} catch (error) {
- return error.response.data;
+ return error.response;
}
};
@@ -25,6 +25,6 @@ export const logout = async () => {
return response.data;
} catch (error) {
- return error.response.data;
+ return error.response;
}
};
diff --git a/src/api/room.js b/src/api/room.js
index 09ceb90..41e3b3b 100644
--- a/src/api/room.js
+++ b/src/api/room.js
@@ -5,7 +5,7 @@ import axios from "axios";
export const getRoom = async (_id) => {
try {
- const response = await axios.get("/room", {_id});
+ const response = await axios.get("/room/"+{_id});
console.log(response.data)
return response.data;
} catch (error) {
@@ -16,7 +16,7 @@ export const getRoom = async (_id) => {
export const getRooms = async () => {
try {
- const response = await axios.get("/room", {});
+ const response = await axios.get("/room");
console.log(response.data)
return response.data;
} catch (error) {
@@ -24,3 +24,60 @@ export const getRooms = async () => {
return error.response.data;
}
};
+
+export const getRoomStats = async () => {
+ try {
+ const response = await axios.get("/room/stats");
+ console.log(response.data)
+ return response.data;
+ } catch (error) {
+ console.log("ERROR", error.response.data)
+ return error.response.data;
+ }
+};
+
+export const formatRoomStats = (roomStats) => {
+ const global = formatRoomStatsGlobal(roomStats.global)
+ const rooms = Object.values(roomStats.rooms).map(formatRoom);
+ const years = roomStats.years;
+ return {
+ global,
+ rooms,
+ years
+ }
+}
+
+function formatRoomStatsGlobal(global){
+ const { rooms_count, items_count, total_price, average_price} = global;
+
+ const most_item_room = {
+ name: global.most_item_room.name,
+ count: global.most_item_room.count
+ };
+
+ const most_expensive_room = {
+ name: global.most_expensive_room.name,
+ price: global.most_expensive_room.price
+ };
+
+ return {
+ rooms_count,
+ items_count,
+ total_price,
+ average_price,
+ most_item_room,
+ most_expensive_room
+ };
+}
+
+
+function formatRoom(room) {
+ const { _id, name, items_count, room_price } = room;
+
+ return {
+ _id,
+ name,
+ items_count,
+ room_price
+ };
+}
\ No newline at end of file
diff --git a/src/assets/styles/diagram.css b/src/assets/styles/diagram.css
new file mode 100644
index 0000000..094e6f9
--- /dev/null
+++ b/src/assets/styles/diagram.css
@@ -0,0 +1,40 @@
+.diagram-container {
+ width: 100%; /* Utilise toute la largeur horizontale disponible */
+ margin-bottom: 20px;
+}
+
+.row-container {
+ display: flex;
+ align-items: flex-end; /* Alignement des éléments à la base */
+ margin-bottom: 10px;
+}
+
+.row {
+ background-color: #007bff;
+ height: 20px;
+ position: relative;
+ border-radius: 5px;
+ transition: width 0.5s ease;
+
+}
+
+.value {
+ position: absolute;
+ bottom: 50%; /* Alignement par rapport à la base de l'élément parent */
+ right: 0;
+ transform: translate(50%, 50%); /* Ajustement de la position */
+ color: white;
+ font-size: 12px;
+ padding: 5px;
+ border-radius: 3px;
+ background-color: rgba(0, 0, 0, 0.8);
+}
+
+.label {
+ width: 55px;
+ text-align: center;
+ font-size: 14px;
+ color: #333;
+ position: relative; /* Permet l'alignement des labels à la base */
+ bottom: 0; /* Alignement à la base */
+}
\ No newline at end of file
diff --git a/src/assets/styles/room-page.css b/src/assets/styles/room-page.css
new file mode 100644
index 0000000..0443219
--- /dev/null
+++ b/src/assets/styles/room-page.css
@@ -0,0 +1,18 @@
+.manContainer {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.topContainer {
+ display: flex;
+ flex-grow: 1;
+}
+
+.statsContainer, .listContainer {
+ flex-grow: 1;
+}
+
+.detailContainer {
+ height: 50%;
+}
diff --git a/src/assets/styles/room-stats.css b/src/assets/styles/room-stats.css
new file mode 100644
index 0000000..31cac00
--- /dev/null
+++ b/src/assets/styles/room-stats.css
@@ -0,0 +1,47 @@
+.room-stats-container {
+ display: flex;
+ flex-direction: column;
+ margin: 20px;
+}
+
+.text-stats {
+ background-color: #f9f9f9;
+ padding: 20px;
+ border-radius: 5px;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+}
+
+.stats-info {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 20px;
+}
+
+.stat {
+ padding: 10px;
+ border: 1px solid #ddd;
+ border-radius: 5px;
+}
+
+ .stat p {
+ margin: 0;
+ font-weight: bold;
+ }
+
+ .stat ul {
+ list-style: none;
+ padding: 0;
+ margin: 5px 0;
+ }
+
+ .stat ul li {
+ margin: 5px 0;
+ }
+
+.diagram {
+ background-color: #fff;
+ padding: 20px;
+ border-radius: 5px;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+}
diff --git a/src/components/diagram.jsx b/src/components/diagram.jsx
new file mode 100644
index 0000000..24dcb57
--- /dev/null
+++ b/src/components/diagram.jsx
@@ -0,0 +1,30 @@
+import React, { useState, useEffect } from "react";
+import { Col, Row } from "antd";
+import '../assets/styles/diagram.css'
+
+
+const Diagram = ({ data }) => {
+ const [diagramData, setDiagramData] = useState(data);
+
+ useEffect(() => {
+ setDiagramData(data);
+ }, [data]);
+
+ const maxValue = Math.max(...diagramData.map(item => item.value));
+
+ return (
+
+
Prix total par an
+ {diagramData.map(({ name, value }) => (
+
+ ))}
+
+ );
+};
+
+export default Diagram;
\ No newline at end of file
diff --git a/src/components/form/formUpdateItem.jsx b/src/components/form/formUpdateItem.jsx
index b2037e6..ca54b2f 100644
--- a/src/components/form/formUpdateItem.jsx
+++ b/src/components/form/formUpdateItem.jsx
@@ -8,34 +8,24 @@ import moment from 'moment';
const { Option } = Select;
-function formatItem(itemObj) {//_id, brand, model, room, price, purchaseDate, description, categories, createdAt, updatedAt, __v, link) {
- let _id = itemObj._id
- let brand = itemObj.brand
- let model = itemObj.model
- let room = itemObj.room
- let price = itemObj.price
- let purchaseDate = new Date(itemObj.purchaseDate)
- let description = itemObj.description
- let categories = itemObj.categories
- let createdAt = itemObj.createdAt
- let updatedAt = itemObj.updatedAt
- let __v = itemObj.__v
- let link = itemObj.link
- let item = {
+function formatItem(itemObj) {
+ const {_id,brand,model,room,price,purchaseDate,description,categories,createdAt,updatedAt,__v,link} = itemObj
+ const formattedPurchaseDate = typeof purchaseDate === 'string' ? new Date(purchaseDate) : purchaseDate;
+
+ return {
_id,
brand,
model,
room,
price,
- purchaseDate,
+ purchaseDate: formattedPurchaseDate,
description,
categories,
createdAt,
updatedAt,
__v,
link
- }
- return item;
+ };
}
export const FormUpdateItem = ({ itemId }) => {
diff --git a/src/components/item/ItemBox.jsx b/src/components/item/ItemBox.jsx
index 1ea6ad2..3a6ad85 100644
--- a/src/components/item/ItemBox.jsx
+++ b/src/components/item/ItemBox.jsx
@@ -1,40 +1,10 @@
import React, { useEffect, useState } from 'react';
-import { searchAndResizeImage } from '../../api/image-request'
import '../../assets/styles/modal.css'
import '../../assets/styles/itembox.css'
import FormUpdateItem from '../form/formUpdateItem';
-// Composant Image
-const Image = ({ src, alt, request, _id }) => {
- const [cacheUrl, setCacheUrl] = useState(null);
- useEffect(() => {
- const fetchData = async () => {
- let cachedUrl = localStorage.getItem(_id);
- if (!cachedUrl) {
- try {
- cachedUrl = await searchAndResizeImage(request);
- localStorage.setItem(_id, cachedUrl);
- console.log("Mise en cache de l'image avec l'ID : " + _id);
- } catch (error) {
- console.error("Erreur lors de la récupération de l'image : ", error);
- }
- }
- setCacheUrl(cachedUrl);
- };
-
- fetchData();
- }, [request, _id]);
-
- if (src) {
- return ;
- } else if (cacheUrl) {
- return ;
- } else {
- return ;
- }
-};
// Composant Description
const Description = ({ title, children }) => {
diff --git a/src/components/nav/Navbar.jsx b/src/components/nav/Navbar.jsx
index ea3df3f..30fbb66 100644
--- a/src/components/nav/Navbar.jsx
+++ b/src/components/nav/Navbar.jsx
@@ -60,7 +60,10 @@ const Navbar = () => {
,
{roomItems}
-
+ ,
+
+ Voir les chambres
+ ,
];
diff --git a/src/components/parts/image.jsx b/src/components/parts/image.jsx
new file mode 100644
index 0000000..ac6c3fc
--- /dev/null
+++ b/src/components/parts/image.jsx
@@ -0,0 +1,34 @@
+
+import React, { useEffect, useState } from 'react';
+import { searchAndResizeImage } from '../../api/image-request'
+
+// Composant Image
+export const Image = ({ src, alt, request, _id }) => {
+ const [cacheUrl, setCacheUrl] = useState(null);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ let cachedUrl = localStorage.getItem(_id);
+ if (!cachedUrl) {
+ try {
+ cachedUrl = await searchAndResizeImage(request);
+ localStorage.setItem(_id, cachedUrl);
+ console.log("Mise en cache de l'image avec l'ID : " + _id);
+ } catch (error) {
+ console.error("Erreur lors de la récupération de l'image : ", error);
+ }
+ }
+ setCacheUrl(cachedUrl);
+ };
+
+ fetchData();
+ }, [request, _id]);
+
+ if (src) {
+ return ;
+ } else if (cacheUrl) {
+ return ;
+ } else {
+ return ;
+ }
+}
\ No newline at end of file
diff --git a/src/components/rooms/room-list.jsx b/src/components/rooms/room-list.jsx
new file mode 100644
index 0000000..e2a1ed6
--- /dev/null
+++ b/src/components/rooms/room-list.jsx
@@ -0,0 +1,46 @@
+import React, { useState, useEffect } from "react";
+import axios from 'axios'; // Assurez-vous que le chemin d'importation soit correct
+import { ItemBox } from './ItemBox';
+import { Space, DatePicker, Row, Col, Select, Input, InputNumber } from 'antd';
+import '../../assets/styles/item-page.css'
+
+
+
+const { RangePicker } = DatePicker;
+const { Option } = Select;
+
+const itemsPerPage = 8; // Nombre total d'items par page
+const itemsPerRow = 4; // Nombre d'items par rangée
+
+// Fonction pour diviser le tableau d'items en rangées
+const chunkArray = (arr, size) => {
+ const chunkedArr = [];
+ for (let i = 0; i < arr.length; i += size) {
+ chunkedArr.push(arr.slice(i, i + size));
+ }
+ return chunkedArr;
+};
+
+// Composant d'affichage de la page
+export const RoomList = (roomsParam) => {
+ const [rooms, setRooms] = useState([]);
+ const [selectedRoom, setSelectedRoom] = useState('all');
+
+ useEffect(() => {
+ setRooms(roomsParam)
+ }, [roomsParam]);
+
+ const handleRoomChange = (value) => {
+ setSelectedRoom(value);
+ };
+
+ return (
+
+
+ {rooms.forEach((room) => {
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/components/rooms/room-stats.jsx b/src/components/rooms/room-stats.jsx
new file mode 100644
index 0000000..8e6742c
--- /dev/null
+++ b/src/components/rooms/room-stats.jsx
@@ -0,0 +1,69 @@
+import React, { useEffect, useState } from 'react';
+
+import { formatRoomStats } from '../../api/room'
+import Diagram from '../diagram';
+import '../../assets/styles/room-stats.css'
+
+
+
+const RoomStats = ({statsParam}) => {
+ const [stats, setStats] = useState();
+ const [diagramValues, setDiagramValues] = useState([])
+
+ useEffect(() => {
+ if (statsParam.global) {
+ console.log(statsParam)
+ let formatedStats = formatRoomStats(statsParam)
+ setStats(formatedStats)
+ }
+ }, [statsParam]);
+
+ useEffect(() => {
+ if (stats) {
+ let table = Object.entries(stats.years)
+ .filter(([year, value]) => value !== 0) // Filtrer les entrées où Y n'est pas égal à 0
+ .map(([year, value]) => ({ name: year, value: value }));
+ setDiagramValues(table);
+ }
+ }, [stats])
+
+ return (
+
+
+
Statistiques des chambres
+
+
+
Total des chambres :
+
{stats?.global?.rooms_count}
+
+
+
Total des articles :
+
{stats?.global?.items_count}
+
+
+
Prix total :
+
{stats?.global?.total_price}
+
+
+
La chambre avec le plus d'articles :
+
+ - {stats?.global.most_item_room?.name}
+ - Nombre d'articles : {stats?.global?.most_item_room?.count}
+
+
+
+
La chambre la plus chère :
+
+ - {stats?.global?.most_expensive_room?.name}
+ - Prix total : {stats?.global?.most_expensive_room?.price}
+
+
+
+
+
+
+
+
+ );
+};
+export default RoomStats;
\ No newline at end of file
diff --git a/src/components/rooms/roomBox.jsx b/src/components/rooms/roomBox.jsx
new file mode 100644
index 0000000..f5d0626
--- /dev/null
+++ b/src/components/rooms/roomBox.jsx
@@ -0,0 +1,23 @@
+import React, { useEffect, useState } from 'react';
+import '../../assets/styles/itembox.css'
+import { } from '../item/ItemBox'
+
+
+// Composant Détails du Produit
+export const RoomBox = ({ name, itemCount, roomPrice, _id }) => {
+ const [roomData, setRoomData] = useState();
+
+ useEffect(() => {
+ setRoomData({name, itemCount, roomPrice, _id})
+ }, [name, itemCount, roomPrice, _id]);
+
+
+ return (
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/pages/rooms-stats.jsx b/src/pages/rooms-stats.jsx
deleted file mode 100644
index 8087dec..0000000
--- a/src/pages/rooms-stats.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React, { useEffect } from 'react';
-
-import { useAuth } from "../hooks";
-import { ItemPage } from "../components/item/ItemPage";
-import { usePageTitle } from '../hooks/page-title-context';
-
-export const RoomsStats = () => {
- const { user } = useAuth();
- const { setPageTitle } = usePageTitle();
-
-
- // Mettre à jour le titre de la page dans le contexte
- useEffect(() => {
- setPageTitle("Toutes les rooms :");
- }, [setPageTitle]);
-
- useEffect(() => {
- setPageTitle("Toutes les rooms :");
- }, [setPageTitle]);
- return (
-
- );
-};
diff --git a/src/pages/rooms.jsx b/src/pages/rooms.jsx
new file mode 100644
index 0000000..7e472c9
--- /dev/null
+++ b/src/pages/rooms.jsx
@@ -0,0 +1,46 @@
+import React, { useEffect, useState } from 'react';
+import '../assets/styles/room-page.css'
+
+import { useAuth } from "../hooks";
+import { formatRoomStats, getRooms, getRoomStats } from "../api/room";
+import { usePageTitle } from '../hooks/page-title-context';
+import RoomStats from '../components/rooms/room-stats';
+
+export const Rooms = () => {
+ const { user } = useAuth();
+ const { setPageTitle } = usePageTitle();
+ const [stats, setStats] = useState({});
+
+
+ // Mettre à jour le titre de la page dans le contexte
+ useEffect(() => {
+ setPageTitle("Toutes les rooms :");
+ }, [setPageTitle]);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const roomsStatsResponse = await getRoomStats();
+ setStats(roomsStatsResponse);
+ };
+
+ fetchData();
+ }, []);
+
+
+ return (
+
+ );
+};
diff --git a/src/router.jsx b/src/router.jsx
index 1147a9b..368f59b 100644
--- a/src/router.jsx
+++ b/src/router.jsx
@@ -3,6 +3,7 @@ import { Route, Routes } from "react-router-dom";
import { Home, Login, Register } from "./pages";
import { Items } from "./pages/items";
+import { Rooms } from "./pages/rooms";
export const Router = () => (
@@ -11,5 +12,6 @@ export const Router = () => (
} />
} />
} />
+ } />
);