Updated to have item details and image zoom
This commit is contained in:
parent
0fbc5721b9
commit
b3a966e834
2
.env
2
.env
|
@ -1 +1 @@
|
||||||
REACT_APP_API_URL=http://10.0.0.66:8080
|
REACT_APP_API_URL=http://10.0.0.16:8080
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Login from './components/Login';
|
||||||
import Boxes from './components/Boxes';
|
import Boxes from './components/Boxes';
|
||||||
import Items from './components/Items';
|
import Items from './components/Items';
|
||||||
import Navbar from './components/Navbar'; // Correct import here
|
import Navbar from './components/Navbar'; // Correct import here
|
||||||
|
import './styles.css'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [token, setToken] = useState(null);
|
const [token, setToken] = useState(null);
|
||||||
|
|
|
@ -2,13 +2,16 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { TextField, Button, Container, Avatar } from '@mui/material';
|
import { TextField, Button, Container, Avatar } from '@mui/material';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { useNavigate } from 'react-router-dom'; // Import useNavigate
|
||||||
|
|
||||||
export default function ItemDetails({ item, token, onSave }) {
|
export default function ItemDetails({ item, token, onSave, onClose, boxId }) {
|
||||||
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
|
const [imageSrc, setImageSrc] = useState('/images/default.jpg'); // Initial default image
|
||||||
const fileInputRef = useRef(null); // Add this line to define fileInputRef
|
const fileInputRef = useRef(null); // Add this line to define fileInputRef
|
||||||
|
const [imageOverlayVisible, setImageOverlayVisible] = useState(false);
|
||||||
|
const navigate = useNavigate(); // Initialize useNavigate
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Function to fetch image similar to getImageSrc in Items.js
|
// Function to fetch image similar to getImageSrc in Items.js
|
||||||
|
@ -52,6 +55,11 @@ export default function ItemDetails({ item, token, onSave }) {
|
||||||
getImageSrc(item.ID).then(dataUrl => setImageSrc(dataUrl));
|
getImageSrc(item.ID).then(dataUrl => setImageSrc(dataUrl));
|
||||||
}, [item.ID, token]);
|
}, [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 handleImageUpload = async () => {
|
const handleImageUpload = async () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('image', fileInputRef.current.files[0]);
|
formData.append('image', fileInputRef.current.files[0]);
|
||||||
|
@ -96,6 +104,14 @@ export default function ItemDetails({ item, token, onSave }) {
|
||||||
e.target.src = '/images/default.jpg'; // Fallback to default image on error
|
e.target.src = '/images/default.jpg'; // Fallback to default image on error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAvatarClick = () => {
|
||||||
|
setImageOverlayVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseOverlay = () => {
|
||||||
|
setImageOverlayVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<h3>Edit Item: {item.name}</h3>
|
<h3>Edit Item: {item.name}</h3>
|
||||||
|
@ -106,8 +122,16 @@ export default function ItemDetails({ item, token, onSave }) {
|
||||||
alt={name}
|
alt={name}
|
||||||
onError={handleImageError}
|
onError={handleImageError}
|
||||||
sx={{ width: 100, height: 100, marginBottom: '16px' }} // Style the Avatar
|
sx={{ width: 100, height: 100, marginBottom: '16px' }} // Style the Avatar
|
||||||
|
onClick={handleAvatarClick}
|
||||||
/>
|
/>
|
||||||
|
{imageOverlayVisible && (
|
||||||
|
<div className="image-overlay">
|
||||||
|
<img src={imageSrc} alt={name} />
|
||||||
|
<button className="close-button" onClick={handleCloseOverlay}>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<TextField
|
<TextField
|
||||||
label="Item Name"
|
label="Item Name"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -156,6 +180,7 @@ export default function ItemDetails({ item, token, onSave }) {
|
||||||
<Button variant="contained" color="primary" onClick={handleSave}>
|
<Button variant="contained" color="primary" onClick={handleSave}>
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={onClose}>Close</Button>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -9,13 +9,14 @@ import {
|
||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
Typography,
|
||||||
Avatar,
|
Avatar,
|
||||||
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 ItemDetails from './ItemDetails';
|
||||||
|
|
||||||
|
|
||||||
export default function Items({ token }) {
|
export default function Items({ token }) {
|
||||||
const { id: boxId } = useParams();
|
const { id: boxId } = useParams();
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
|
@ -28,6 +29,17 @@ export default function Items({ token }) {
|
||||||
const [itemImages, setItemImages] = useState({});
|
const [itemImages, setItemImages] = useState({});
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
|
|
||||||
|
// const handleSelectItem = (item) => {
|
||||||
|
// setSelectedItem(item);
|
||||||
|
// };
|
||||||
|
|
||||||
|
const [selectedItem, setSelectedItem] = React.useState(null);
|
||||||
|
|
||||||
|
const handleCloseItemDetails = () => {
|
||||||
|
setEditingItem(null); // Close the ItemDetails modal
|
||||||
|
};
|
||||||
|
|
||||||
const handleImageError = (e) => {
|
const handleImageError = (e) => {
|
||||||
if (e.target.src.startsWith('data:image/')) {
|
if (e.target.src.startsWith('data:image/')) {
|
||||||
console.error("Default image failed to load. Check the file path.");
|
console.error("Default image failed to load. Check the file path.");
|
||||||
|
@ -188,7 +200,13 @@ export default function Items({ token }) {
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{editingItem ? (
|
{editingItem ? (
|
||||||
<ItemDetails item={editingItem} token={token} onSave={handleSaveEdit} />
|
<ItemDetails
|
||||||
|
item={editingItem}
|
||||||
|
token={token}
|
||||||
|
onSave={handleSaveEdit}
|
||||||
|
onClose={handleCloseItemDetails}
|
||||||
|
boxId={boxId}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<List>
|
<List>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* styles.css */
|
||||||
|
|
||||||
|
.image-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 9999; /* Set a high z-index value to ensure it appears on top of other elements */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-overlay img {
|
||||||
|
max-width: 80%;
|
||||||
|
max-height: 80%;
|
||||||
|
position: absolute; /* Set the position to absolute */
|
||||||
|
top: 50%; /* Center the image vertically */
|
||||||
|
left: 50%; /* Center the image horizontally */
|
||||||
|
transform: translate(-50%, -50%); /* Center the image using transform */
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
Loading…
Reference in New Issue