From ea690d14c60c2fc1677dbfad9e24711359a823c9 Mon Sep 17 00:00:00 2001 From: Steve White Date: Tue, 15 Oct 2024 16:27:11 -0500 Subject: [PATCH] added type-down search --- src/components/ItemDetails.js | 29 +++++++++++++----- src/components/Items.js | 55 +++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/components/ItemDetails.js b/src/components/ItemDetails.js index 8cd9f6b..98bf967 100644 --- a/src/components/ItemDetails.js +++ b/src/components/ItemDetails.js @@ -1,6 +1,6 @@ // src/components/ItemDetails.js import React, { useState, useEffect, useRef, useCallback } from 'react'; -import { TextField, Button, Container, Avatar, Typography } from '@mui/material'; +import { TextField, Button, Container, Avatar } from '@mui/material'; import axios from 'axios'; import { PRIMARY_COLOR, SECONDARY_COLOR } from '../App'; //import { useNavigate } from 'react-router-dom'; // Import useNavigate @@ -13,9 +13,14 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { const fileInputRef = useRef(null); // Add this line to define fileInputRef const [imageOverlayVisible, setImageOverlayVisible] = useState(false); // const navigate = useNavigate(); // Initialize useNavigate + // eslint says boxName is defined but never used, but when I remove it it fails to compile + // because boxName is undefined + // eslint-disable-next-line const [boxName, setBoxName] = useState(''); const [boxes, setBoxes] = useState([]); - const [selectedBoxId, setSelectedBoxId] = useState(boxId); + const [selectedBoxId, setSelectedBoxId] = useState(item.box_id); + + //console.log("item.box_id: " + item.box_id); useEffect(() => { const fetchBoxes = async () => { @@ -35,7 +40,7 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { const handleBoxChange = (event) => { const newBoxId = event.target.value; setSelectedBoxId(newBoxId); // Update only this state - console.log('Selected box ID:', newBoxId); + //console.log('Selected box ID:', newBoxId); }; useEffect(() => { @@ -56,10 +61,14 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { } }; - if (selectedBoxId) { + if (selectedBoxId !== item.box_id) { getBoxDetails(selectedBoxId); // Fetch when selected box changes + //console.log("selectedBoxId:", selectedBoxId); + } else if (item.box_id) { + getBoxDetails(item.box_id); // Fetch when boxId exists and selectedBoxId is empty + //console.log("item.box_id:", item.box_id); } - }, [selectedBoxId, token]); // Removed `boxId` from dependencies + }, [selectedBoxId, token, item.box_id]); // Removed `boxId` from dependencies useEffect(() => { // Function to fetch image similar to getImageSrc in Items.js @@ -120,7 +129,7 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { } }); // Handle successful upload (e.g., show a success message) - console.log('Image uploaded successfully!', response.data.imagePath); + //console.log('Image uploaded successfully!', response.data.imagePath); return response.data.imagePath; // Indicate successful upload } catch (error) { // Handle upload error (e.g., show an error message) @@ -128,8 +137,10 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { } }, [item.ID, token]); + // eslint-disable-next-line const updateItemBoxId = async () => { try { + // eslint-disable-next-line const response = await axios.put(`${process.env.REACT_APP_API_URL}/items/${item.id}`, { box_id: selectedBoxId, }, { @@ -146,9 +157,10 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { let imagePath; // 1. Handle image upload first if a new image is selected if (fileInputRef.current.files[0]) { + // eslint-disable-next-line imagePath = await handleImageUpload(); } - console.log("Selected box ID:", selectedBoxId) + //console.log("Selected box ID:", selectedBoxId) // 2. Update item details (name, description, etc.) try { @@ -233,7 +245,8 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { {boxes.map((box) => ( // eslint-disable-next-line - console.log('Box at the selection point:', box.ID), + //console.log('Box at the selection point:', box.ID), + //console.log("Box name:", box.name), diff --git a/src/components/Items.js b/src/components/Items.js index ff0a0e8..20ba5bd 100644 --- a/src/components/Items.js +++ b/src/components/Items.js @@ -37,7 +37,7 @@ export default function Items({ token }) { const { id } = useParams(); const boxID = id; const url = boxId === undefined ? `${process.env.REACT_APP_API_URL}/items` : `${process.env.REACT_APP_API_URL}/boxes/${boxId}/items`; - + const [searchQuery, setSearchQuery] = useState(''); const debugLog = (message) => { if (process.env.DEBUG_API) { @@ -63,9 +63,35 @@ export default function Items({ token }) { } }; - const handleImageUpload = async (itemId, imageFile) => { + /** + * This function takes an image name and returns a unique image name. + * If the image name is 'image.jpg', a random string is generated and appended to the image name. + * This is used to prevent overwriting of images with the same name. + * @param {string} imageName - The name of the image + * @return {string} - The unique image name + */ + const generateUniqueImageName = (imageName) => { + if (imageName.toLowerCase() === 'image.jpg') { + const randomString = Math.random().toString(36).substr(2, 9); + return `image_${randomString}.jpg`; + } + return imageName; + }; + + + const handleImageUpload = async (itemId, imageFile, newImageName) => { const formData = new FormData(); - formData.append('image', imageFile); + //const imageFile = fileInputRef.current.files[0]; + //const newImageName = generateUniqueImageName(imageFile.name); + formData.append('image', new File([imageFile], newImageName, { + type: imageFile.type, + })); + + // Create a new file with the unique name + // eslint-disable-next-line + const newImageFile = new File([imageFile], newImageName, { + type: imageFile.type, + }); try { const response = await axios.post(`${process.env.REACT_APP_API_URL}/items/${itemId}/upload`, formData, { @@ -81,6 +107,7 @@ export default function Items({ token }) { return null; // Indicate upload failure } }; + const handleSaveNewItem = async () => { try { // 1. Create the item first @@ -98,7 +125,9 @@ export default function Items({ token }) { // 2. If item creation is successful, upload the image if (newItemResponse.status === 200 && fileInputRef.current.files[0]) { const newItemId = newItemResponse.data.id; - const uploadedImagePath = await handleImageUpload(newItemId, fileInputRef.current.files[0]); + const imageFile = fileInputRef.current.files[0]; + const newImageName = generateUniqueImageName(imageFile.name); + const uploadedImagePath = await handleImageUpload(newItemId, fileInputRef.current.files[0], newImageName); if (uploadedImagePath) { // console.log("Image path to save:", uploadedImagePath); @@ -249,6 +278,14 @@ export default function Items({ token }) { return ( + setSearchQuery(e.target.value)} + />

Items in Box: {boxName === "Unknown Box" ? "All Boxes" : `${boxName} (${items.length} items)`}

@@ -307,13 +345,18 @@ export default function Items({ token }) { /> ) : ( - {items.map((item) => ( + {items + .filter(item => + item.name.toLowerCase().includes(searchQuery.toLowerCase()) || + item.description.toLowerCase().includes(searchQuery.toLowerCase()) + ) + .map((item) => ( handleEditItem(item)}> - handleDeleteItem(item.ID)}> + handleDeleteItem(item.ID)}>