From c5640b54fd814118dae784f6768aeb866bfdfd77 Mon Sep 17 00:00:00 2001 From: Steve White Date: Fri, 11 Oct 2024 17:10:06 -0500 Subject: [PATCH] Image zoom works, save image works in both places. --- src/components/ItemDetails.js | 22 ++-- src/components/Items.js | 198 ++++++++++++++++++++++++---------- 2 files changed, 156 insertions(+), 64 deletions(-) diff --git a/src/components/ItemDetails.js b/src/components/ItemDetails.js index d57cbb6..8d23daa 100644 --- a/src/components/ItemDetails.js +++ b/src/components/ItemDetails.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { TextField, Button, Container, Avatar } from '@mui/material'; import axios from 'axios'; -import { useNavigate } from 'react-router-dom'; // Import useNavigate +//import { useNavigate } from 'react-router-dom'; // Import useNavigate export default function ItemDetails({ item, token, onSave, onClose, boxId }) { const [name, setName] = useState(item.name); @@ -11,7 +11,7 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { const [imageSrc, setImageSrc] = useState('/images/default.jpg'); // Initial default image const fileInputRef = useRef(null); // Add this line to define fileInputRef const [imageOverlayVisible, setImageOverlayVisible] = useState(false); - const navigate = useNavigate(); // Initialize useNavigate + // const navigate = useNavigate(); // Initialize useNavigate useEffect(() => { // Function to fetch image similar to getImageSrc in Items.js @@ -55,24 +55,25 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { getImageSrc(item.ID).then(dataUrl => setImageSrc(dataUrl)); }, [item.ID, token]); - const handleCloseItemDetails = () => { - onClose(); // Call the onClose prop to close the modal - navigate(`/boxes/${boxId}/items`); // Navigate back to the items list - }; + // const handleCloseItemDetails = () => { + // onClose(); // Call the onClose prop to close the modal + // navigate(`/boxes/${boxId}/items`); // Navigate back to the items list + // }; const handleImageUpload = async () => { const formData = new FormData(); formData.append('image', fileInputRef.current.files[0]); try { - await axios.post(`${process.env.REACT_APP_API_URL}/items/${item.ID}/upload`, formData, { + const response = await axios.post(`${process.env.REACT_APP_API_URL}/items/${item.ID}/upload`, formData, { headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'multipart/form-data' } }); // Handle successful upload (e.g., show a success message) - console.log('Image uploaded successfully!'); + 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) console.error('Image upload failed:', error); @@ -80,15 +81,16 @@ export default function ItemDetails({ item, token, onSave, onClose, boxId }) { }; const handleSave = async () => { + let imagePath; // 1. Handle image upload first if a new image is selected if (fileInputRef.current.files[0]) { - await handleImageUpload(); + imagePath = await handleImageUpload(); } // 2. Update item details (name, description, etc.) try { await axios.put(`${process.env.REACT_APP_API_URL}/items/${item.ID}`, - { name, description, image_path: imagePath }, // You might remove image_path here + { name, description, image_path: imagePath }, // Use teh uploaded image path { headers: { Authorization: `Bearer ${token}` } } diff --git a/src/components/Items.js b/src/components/Items.js index 71a03e8..4bbf31b 100644 --- a/src/components/Items.js +++ b/src/components/Items.js @@ -10,6 +10,10 @@ import { Typography, Avatar, ListItemAvatar, + Dialog, + DialogTitle, + DialogContent, + DialogActions, } from '@mui/material'; import { Delete as DeleteIcon, Edit as EditIcon } from '@mui/icons-material'; import axios from 'axios'; @@ -22,19 +26,94 @@ export default function Items({ token }) { const [items, setItems] = useState([]); const [newItemName, setNewItemName] = useState(''); const [newItemDescription, setNewItemDescription] = useState(''); - const [newItemImagePath, setNewItemImagePath] = useState('/images/default.jpg'); + // const [newItemImagePath, setNewItemImagePath] = useState('/images/default.jpg'); const [editingItem, setEditingItem] = useState(null); const location = useLocation(); const boxName = location.state?.boxName || 'Unknown Box'; const [itemImages, setItemImages] = useState({}); const fileInputRef = useRef(null); + const [openAddItemDialog, setOpenAddItemDialog] = useState(false); // For Add Item dialog // const handleSelectItem = (item) => { // setSelectedItem(item); // }; + const handleAddItem = () => { + setOpenAddItemDialog(true); + }; - const [selectedItem, setSelectedItem] = React.useState(null); + const handleCloseAddItemDialog = () => { + setOpenAddItemDialog(false); + setNewItemName(''); + setNewItemDescription(''); + // setNewItemImagePath(''); + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }; + + const handleImageUpload = async (itemId, imageFile) => { + const formData = new FormData(); + formData.append('image', imageFile); + + try { + const response = await axios.post(`${process.env.REACT_APP_API_URL}/items/${itemId}/upload`, formData, { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'multipart/form-data' + } + }); + console.log('Image uploaded successfully!'); + return response.data.imagePath; // Indicate successful upload + } catch (error) { + console.error('Image upload failed:', error); + return null; // Indicate upload failure + } + }; + const handleSaveNewItem = async () => { + try { + // 1. Create the item first + const newItemResponse = await axios.post(`${process.env.REACT_APP_API_URL}/items`, { + name: newItemName, + description: newItemDescription, + box_id: parseInt(boxId, 10) + }, { + headers: { + Authorization: `Bearer ${token}` + } + }); + console.log('New item created:', newItemResponse.status); + + // 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]); + + if (uploadedImagePath) { + console.log("Image path to save:", uploadedImagePath); + + // You might want to update your item in the backend with the image path + // For example: + // await axios.put(...); + + } else { + // Handle image upload failure + console.error('Failed to upload image for the new item.'); + } + } + + handleCloseAddItemDialog(); + fetchItems(); + } catch (error) { + console.error('Error adding item:', error); + } + }; + + + + + + //const [selectedItem, setSelectedItem] = React.useState(null); const handleCloseItemDetails = () => { setEditingItem(null); // Close the ItemDetails modal @@ -112,32 +191,32 @@ export default function Items({ token }) { fetchItems(); }, [boxId, token, fetchItems]); - const handleAddItem = () => { - const formData = new FormData(); - formData.append('name', newItemName); - formData.append('description', newItemDescription); - formData.append('box_id', parseInt(boxId, 10)); - // Append image only if a new one is selected - if (fileInputRef.current.files[0]) { - formData.append('image', fileInputRef.current.files[0]); - } + // const handleAddItem = () => { + // const formData = new FormData(); + // formData.append('name', newItemName); + // formData.append('description', newItemDescription); + // formData.append('box_id', parseInt(boxId, 10)); + // // Append image only if a new one is selected + // if (fileInputRef.current.files[0]) { + // formData.append('image', fileInputRef.current.files[0]); + // } - axios.post(`${process.env.REACT_APP_API_URL}/items`, formData, { - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'multipart/form-data' // Important for file uploads - } - }).then(() => { - setNewItemName(''); - setNewItemDescription(''); - setNewItemImagePath(''); - // Clear the file input - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - fetchItems(); - }); - }; + // axios.post(`${process.env.REACT_APP_API_URL}/items`, formData, { + // headers: { + // Authorization: `Bearer ${token}`, + // 'Content-Type': 'multipart/form-data' // Important for file uploads + // } + // }).then(() => { + // setNewItemName(''); + // setNewItemDescription(''); + // setNewItemImagePath(''); + // // Clear the file input + // if (fileInputRef.current) { + // fileInputRef.current.value = ''; + // } + // fetchItems(); + // }); + // }; const handleDeleteItem = (itemId) => { axios.delete(`${process.env.REACT_APP_API_URL}/items/${itemId}`, { @@ -160,30 +239,6 @@ export default function Items({ token }) {

Items in Box: {boxName}

- setNewItemName(e.target.value)} - /> - setNewItemDescription(e.target.value)} - /> - setNewItemImagePath(e.target.files[0].name)} - /> - + {/* Dialog for adding new item */} + + Add New Item + + setNewItemName(e.target.value)} + /> + setNewItemDescription(e.target.value)} + /> + + + + + + + {editingItem ? (