added delete function to product table
This commit is contained in:
@@ -35,6 +35,7 @@ CREATE TABLE IF NOT EXISTS products (
|
|||||||
picture VARCHAR(500) DEFAULT NULL,
|
picture VARCHAR(500) DEFAULT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
deleted BOOLEAN DEFAULT FALSE NOT NULL,
|
||||||
FOREIGN KEY (storage_location) REFERENCES storage_locations(uuid) ON DELETE CASCADE
|
FOREIGN KEY (storage_location) REFERENCES storage_locations(uuid) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export const allProducts = async () => {
|
|||||||
p.updated_at
|
p.updated_at
|
||||||
FROM products p
|
FROM products p
|
||||||
JOIN storage_locations s ON p.storage_location = s.uuid
|
JOIN storage_locations s ON p.storage_location = s.uuid
|
||||||
|
WHERE p.deleted = 0
|
||||||
`);
|
`);
|
||||||
|
|
||||||
if (result.length > 0) {
|
if (result.length > 0) {
|
||||||
@@ -137,3 +138,16 @@ export const updateItem = async (itemUUID, newValues) => {
|
|||||||
return { code: "ep005" }; // error
|
return { code: "ep005" }; // error
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteProduct = async (uuid) => {
|
||||||
|
const [result] = await pool.query(
|
||||||
|
`UPDATE products SET deleted = 1 WHERE uuid = UUID_TO_BIN(?);`,
|
||||||
|
[uuid],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.affectedRows > 0) {
|
||||||
|
return { code: "sp006" }; // success
|
||||||
|
} else {
|
||||||
|
return { code: "ep006" }; // error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import dotenv from "dotenv";
|
|||||||
import { authenticate } from "../../services/tokenService.js";
|
import { authenticate } from "../../services/tokenService.js";
|
||||||
import {
|
import {
|
||||||
allProducts,
|
allProducts,
|
||||||
|
deleteProduct,
|
||||||
newProduct,
|
newProduct,
|
||||||
productDetails,
|
productDetails,
|
||||||
setAmount,
|
setAmount,
|
||||||
@@ -147,4 +148,33 @@ router.post("/mutate/update-item", authenticate, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("/delete-selection", authenticate, async (req, res) => {
|
||||||
|
let isError = false;
|
||||||
|
const uuidArray = req.body;
|
||||||
|
|
||||||
|
for (const uuid of uuidArray) {
|
||||||
|
const response = await deleteProduct(uuid);
|
||||||
|
if (response.code === "ep006" || !response) {
|
||||||
|
isError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError === false) {
|
||||||
|
res.status(202).json({
|
||||||
|
success: true,
|
||||||
|
code: "sp006",
|
||||||
|
data: null,
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
code: "ep006",
|
||||||
|
data: null,
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import FilterListIcon from "@mui/icons-material/FilterList";
|
|||||||
import KeyboardArrowLeftIcon from "@mui/icons-material/KeyboardArrowLeft";
|
import KeyboardArrowLeftIcon from "@mui/icons-material/KeyboardArrowLeft";
|
||||||
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
||||||
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { getProducts } from "../utils/uxFncs";
|
import { getProducts, deleteSelectedProducts } from "../utils/uxFncs";
|
||||||
import { visuallyHidden } from "@mui/utils";
|
import { visuallyHidden } from "@mui/utils";
|
||||||
import { formatDate } from "../utils/uxFncs";
|
import { formatDate } from "../utils/uxFncs";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
@@ -182,8 +182,22 @@ const EnhancedTableHead = (props: EnhancedTableHeadProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const EnhancedTableToolbar = ({ numSelected }: { numSelected: number }) => {
|
const EnhancedTableToolbar = ({
|
||||||
|
numSelected,
|
||||||
|
selected,
|
||||||
|
}: {
|
||||||
|
numSelected: number;
|
||||||
|
selected: readonly string[];
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const { mutate } = useMutation({
|
||||||
|
mutationFn: (values: string[]) => deleteSelectedProducts(values),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["products"] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -205,16 +219,26 @@ const EnhancedTableToolbar = ({ numSelected }: { numSelected: number }) => {
|
|||||||
>
|
>
|
||||||
{numSelected > 0 ? (
|
{numSelected > 0 ? (
|
||||||
<Typography sx={{ flex: "1 1 100%" }} component="div">
|
<Typography sx={{ flex: "1 1 100%" }} component="div">
|
||||||
{numSelected} ausgewahlt
|
{numSelected} {t("selected")}
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<Typography level="body-lg" sx={{ flex: "1 1 100%" }} component="div">
|
<Typography
|
||||||
|
level="body-lg"
|
||||||
|
fontWeight={"bold"}
|
||||||
|
sx={{ flex: "1 1 100%" }}
|
||||||
|
component="div"
|
||||||
|
>
|
||||||
{t("inventory")}
|
{t("inventory")}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{numSelected > 0 ? (
|
{numSelected > 0 ? (
|
||||||
<Tooltip title="Delete">
|
<Tooltip title="Delete">
|
||||||
<IconButton size="sm" color="danger" variant="solid">
|
<IconButton
|
||||||
|
onClick={() => mutate([...selected])}
|
||||||
|
size="sm"
|
||||||
|
color="danger"
|
||||||
|
variant="solid"
|
||||||
|
>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -346,7 +370,10 @@ export const InventoryPage = () => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
className="mt-6 overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm"
|
className="mt-6 overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm"
|
||||||
>
|
>
|
||||||
<EnhancedTableToolbar numSelected={selected.length} />
|
<EnhancedTableToolbar
|
||||||
|
numSelected={selected.length}
|
||||||
|
selected={selected}
|
||||||
|
/>
|
||||||
<Table
|
<Table
|
||||||
aria-labelledby="tableTitle"
|
aria-labelledby="tableTitle"
|
||||||
hoverRow
|
hoverRow
|
||||||
|
|||||||
@@ -38,5 +38,6 @@
|
|||||||
"quick-tips-1": "Update the app name to personalize the sidebar and login header.",
|
"quick-tips-1": "Update the app name to personalize the sidebar and login header.",
|
||||||
"quick-tips-2": "Choose a currency code that matches your pricing display, e.g. EUR, CHF, or USD.",
|
"quick-tips-2": "Choose a currency code that matches your pricing display, e.g. EUR, CHF, or USD.",
|
||||||
"settings-sub": "Manage your app preferences and store defaults.",
|
"settings-sub": "Manage your app preferences and store defaults.",
|
||||||
"preferences": "Preferences"
|
"preferences": "Preferences",
|
||||||
|
"selected": "selected"
|
||||||
}
|
}
|
||||||
@@ -273,3 +273,19 @@ export const fetchSettings = async () => {
|
|||||||
return { success: true, data: response.data, code: response.code };
|
return { success: true, data: response.data, code: response.code };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteSelectedProducts = async (uuids: string[]) => {
|
||||||
|
const result = await fetch(`${API_BASE}/products/delete-selection`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(uuids),
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await result.json();
|
||||||
|
|
||||||
|
console.log(response);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user