fix jsp pein de truc en vrais

This commit is contained in:
Victor 2024-05-13 00:13:34 +02:00
parent 18b7052259
commit 2868efcda4
5 changed files with 1158 additions and 981 deletions

1642
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,12 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Form, Input, InputNumber, Button, Select } from "antd"; import { Form, Input, InputNumber, Button, Select, DatePicker } from "antd";
import axios from "axios"; import axios from "axios";
const { TextArea } = Input; const { TextArea } = Input;
const { Option } = Select; const { Option } = Select;
const dateFormat = "YYYY-MM-DD";
export const FormCreateItem = () => { export const FormCreateItem = ({ onClose }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [rooms, setRooms] = useState([]); const [rooms, setRooms] = useState([]);
@ -31,6 +32,8 @@ export const FormCreateItem = () => {
values, values,
); );
console.log(response.data); console.log(response.data);
// Fermer la fenêtre modale après soumission réussie
onClose();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@ -58,7 +61,7 @@ export const FormCreateItem = () => {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item label="Purchase Date" name="purchaseDate"> <Form.Item label="Purchase Date" name="purchaseDate">
<Input /> <DatePicker format={dateFormat} />
</Form.Item> </Form.Item>
<Form.Item label="Description" name="description"> <Form.Item label="Description" name="description">
<TextArea rows={4} /> <TextArea rows={4} />

View File

@ -3,113 +3,125 @@ import { Form, Input, InputNumber, Button, Select, DatePicker } from "antd";
import axios from "axios"; import axios from "axios";
import { getRooms } from "../../api/room"; import { getRooms } from "../../api/room";
import { getItem } from "../../api/item"; import { getItem } from "../../api/item";
import moment from 'moment'; import moment from "moment";
const { Option } = Select; const { Option } = Select;
function formatItem(itemObj) { function formatItem(itemObj) {
const {_id,brand,model,room,price,purchaseDate,description,categories,createdAt,updatedAt,__v,link} = itemObj const {
const formattedPurchaseDate = typeof purchaseDate === 'string' ? new Date(purchaseDate) : purchaseDate; _id,
brand,
model,
room,
price,
purchaseDate,
description,
categories,
createdAt,
updatedAt,
__v,
link,
} = itemObj;
const formattedPurchaseDate =
typeof purchaseDate === "string" ? new Date(purchaseDate) : purchaseDate;
return { return {
_id, _id,
brand, brand,
model, model,
room, room,
price, price,
purchaseDate: formattedPurchaseDate, purchaseDate: formattedPurchaseDate,
description, description,
categories, categories,
createdAt, createdAt,
updatedAt, updatedAt,
__v, __v,
link link,
}; };
} }
export const FormUpdateItem = ({ itemId }) => { export const FormUpdateItem = ({ itemId, onClose }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [rooms, setRooms] = useState([]); const [rooms, setRooms] = useState([]);
const [item, setItem] = useState(null) const [item, setItem] = useState(null);
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
const roomsResponse = await getRooms(); const roomsResponse = await getRooms();
setRooms(roomsResponse); setRooms(roomsResponse);
const itemResponse = await getItem(itemId); const itemResponse = await getItem(itemId);
console.log(itemResponse) console.log(itemResponse);
setItem(formatItem(itemResponse)); setItem(formatItem(itemResponse));
};
fetchData();
}, [itemId]);
useEffect(() => {
if (item) {
form.setFieldsValue({
...item,
purchaseDate: item.purchaseDate ? moment(item.purchaseDate) : null,
});
}
}, [item, form]);
const onFinish = async (values) => {
try {
const response = await axios.put(
`${import.meta.env.VITE_API_URL}/item/${item._id}`,
values,
);
console.log(response.data);
} catch (error) {
console.error(error);
}
}; };
const dateFormat = 'YYYY-MM-DD'; fetchData();
return ( }, [itemId]);
<Form
form={form} useEffect(() => {
onFinish={onFinish} if (item) {
initialValues={item} // Initialise le formulaire avec les valeurs de l'élément form.setFieldsValue({
> ...item,
<h1>Update Item</h1> purchaseDate: item.purchaseDate ? moment(item.purchaseDate) : null,
<Form.Item label="Brand" name="brand"> });
<Input /> }
</Form.Item> }, [item, form]);
<Form.Item label="Model" name="model">
<Input /> const onFinish = async (values) => {
</Form.Item> try {
<Form.Item label="Room" name="room"> const response = await axios.put(
<Select placeholder="Select a room"> `${import.meta.env.VITE_API_URL}/item/${item._id}`,
{console.log(rooms)} values,
{ );
rooms.map((room) => ( console.log(response.data);
<Option key={room._id} value={room._id}> // Fermer la fenêtre modale après soumission réussie
{room.name} onClose();
</Option> } catch (error) {
))} console.error(error);
</Select> }
</Form.Item> };
<Form.Item label="Price" name="price">
<InputNumber /> const dateFormat = "YYYY-MM-DD";
</Form.Item> return (
<Form.Item label="Purchase Date" name="purchaseDate"> <Form
<DatePicker form={form}
dateFormat={dateFormat} onFinish={onFinish}
/> initialValues={item} // Initialise le formulaire avec les valeurs de l'élément
</Form.Item> >
<Form.Item label="Description" name="description"> <h1>Update Item</h1>
<Input.TextArea rows={4} /> <Form.Item label="Brand" name="brand">
</Form.Item> <Input />
<Form.Item> </Form.Item>
<Button type="primary" htmlType="submit"> <Form.Item label="Model" name="model">
Submit <Input />
</Button> </Form.Item>
</Form.Item> <Form.Item label="Room" name="room">
</Form> <Select placeholder="Select a room">
); {console.log(rooms)}
{rooms.map((room) => (
<Option key={room._id} value={room._id}>
{room.name}
</Option>
))}
</Select>
</Form.Item>
<Form.Item label="Price" name="price">
<InputNumber />
</Form.Item>
<Form.Item label="Purchase Date" name="purchaseDate">
<DatePicker dateFormat={dateFormat} />
</Form.Item>
<Form.Item label="Description" name="description">
<Input.TextArea rows={4} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
}; };
export default FormUpdateItem; export default FormUpdateItem;

