Product detail modal

This commit is contained in:
Eden Kirin
2024-01-23 22:32:11 +01:00
parent 0a344ed1ce
commit ea7c54a5dc
10 changed files with 98 additions and 19 deletions

View File

@ -1,5 +1,4 @@
import axios from "axios";
import { API_URL } from "../const";
export class ApiBase {}
@ -12,7 +11,6 @@ const commonHeaders = {
};
export const axiosUnauthorizedInstance = axios.create({
baseURL: API_URL,
timeout: 5000,
headers: commonHeaders,
});
@ -25,7 +23,6 @@ axiosUnauthorizedInstance.interceptors.response.use(
);
export const axiosInstance = axios.create({
baseURL: API_URL,
timeout: 5000,
headers: {
...commonHeaders,

View File

@ -1 +1,2 @@
export { machinesApi } from "./machines";
export { productsApi } from "./products";

View File

@ -1,14 +1,17 @@
import { axiosInstance, ApiBase } from "./common";
import { MACHINES_API_URL } from "../const";
const baseUrl = `${MACHINES_API_URL}/machines`;
class MachinesApi extends ApiBase {
list = async () => {
return axiosInstance.get(`/machines`, {});
return axiosInstance.get(`${baseUrl}`, {});
};
get = async (machineId) => {
return axiosInstance.get(`/machines/${machineId}`, {});
return axiosInstance.get(`${baseUrl}/${machineId}`, {});
};
listProducts = async (machineId) => {
return axiosInstance.get(`/machines/${machineId}/products`, {});
return axiosInstance.get(`${baseUrl}/${machineId}/products`, {});
};
}

View File

@ -0,0 +1,12 @@
import { axiosInstance, ApiBase } from "./common";
import { PRODUCTS_API_URL } from "../const";
const baseUrl = `${PRODUCTS_API_URL}/products`;
class ProductsApi extends ApiBase {
get = async (productId) => {
return axiosInstance.get(`${baseUrl}/${productId}`, {});
};
}
export const productsApi = new ProductsApi();

View File

@ -6,20 +6,21 @@ import Typography from "@mui/material/Typography";
import { CardActionArea } from "@mui/material";
import { PRODUCT_IMAGE_DIR } from "../const";
function ProductCard({ product }) {
const productImg = `${PRODUCT_IMAGE_DIR}${product.image}`;
function ProductCard({ product, onClick }) {
const productImg = `${PRODUCT_IMAGE_DIR}/${product.image}`;
return (
<Card>
<CardActionArea>
<CardMedia component="img" height="140" image={productImg} alt={product.name} />
<Card sx={{ width: "100%" }}>
<CardActionArea
onClick={() => {
onClick(product.id);
}}
>
<CardMedia component="img" height="200" image={productImg} alt={product.name} />
<CardContent>
<Typography gutterBottom variant="h5" component="div">
<Typography gutterBottom variant="h5" component="div" sx={{ marginBottom: 0 }}>
{product.name}
</Typography>
<Typography variant="body2" color="text.secondary">
{product.description}
</Typography>
</CardContent>
</CardActionArea>
</Card>

View File

@ -0,0 +1,36 @@
import * as React from "react";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import CardMedia from "@mui/material/CardMedia";
import { PRODUCT_IMAGE_DIR } from "../const";
function ProductModal({ product, onClose }) {
const productImg = `${PRODUCT_IMAGE_DIR}/${product.image}`;
return (
<Dialog open={true} onClose={onClose}>
<DialogTitle>{product.name}</DialogTitle>
<DialogContent>
<CardMedia
component="img"
height="300"
image={productImg}
alt={product.name}
sx={{ marginBottom: "1rem" }}
/>
<DialogContentText>{product.description}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onClose} variant="contained" autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
);
}
export { ProductModal };

View File

@ -2,12 +2,32 @@ import * as React from "react";
import Grid from "@mui/material/Unstable_Grid2";
import Typography from "@mui/material/Typography";
import { ProductCard } from "./ProductCard";
import { ProductModal } from "./ProductModal";
import { productsApi } from "../api";
function Products({ machineName, products, onSelect }) {
const [productModal, setProductModal] = React.useState({ isOpen: false, product: null });
const onProductSelect = (productId) => {
productsApi.get(productId).then((response) => {
setProductModal({
isOpen: true,
product: response.data,
});
});
};
const onProductModalClose = () => {
setProductModal({
isOpen: false,
productId: null,
});
};
const productItems = products.map((product) => {
return (
<Grid md={6} key={product.id} sx={{ display: "flex" }}>
<ProductCard product={product} />
<ProductCard product={product} onClick={onProductSelect} />
</Grid>
);
});
@ -21,6 +41,8 @@ function Products({ machineName, products, onSelect }) {
<Grid container spacing={2}>
{productItems}
</Grid>
{productModal.isOpen && <ProductModal product={productModal.product} onClose={onProductModalClose} />}
</>
);
}

View File

@ -1,2 +1,3 @@
export const API_URL = process.env.REACT_APP_BACKEND_API_URL || "http://localhost:10000";
export const MACHINES_API_URL = process.env.REACT_APP_MACHINES_API_URL || "http://localhost:4000";
export const PRODUCTS_API_URL = process.env.REACT_APP_PRODUCTS_API_URL || "http://localhost:4001";
export const PRODUCT_IMAGE_DIR = "/static/products/";

View File

@ -18,9 +18,7 @@ function Home() {
}, []);
const onMachineSelect = (machineName, machineId) => {
console.log("selected:", machineName);
machinesApi.listProducts(machineId).then((response) => {
console.log(response.data.products);
setProductsData({
machineName,
products: response.data.products,