added default.jpg and fixed image display code
This commit is contained in:
parent
88ad1e7e1b
commit
3a54c5da58
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
|
@ -1,12 +1,55 @@
|
||||||
// src/components/ItemDetails.js
|
// src/components/ItemDetails.js
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { TextField, Button, Container } from '@mui/material';
|
import { TextField, Button, Container, Avatar } from '@mui/material';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export default function ItemDetails({ item, token, onSave }) {
|
export default function ItemDetails({ item, token, onSave }) {
|
||||||
const [name, setName] = useState(item.name);
|
const [name, setName] = useState(item.name);
|
||||||
const [description, setDescription] = useState(item.description);
|
const [description, setDescription] = useState(item.description);
|
||||||
const [imagePath, setImagePath] = useState(item.image_path || '');
|
const [imagePath, setImagePath] = useState(item.image_path || '');
|
||||||
|
const [imageSrc, setImageSrc] = useState('/images/default.jpg'); // Initial default image
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Function to fetch image similar to getImageSrc in Items.js
|
||||||
|
const getImageSrc = (itemId) => {
|
||||||
|
return axios.get(`${process.env.REACT_APP_API_URL}/items/${itemId}/image`, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsDataURL(response.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error('Image fetch failed');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Return the data URL of the default image if image fetch fails
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = '/default.jpg';
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
const dataURL = canvas.toDataURL();
|
||||||
|
resolve(dataURL);
|
||||||
|
};
|
||||||
|
img.onerror = reject;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the image when the component mounts or the item changes
|
||||||
|
getImageSrc(item.ID).then(dataUrl => setImageSrc(dataUrl));
|
||||||
|
}, [item.ID, token]);
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
axios.put(`${process.env.REACT_APP_API_URL}/items/${item.ID}`,
|
axios.put(`${process.env.REACT_APP_API_URL}/items/${item.ID}`,
|
||||||
|
@ -19,9 +62,22 @@ export default function ItemDetails({ item, token, onSave }) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImageError = (e) => {
|
||||||
|
e.target.src = '/images/default.jpg'; // Fallback to default image on error
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<h3>Edit Item: {item.name}</h3>
|
<h3>Edit Item: {item.name}</h3>
|
||||||
|
|
||||||
|
{/* Display the item image as an avatar */}
|
||||||
|
<Avatar
|
||||||
|
src={imageSrc}
|
||||||
|
alt={name}
|
||||||
|
onError={handleImageError}
|
||||||
|
sx={{ width: 100, height: 100, marginBottom: '16px' }} // Style the Avatar
|
||||||
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
label="Item Name"
|
label="Item Name"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|
|
@ -8,13 +8,13 @@ import {
|
||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
Typography,
|
||||||
Avatar, // Import Avatar for image display
|
Avatar,
|
||||||
ListItemAvatar // Import ListItemAvatar
|
ListItemAvatar
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Delete as DeleteIcon, Edit as EditIcon } from '@mui/icons-material';
|
import { Delete as DeleteIcon, Edit as EditIcon } from '@mui/icons-material';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useParams, useLocation } from 'react-router-dom';
|
import { useParams, useLocation } from 'react-router-dom';
|
||||||
import ItemDetails from './ItemDetails'; // Import the new ItemDetails component
|
import ItemDetails from './ItemDetails';
|
||||||
|
|
||||||
export default function Items({ token }) {
|
export default function Items({ token }) {
|
||||||
const { id: boxId } = useParams();
|
const { id: boxId } = useParams();
|
||||||
|
@ -22,16 +22,76 @@ export default function Items({ token }) {
|
||||||
const [newItemName, setNewItemName] = useState('');
|
const [newItemName, setNewItemName] = useState('');
|
||||||
const [newItemDescription, setNewItemDescription] = useState('');
|
const [newItemDescription, setNewItemDescription] = useState('');
|
||||||
const [newItemImagePath, setNewItemImagePath] = useState('/images/default.jpg');
|
const [newItemImagePath, setNewItemImagePath] = useState('/images/default.jpg');
|
||||||
const [editingItem, setEditingItem] = useState(null); // Track which item is being edited
|
const [editingItem, setEditingItem] = useState(null);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const boxName = location.state?.boxName || 'Unknown Box';
|
const boxName = location.state?.boxName || 'Unknown Box';
|
||||||
|
const [itemImages, setItemImages] = useState({});
|
||||||
|
|
||||||
|
const handleImageError = (e) => {
|
||||||
|
if (e.target.src.startsWith('data:image/')) {
|
||||||
|
console.error("Default image failed to load. Check the file path.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
e.target.onerror = null;
|
||||||
|
e.target.src = reader.result;
|
||||||
|
};
|
||||||
|
fetch('/default.jpg')
|
||||||
|
.then(res => res.blob())
|
||||||
|
.then(blob => reader.readAsDataURL(blob))
|
||||||
|
.catch(error => console.error("Error loading default image:", error));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getImageSrc = (itemId) => {
|
||||||
|
return axios.get(`${process.env.REACT_APP_API_URL}/items/${itemId}/image`, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsDataURL(response.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error('Image fetch failed');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = '/default.jpg';
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
resolve(canvas.toDataURL());
|
||||||
|
};
|
||||||
|
img.onerror = reject;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const fetchItems = useCallback(() => {
|
const fetchItems = useCallback(() => {
|
||||||
axios.get(`${process.env.REACT_APP_API_URL}/boxes/${boxId}/items`, {
|
axios.get(`${process.env.REACT_APP_API_URL}/boxes/${boxId}/items`, {
|
||||||
headers: { Authorization: `Bearer ${token}` }
|
headers: { Authorization: `Bearer ${token}` }
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
setItems(response.data);
|
setItems(response.data);
|
||||||
|
|
||||||
|
// Fetch images for each item
|
||||||
|
response.data.forEach(item => {
|
||||||
|
getImageSrc(item.ID).then(imageDataUrl => {
|
||||||
|
setItemImages(prevItemImages => ({
|
||||||
|
...prevItemImages,
|
||||||
|
[item.ID]: imageDataUrl
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, [boxId, token]);
|
}, [boxId, token]);
|
||||||
|
|
||||||
|
@ -66,19 +126,18 @@ export default function Items({ token }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditItem = (item) => {
|
const handleEditItem = (item) => {
|
||||||
setEditingItem(item); // Set the item to be edited
|
setEditingItem(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveEdit = () => {
|
const handleSaveEdit = () => {
|
||||||
setEditingItem(null); // Clear the editing state after saving
|
setEditingItem(null);
|
||||||
fetchItems(); // Refresh the list after edit
|
fetchItems();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<h2>Items in Box: {boxName}</h2>
|
<h2>Items in Box: {boxName}</h2>
|
||||||
|
|
||||||
{/* Add Item Form */}
|
|
||||||
<TextField
|
<TextField
|
||||||
label="Item Name"
|
label="Item Name"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -107,7 +166,6 @@ export default function Items({ token }) {
|
||||||
Add Item
|
Add Item
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{/* Conditionally render the ItemDetails component if editingItem is not null */}
|
|
||||||
{editingItem ? (
|
{editingItem ? (
|
||||||
<ItemDetails item={editingItem} token={token} onSave={handleSaveEdit} />
|
<ItemDetails item={editingItem} token={token} onSave={handleSaveEdit} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -125,9 +183,9 @@ export default function Items({ token }) {
|
||||||
}>
|
}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Avatar
|
<Avatar
|
||||||
src= {axios.get(`${process.env.REACT_APP_API_URL}/items/${+item.ID}/image`, {
|
src={itemImages[item.ID]}
|
||||||
headers: { Authorization: `Bearer ${token}` }})}
|
|
||||||
alt={item.name}
|
alt={item.name}
|
||||||
|
onError={handleImageError}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
|
|
Loading…
Reference in New Issue