View File

@ -1,16 +1,14 @@
import React, { useEffect, useState } from 'react'; import React, { useState } from "react";
import '../../assets/styles/modal.css' import "../../assets/styles/modal.css";
import '../../assets/styles/itembox.css' import "../../assets/styles/itembox.css";
import FormUpdateItem from '../form/formUpdateItem'; import FormUpdateItem from "../form/formUpdateItem";
import {Image } from '../parts/image' import { Image } from "../parts/image";
// Composant Description // Composant Description
const Description = ({ title, children }) => { const Description = ({ title, children }) => {
return ( return (
<div className="description"> <div className="description">
<h2 className="text-ellipsis">{title}</h2> <h2 className="text-ellipsis">{title}</h2>
{children} {children}
</div> </div>
); );
@ -18,7 +16,6 @@ const Description = ({ title, children }) => {
// Composant Caractéristique // Composant Caractéristique
const Characteristic = ({ label, value }) => { const Characteristic = ({ label, value }) => {
return ( return (
<div className="characteristic"> <div className="characteristic">
<strong>{label}:</strong> {value} <strong>{label}:</strong> {value}
@ -26,52 +23,48 @@ const Characteristic = ({ label, value }) => {
); );
}; };
// Composant Détails du Produit // Composant Détails du Produit
export const ItemBox = ({ model, brand, purchaseDate, price, _id }) => { export const ItemBox = ({ model, brand, purchaseDate, price, _id }) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false); // Fonction pour ouvrir la fenêtre modale
const openModal = () => {
setIsModalOpen(true);
};
// Fonction pour ouvrir la fenêtre modale // Fonction pour fermer la fenêtre modale
const openModal = () => { const closeModal = () => {
setIsModalOpen(true); setIsModalOpen(false);
}; };
// Fonction pour fermer la fenêtre modale let productname = brand + " " + model;
const closeModal = () => { let formatedPrice = price + "€";
setIsModalOpen(false); let formatedDate = new Date(purchaseDate).toLocaleDateString("fr-FR");
};
let request = brand + " " + model;
return (
let productname = brand + " " + model; <div className="product-details">
let formatedPrice = price + "€"; <Description title={productname}>
let formatedDate = new Date(purchaseDate).toLocaleDateString('fr-FR'); <Image request={request} _id={_id} alt="Product" />
<Characteristic label="Model" value={model} />
let request = brand + " " + model <Characteristic label="Brand" value={brand} />
<Characteristic label="Purchase Date" value={formatedDate} />
return ( <Characteristic label="Price" value={formatedPrice} />
<div className="product-details" > {/* Bouton d'édition pour ouvrir la fenêtre modale */}
<Description title={productname} > <button onClick={openModal}>Edit</button>
<Image request={request} _id={_id} alt="Product" /> </Description>
<Characteristic label="Model" value={model} /> {/* Fenêtre modale pour la mise à jour */}
<Characteristic label="Brand" value={brand} /> {isModalOpen && (
<Characteristic label="Purchase Date" value={formatedDate} /> <div className="modal">
<Characteristic label="Price" value={formatedPrice} /> <div className="modal-content">
{/* Bouton d'édition pour ouvrir la fenêtre modale */} <span className="close" onClick={closeModal}>
<button onClick={openModal}>Edit</button> &times;
</Description> </span>
{/* Fenêtre modale */} <FormUpdateItem itemId={_id} onClose={closeModal} />
{isModalOpen && ( </div>
<div className="modal">
<div className="modal-content">
<span className="close" onClick={closeModal}>&times;</span>
<FormUpdateItem itemId={_id}>{console.log("item ID :" + _id)}</FormUpdateItem>
</div>
</div>
)}
</div> </div>
); )}
}; </div>
);
};

View File

@ -1,18 +1,16 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import axios from 'axios'; // Assurez-vous que le chemin d'importation soit correct import axios from "axios";
import { ItemBox } from './ItemBox'; import { ItemBox } from "./ItemBox";
import { Space, DatePicker, Row, Col, Select, Input, InputNumber } from 'antd'; import { DatePicker, Row, Col, Select, Input, InputNumber } from "antd";
import '../../assets/styles/item-page.css' import "../../assets/styles/item-page.css";
import FormCreateItem from "../form/formCreateItem";
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const { Option } = Select; const { Option } = Select;
const itemsPerPage = 8; // Nombre total d'items par page const itemsPerPage = 8;
const itemsPerRow = 4; // Nombre d'items par rangée const itemsPerRow = 4;
// Fonction pour diviser le tableau d'items en rangées
const chunkArray = (arr, size) => { const chunkArray = (arr, size) => {
const chunkedArr = []; const chunkedArr = [];
for (let i = 0; i < arr.length; i += size) { for (let i = 0; i < arr.length; i += size) {
@ -21,39 +19,26 @@ const chunkArray = (arr, size) => {
return chunkedArr; return chunkedArr;
}; };
// Composant d'affichage de la page
export const ItemPage = () => { export const ItemPage = () => {
const [items, setItems] = useState([]); const [items, setItems] = useState([]);
const [filteredItems, setFilteredItems] = useState([]); // State pour les items filtrés const [filteredItems, setFilteredItems] = useState([]);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [filterName, setFilterName] = useState(''); const [filterName, setFilterName] = useState("");
const [filterPriceMin, setFilterPriceMin] = useState(''); const [filterPriceMin, setFilterPriceMin] = useState("");
const [filterPriceMax, setFilterPriceMax] = useState(''); const [filterPriceMax, setFilterPriceMax] = useState("");
const [filterDateRange, setFilterDateRange] = useState([]); const [filterDateRange, setFilterDateRange] = useState([]);
const [selectedRoom, setSelectedRoom] = useState('all'); // State pour la chambre sélectionnée const [selectedRoom, setSelectedRoom] = useState("all");
const [rooms, setRooms] = useState([]);
const [rooms, setRooms] = useState([]); // State pour stocker les chambres const [isCreateItemModalOpen, setIsCreateItemModalOpen] = useState(false);
useEffect(() => { useEffect(() => {
const fetchItems = async () => { const fetchItems = async () => {
try { try {
const response = await axios.get( const response = await axios.get(
`${import.meta.env.VITE_API_URL}/item`, `${import.meta.env.VITE_API_URL}/item`,
); );
//await response.data.forEach(async (item) => {
// let cacheUrl = localStorage.getItem(item._id);
// if (cacheUrl == null || cacheUrl == "") {
// let request = item.brand + " " + item.model
// cacheUrl = await searchAndResizeImage(request)
// await localStorage.setItem(item._id, cacheUrl)
// console.log("mise en cache "+ item.imageUrl)
// }
// item.imageUrl = cacheUrl;
//})
setItems(response.data); setItems(response.data);
} } catch (error) {
catch (error) {
console.error(error); console.error(error);
} }
}; };
@ -68,98 +53,108 @@ export const ItemPage = () => {
console.error(error); console.error(error);
} }
}; };
fetchItems(); fetchItems();
fetchRooms(); fetchRooms();
}, []); }, []);
useEffect(() => { useEffect(() => {
// Filtrer les éléments chaque fois que les filtres ou la chambre sélectionnée changent const filtered = items.filter((item) => {
const filtered = items.filter(item => { const matchesRoom = selectedRoom === "all" || item.room === selectedRoom;
// Filtrer par chambre si une chambre est sélectionnée const matchesName =
const matchesRoom = selectedRoom === 'all' || item.room === selectedRoom; item.brand.toLowerCase().includes(filterName.toLowerCase()) ||
// Filtrer par nom (brand ou model) item.model.toLowerCase().includes(filterName.toLowerCase());
const matchesName = item.brand.toLowerCase().includes(filterName.toLowerCase()) || const matchesPrice =
item.model.toLowerCase().includes(filterName.toLowerCase()); (filterPriceMin === "" || item.price >= parseFloat(filterPriceMin)) &&
// Filtrer par prix (filterPriceMax === "" || item.price <= parseFloat(filterPriceMax));
const matchesPrice = const matchesDate =
(filterPriceMin === '' || item.price >= parseFloat(filterPriceMin)) && filterDateRange.length === 0 ||
(filterPriceMax === '' || item.price <= parseFloat(filterPriceMax)); (new Date(item.purchaseDate) >= filterDateRange[0] &&
// Filtrer par date new Date(item.purchaseDate) <= filterDateRange[1]);
const matchesDate = filterDateRange.length === 0 || (
new Date(item.purchaseDate) >= filterDateRange[0] &&
new Date(item.purchaseDate) <= filterDateRange[1]
);
return matchesRoom && matchesName && matchesPrice && matchesDate; return matchesRoom && matchesName && matchesPrice && matchesDate;
}); });
setFilteredItems(filtered); setFilteredItems(filtered);
}, [items, selectedRoom, filterName, filterPriceMin, filterPriceMax, filterDateRange]); }, [
items,
selectedRoom,
filterName,
filterPriceMin,
filterPriceMax,
filterDateRange,
]);
const handleNextPage = () => { const handleNextPage = () => {
setCurrentPage(prevPage => prevPage + 1); setCurrentPage((prevPage) => prevPage + 1);
}; };
const handlePrevPage = () => { const handlePrevPage = () => {
setCurrentPage(prevPage => prevPage - 1); setCurrentPage((prevPage) => prevPage - 1);
}; };
const handleRoomChange = (value) => { const handleRoomChange = (value) => {
setSelectedRoom(value); setSelectedRoom(value);
}; };
const handleCloseModal = () => {
setIsCreateItemModalOpen(false);
};
const chunkedItems = chunkArray(filteredItems, itemsPerRow); const chunkedItems = chunkArray(filteredItems, itemsPerRow);
const startIndex = (currentPage - 1) * (itemsPerPage / itemsPerRow); const startIndex = (currentPage - 1) * (itemsPerPage / itemsPerRow);
const endIndex = startIndex + (itemsPerPage / itemsPerRow); const endIndex = startIndex + itemsPerPage / itemsPerRow;
const rowsToDisplay = chunkedItems.slice(startIndex, endIndex); const rowsToDisplay = chunkedItems.slice(startIndex, endIndex);
return ( return (
<div className="item-container"> <div className="item-container">
<div className="filters"> <div className="filters">{/* Filters here */}</div>
<div className="filter-group">
<label htmlFor="roomSelect">Chambre :</label> {/* Button to open create item modal */}
<Select id="roomSelect" defaultValue="all" style={{ width: 120 }} onChange={handleRoomChange}> <button onClick={() => setIsCreateItemModalOpen(true)}>
<Option value="all">Toutes</Option> Create Item
{rooms.map(room => ( </button>
<Option key={room._id} value={room._id}>{room.name}</Option>
))} {/* Create item form modal */}
</Select> {isCreateItemModalOpen && (
</div> <div className="modal">
<div className="filter-group"> <div className="modal-content">
<label htmlFor="nameInput">Recherche par nom :</label> <span className="close" onClick={handleCloseModal}>
<Input id="nameInput" placeholder="Recherche par nom" value={filterName} onChange={e => setFilterName(e.target.value)} /> &times;
</div> </span>
<div className="filter-group"> <FormCreateItem onClose={handleCloseModal} />
<label>Prix :</label>
<InputNumber placeholder="Prix min" value={filterPriceMin} onChange={value => setFilterPriceMin(value)} />
<span> - </span>
<InputNumber placeholder="Prix max" value={filterPriceMax} onChange={value => setFilterPriceMax(value)} />
</div>
<div className="filter-group">
<label>Date d'achat :</label>
<RangePicker format="YYYY-MM-DD" onChange={dates => setFilterDateRange(dates)} value={filterDateRange} />
</div>
</div>
<div className="item-list">
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{rowsToDisplay.map((row, rowIndex) => (
<React.Fragment key={rowIndex}>
{row.map(item => (
<Col className="gutter-row" span={24 / itemsPerRow} key={item._id}>
<ItemBox {...item} />
</Col>
))}
</React.Fragment>
))}
</Row>
</div>
<div className="pagination">
<button onClick={handlePrevPage} disabled={currentPage === 1}>Précédente</button>
<span>Page {currentPage}</span>
<button onClick={handleNextPage} disabled={endIndex >= chunkedItems.length}>Suivante</button>
</div> </div>
</div>
)}
<div className="item-list">
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{rowsToDisplay.map((row, rowIndex) => (
<React.Fragment key={rowIndex}>
{row.map((item) => (
<Col
className="gutter-row"
span={24 / itemsPerRow}
key={item._id}
>
<ItemBox {...item} />
</Col>
))}
</React.Fragment>
))}
</Row>
</div> </div>
<div className="pagination">
<button onClick={handlePrevPage} disabled={currentPage === 1}>
Previous
</button>
<span>Page {currentPage}</span>
<button
onClick={handleNextPage}
disabled={endIndex >= chunkedItems.length}
>
Next
</button>
</div>
</div>
); );
}; };