mirror of
https://github.com/lemeow125/Ivy-Frontend.git
synced 2024-11-17 06:39:25 +08:00
Added quantity editing to inventory
This commit is contained in:
parent
fa9931c948
commit
1bdf7356d8
5 changed files with 168 additions and 81 deletions
|
@ -35,15 +35,20 @@ export function GetProduct(id: number) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UpdateProduct(note: UpdateProductParams) {
|
export function UpdateProduct(product: UpdateProductParams) {
|
||||||
const token = JSON.parse(localStorage.getItem("token") || "{}");
|
const token = JSON.parse(localStorage.getItem("token") || "{}");
|
||||||
return axios
|
return axios
|
||||||
.patch("http://localhost:8000/api/v1/products/" + note.id + "/", note, {
|
.patch(
|
||||||
headers: {
|
"http://localhost:8000/api/v1/products/" + product.id + "/",
|
||||||
Authorization: "Token " + token,
|
product,
|
||||||
},
|
{
|
||||||
})
|
headers: {
|
||||||
|
Authorization: "Token " + token,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
console.log("Product update successful", response.data);
|
||||||
return response.data;
|
return response.data;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
35
src/Components/InventoryPage/RowRenderer/RowRenderer.tsx
Normal file
35
src/Components/InventoryPage/RowRenderer/RowRenderer.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { ProductList } from "../../../Interfaces/Interfaces";
|
||||||
|
import styles from "../../../styles";
|
||||||
|
import { TableBody, TableRow, TableCell } from "@mui/material";
|
||||||
|
import StockRenderer from "../StockRenderer/StockRenderer";
|
||||||
|
|
||||||
|
export default function RowRenderer(props: ProductList) {
|
||||||
|
if (props.Products.length === 0) {
|
||||||
|
return (
|
||||||
|
<div style={{ ...styles.content_column, ...{ alignItems: "center" } }}>
|
||||||
|
<p style={{ ...styles.text_white, ...styles.text_L }}>
|
||||||
|
No products yet. Add one!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableBody>
|
||||||
|
{props.Products.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||||
|
>
|
||||||
|
<TableCell style={{ ...styles.text_white, ...styles.text_S }}>
|
||||||
|
{row.id}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={{ ...styles.text_white, ...styles.text_S }}>
|
||||||
|
{row.name}
|
||||||
|
</TableCell>
|
||||||
|
{StockRenderer(row)}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,63 +1,73 @@
|
||||||
import { TableCell } from "@mui/material";
|
import { Button, TableCell } from "@mui/material";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import styles from "../../../styles";
|
import styles from "../../../styles";
|
||||||
import IsNumber from "../IsNumber/IsNumber";
|
import IsNumber from "../IsNumber/IsNumber";
|
||||||
|
import { UpdateProduct } from "../../Api/Api";
|
||||||
|
import { useQueryClient, useMutation } from "react-query";
|
||||||
|
import { Product } from "../../../Interfaces/Interfaces";
|
||||||
|
|
||||||
export default function StockRenderer(in_stock: number) {
|
export default function StockRenderer(product: Product) {
|
||||||
const [stock, setStock] = useState(in_stock);
|
const [stock, setStock] = useState(product.quantity);
|
||||||
if (stock >= 0 && stock <= 3) {
|
const [valueChanged, setValueChanged] = useState(false);
|
||||||
return (
|
const queryClient = useQueryClient();
|
||||||
<TableCell>
|
const mutation = useMutation({
|
||||||
<input
|
mutationFn: UpdateProduct,
|
||||||
style={{
|
onSuccess: () => {
|
||||||
...styles.text_red,
|
queryClient.invalidateQueries("products");
|
||||||
...{ border: "none", background: "none" },
|
},
|
||||||
...styles.text_S,
|
});
|
||||||
}}
|
|
||||||
value={stock}
|
function updateQuantity() {
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
mutation.mutate({
|
||||||
if (IsNumber(e.target.value)) {
|
id: product.id,
|
||||||
setStock(parseInt(e.target.value));
|
name: product.name,
|
||||||
}
|
quantity: stock,
|
||||||
}}
|
});
|
||||||
/>
|
setValueChanged(false);
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
} else if (stock >= 4 && stock < 9) {
|
|
||||||
return (
|
|
||||||
<TableCell>
|
|
||||||
<input
|
|
||||||
style={{
|
|
||||||
...styles.text_orange,
|
|
||||||
...{ border: "none", background: "none" },
|
|
||||||
...styles.text_S,
|
|
||||||
}}
|
|
||||||
value={stock}
|
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
if (IsNumber(e.target.value)) {
|
|
||||||
setStock(parseInt(e.target.value));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<TableCell>
|
|
||||||
<input
|
|
||||||
style={{
|
|
||||||
...styles.text_green,
|
|
||||||
...{ border: "none", background: "none" },
|
|
||||||
...styles.text_S,
|
|
||||||
}}
|
|
||||||
value={stock}
|
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
if (IsNumber(e.target.value)) {
|
|
||||||
setStock(parseInt(e.target.value));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
if (stock !== product.quantity) {
|
||||||
|
setValueChanged(true);
|
||||||
|
} else if (stock === product.quantity) {
|
||||||
|
setValueChanged(false);
|
||||||
|
}
|
||||||
|
}, [stock]);
|
||||||
|
let style;
|
||||||
|
if (stock >= 0 && stock <= 3) {
|
||||||
|
style = styles.text_red;
|
||||||
|
} else if (stock >= 4 && stock < 9) {
|
||||||
|
style = styles.text_orange;
|
||||||
|
} else {
|
||||||
|
style = styles.text_green;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableCell>
|
||||||
|
<div style={styles.content_row}>
|
||||||
|
<input
|
||||||
|
style={{
|
||||||
|
...style,
|
||||||
|
...{ border: "none", background: "none", width: 64 },
|
||||||
|
...styles.text_S,
|
||||||
|
}}
|
||||||
|
value={stock}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (IsNumber(e.target.value)) {
|
||||||
|
setStock(parseInt(e.target.value));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div style={{ paddingRight: 64 }} />
|
||||||
|
<Button
|
||||||
|
disabled={!valueChanged}
|
||||||
|
style={{ backgroundColor: "#80b38a" }}
|
||||||
|
onClick={() => {
|
||||||
|
updateQuantity();
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ export interface Product {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
date_added: string;
|
date_added: string;
|
||||||
|
quantity: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redux Interfaces
|
// Redux Interfaces
|
||||||
|
@ -63,5 +64,5 @@ export interface AddProductParams {
|
||||||
export interface UpdateProductParams {
|
export interface UpdateProductParams {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
quantity: string;
|
quantity: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,59 @@ import {
|
||||||
import { SampleInventoryData } from "../../Components/SampleData/SampleData";
|
import { SampleInventoryData } from "../../Components/SampleData/SampleData";
|
||||||
import StockRenderer from "../../Components/InventoryPage/StockRenderer/StockRenderer";
|
import StockRenderer from "../../Components/InventoryPage/StockRenderer/StockRenderer";
|
||||||
import LoginChecker from "../../Components/LoginChecker/LoginChecker";
|
import LoginChecker from "../../Components/LoginChecker/LoginChecker";
|
||||||
|
import { GetProducts, UpdateProduct } from "../../Components/Api/Api";
|
||||||
|
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||||
|
import RowRenderer from "../../Components/InventoryPage/RowRenderer/RowRenderer";
|
||||||
|
|
||||||
export default function Inventory() {
|
export default function Inventory() {
|
||||||
|
const {
|
||||||
|
data: products,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
} = useQuery("products", GetProducts, { retry: 0 });
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<LoginChecker />
|
||||||
|
<div style={styles.content_row}>
|
||||||
|
<div style={{ ...styles.content_row, ...{ flex: 1 } }}>
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||||||
|
<InventoryIcon size={64} color="white" />
|
||||||
|
<p style={{ ...styles.text_white, ...styles.text_XL }}>
|
||||||
|
Inventory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ ...styles.content_column, ...{ alignItems: "center" } }}>
|
||||||
|
<p style={{ ...styles.text_white, ...styles.text_L }}>
|
||||||
|
Loading inventory...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (error) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={styles.content_row}>
|
||||||
|
<div style={{ ...styles.content_row, ...{ flex: 1 } }}>
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||||||
|
<InventoryIcon size={64} color="white" />
|
||||||
|
<p style={{ ...styles.text_white, ...styles.text_XL }}>
|
||||||
|
Inventory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ ...styles.content_column, ...{ alignItems: "center" } }}>
|
||||||
|
<p style={{ ...styles.text_red, ...styles.text_L }}>
|
||||||
|
Error loading inventory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%" }}>
|
<div style={{ height: "100%" }}>
|
||||||
<LoginChecker />
|
<LoginChecker />
|
||||||
|
@ -41,22 +92,7 @@ export default function Inventory() {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<RowRenderer Products={products} />
|
||||||
{SampleInventoryData.map((row) => (
|
|
||||||
<TableRow
|
|
||||||
key={row.id}
|
|
||||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
|
||||||
>
|
|
||||||
<TableCell style={{ ...styles.text_white, ...styles.text_S }}>
|
|
||||||
{row.id}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell style={{ ...styles.text_white, ...styles.text_S }}>
|
|
||||||
{row.name}
|
|
||||||
</TableCell>
|
|
||||||
{StockRenderer(row.in_stock)}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue