bananas-commerce-admin
Version:
What's this, an admin for apes?
147 lines • 7.49 kB
JavaScript
import React, { useCallback, useMemo, useState } from "react";
import { useParams } from "react-router-dom";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import CardActions from "@mui/material/CardActions";
import Stack from "@mui/material/Stack";
import { useTheme } from "@mui/material/styles";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";
import { TableCell } from "../../../components/Table/TableCell";
import TableHead from "../../../components/Table/TableHead";
import TableHeading from "../../../components/Table/TableHeading";
import TableCardHeader from "../../../components/TableCardHeader";
import { useApi } from "../../../contexts/ApiContext";
import { useDialog } from "../../../contexts/DialogContext";
import { useI18n } from "../../../contexts/I18nContext";
import { useUser } from "../../../contexts/UserContext";
import { hasPermission } from "../../../util/has_permission";
import { PriceRow } from "./PriceRow";
export const PricesCard = ({ prices, setPrices }) => {
const theme = useTheme();
const openDialog = useDialog();
const api = useApi();
const params = useParams();
const { t } = useI18n();
const { user } = useUser();
const [isEditing, setIsEditing] = useState(false);
const [isDisabled, setIsDisabled] = useState(false);
const [changedPrices, setChangedPrices] = useState({});
const [deletedPrices, setDeletedPrices] = useState([]);
const [createdPrices, setCreatedPrices] = useState([]);
const hasChanges = useMemo(() => Object.entries(changedPrices).length > 0 ||
deletedPrices.length > 0 ||
createdPrices.length > 0, [changedPrices, deletedPrices, createdPrices]);
const shownPrices = useMemo(() => {
if (!isEditing)
return prices;
return prices
.map(({ amount, ...price }) => {
if (deletedPrices.includes(price.article_code)) {
return null;
}
return {
...price,
amount: changedPrices[price.article_code] ?? amount,
};
})
.filter((price) => price !== null);
}, [prices, isEditing, changedPrices, deletedPrices]);
const clear = useCallback(() => {
setChangedPrices({});
setDeletedPrices([]);
setCreatedPrices([]);
setIsEditing(false);
}, []);
const save = useCallback(async () => {
const action = api.operations["pricing.contrib:prices-update"];
if (!action) {
throw new Error('Invalid action "pricing.contrib:prices-update".');
}
setIsDisabled(true);
const response = await action.call({
params,
body: {
updates: [
...Object.entries(changedPrices).map(([article_code, amount]) => ({
article_code,
amount,
})),
...createdPrices,
],
deleted: deletedPrices,
},
});
setIsDisabled(false);
if (response.ok) {
const updatedPrices = await response.json();
setPrices(updatedPrices);
clear();
}
else {
console.error("[PRICES_CARD]", response);
}
}, [changedPrices, deletedPrices, createdPrices]);
return (React.createElement(Card, { sx: {
boxShadow: 0,
borderRadius: 3,
borderWidth: "1px",
borderStyle: "solid",
borderColor: theme.palette.divider,
backgroundColor: theme.palette.background.paper,
overflow: "visible",
width: "100%",
} },
React.createElement(TableCardHeader, { isDisabled: isDisabled, isEditable: hasPermission(user, "pricing.change_price"), title: "Prices", toggled: isEditing, onChange: async (isEditing) => {
if (hasChanges) {
if (await openDialog("Unsaved changes", "You have unsaved changes. Are you sure you want to discard your changes?", { ok: "Discard changes", cancel: "Cancel" })) {
clear();
}
}
else {
setIsEditing(isEditing);
}
} }),
React.createElement(TableContainer, null,
React.createElement(Table, null,
React.createElement(TableHead, null,
React.createElement(TableHeading, null, t("Article number")),
React.createElement(TableHeading, { align: "right" }, t("Amount")),
React.createElement(TableHeading, null)),
React.createElement(TableBody, { sx: {
".MuiTableRow-root:last-child > .MuiTableCell-root": { borderBottom: "none" },
} },
shownPrices.length === 0 && (React.createElement(TableRow, null,
React.createElement(TableCell, { align: "center", colSpan: 3, sx: { color: "GrayText" } }, t("No prices")))),
shownPrices.map((price, i) => (React.createElement(PriceRow, { key: i, isDisabled: isDisabled, isEditing: isEditing, price: price, onChangeAmount: (amount) => {
setChangedPrices((prev) => ({ ...prev, [price.article_code]: amount }));
}, onDelete: () => {
setDeletedPrices((prev) => [...prev, price.article_code]);
} }))),
isEditing && (React.createElement(React.Fragment, null, createdPrices.map((price, i) => (React.createElement(PriceRow, { key: i, isDisabled: isDisabled, isEditing: true, price: price, onChangeAmount: (amount) => {
setCreatedPrices((prev) => prev.map((p, j) => (i === j ? { ...p, amount } : p)));
}, onChangeArticleCode: (article_code) => {
setCreatedPrices((prev) => prev.map((p, j) => (i === j ? { ...p, article_code } : p)));
}, onDelete: () => {
setCreatedPrices((prev) => prev.filter((_, j) => j !== i));
} })))))))),
isEditing && (React.createElement(Stack, { direction: "row", justifyContent: "space-between" },
React.createElement(Box, { p: [1, 2, 3, 2] },
React.createElement(Button, { disabled: isDisabled, size: "medium", variant: "outlined", onClick: () => {
setCreatedPrices((prev) => [
...prev,
{ article_code: "", amount: "", currency: shownPrices[0]?.currency ?? "" },
]);
} }, "Add price")),
React.createElement(CardActions, { sx: {
p: [1, 2, 3, 2],
display: "flex",
justifyContent: "flex-end",
} },
React.createElement(Button, { disabled: isDisabled, size: "medium", variant: "outlined", onClick: clear }, t("Cancel")),
React.createElement(Button, { disabled: isDisabled, size: "medium", variant: "contained", onClick: save }, t("Save")))))));
};
//# sourceMappingURL=PricesCard.js.map