adminFront/src/kitUI/Cart/Cart.tsx
2023-05-18 23:31:36 +03:00

336 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import theme from "@theme";
import { Button, Paper, Box, Typography, TableHead, TableRow, TableCell, TableBody, Table, Tooltip, Alert, Checkbox, FormControlLabel } from "@mui/material";
import Input from "@kitUI/input";
import { useCartStore } from "@root/stores/cart";
import { useState } from "react";
import { GridSelectionModel } from "@mui/x-data-grid";
import { testUser } from "@root/stores/mocks/user";
import { useDiscountStore } from "@root/stores/discounts";
import { calcCartData, createCartItem, findDiscountFactor, formatDiscountFactor } from "./calc";
import { useTariffStore } from "@root/stores/tariffs";
import { AnyDiscount, CartItemTotal } from "@root/model/cart";
interface Props {
selectedTariffs: GridSelectionModel;
}
export default function Cart({ selectedTariffs }: Props) {
const tariffs = useTariffStore(store => store.tariffs);
const discounts = useDiscountStore(store => store.discounts);
const cartTotal = useCartStore(state => state.cartTotal);
const setCartTotal = useCartStore(store => store.setCartTotal);
const [couponField, setCouponField] = useState<string>("");
const [loyaltyField, setLoyaltyField] = useState<string>("");
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [isNonCommercial, setIsNonCommercial] = useState<boolean>(false);
const cartRows = cartTotal?.items.map(cartItemTotal => {
const service = cartItemTotal.tariff.privilege.serviceKey;
const serviceDiscount = cartTotal.discountsByService[service];
const envolvedDiscountsElement = (
<Box>
{cartItemTotal.envolvedDiscounts.map((discount, index, arr) => (
<span key={discount._id}>
<DiscountTooltip
discount={discount}
cartItemTotal={cartItemTotal}
/>
{index < arr.length - (serviceDiscount ? 0 : 1) &&
<span>,&nbsp;</span>
}
</span>
))}
{serviceDiscount &&
<span>
<DiscountTooltip
discount={serviceDiscount}
cartItemTotal={cartItemTotal}
/>
</span>
}
</Box>
);
const totalIncludingServiceDiscount = cartItemTotal.totalPrice * (serviceDiscount?.target.factor || 1);
return {
id: cartItemTotal.tariff.id,
tariffName: cartItemTotal.tariff.name,
privilegeDesc: cartItemTotal.tariff.privilege.description,
envolvedDiscounts: envolvedDiscountsElement,
price: totalIncludingServiceDiscount,
};
});
const cartDiscounts = cartTotal?.envolvedCartDiscounts;
const cartDiscountsResultFactor = cartDiscounts && cartDiscounts?.length > 1 && cartDiscounts.reduce((acc, discount) => acc * findDiscountFactor(discount), 1);
const envolvedCartDiscountsElement = cartDiscounts && (
<Box sx={{
display: "inline-flex",
flexWrap: "wrap",
}}>
{cartDiscounts?.map((discount, index, arr) => (
<span key={discount._id}>
<DiscountTooltip
discount={discount}
/>
{index < arr.length - 1 &&
<span>,&nbsp;</span>
}
</span>
))}
&nbsp;
{cartDiscountsResultFactor && `= ${formatDiscountFactor(cartDiscountsResultFactor)}`}
</Box>
);
function handleCalcCartClick() {
const cartTariffs = tariffs.filter(tariff => selectedTariffs.includes(tariff.id));
const cartItems = cartTariffs.map(tariff => createCartItem(tariff));
let loyaltyValue = parseInt(loyaltyField);
if (!isFinite(loyaltyValue)) loyaltyValue = 0;
const activeDiscounts = discounts.filter(discount => !discount.disabled);
const cartData = calcCartData({
user: testUser,
purchasesAmount: loyaltyValue,
cartItems,
discounts: activeDiscounts,
isNonCommercial,
coupon: couponField,
});
if (cartData instanceof Error) {
setErrorMessage(cartData.message);
return setCartTotal(null);
}
setErrorMessage(null);
setCartTotal(cartData);
}
return (
<Box
component="section"
sx={{
border: "1px solid white",
display: "flex",
flexDirection: "column",
alignItems: "center",
width: "100%",
pb: "20px",
borderRadius: "4px",
}}
>
<Typography variant="caption">
корзина
</Typography>
<Paper
variant="bar"
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: "20px",
}}
>
<FormControlLabel
checked={isNonCommercial}
onChange={(e, checked) => setIsNonCommercial(checked)}
control={<Checkbox
sx={{
color: theme.palette.secondary.main,
"&.Mui-checked": {
color: theme.palette.secondary.main,
},
}}
/>}
label="НКО"
sx={{
color: theme.palette.secondary.main,
}}
/>
<Box
sx={{
border: "1px solid white",
padding: "3px",
display: "flex",
flexDirection: "column"
}}
>
<Input
label="промокод"
size="small"
value={couponField}
onChange={e => setCouponField(e.target.value)}
InputProps={{
style: {
backgroundColor: theme.palette.content.main,
color: theme.palette.secondary.main,
}
}}
InputLabelProps={{
style: {
color: theme.palette.secondary.main
}
}}
/>
</Box>
{cartTotal?.couponState && (
cartTotal.couponState === "applied" ?
<Alert severity="success">Купон применен!</Alert>
:
<Alert severity="error">Подходящий купон не найден!</Alert>
)}
<Box
sx={{
border: "1px solid white",
padding: "3px",
display: "flex",
flexDirection: "column",
ml: "auto",
}}
>
<Input
label="лояльность"
size="small"
type="number"
value={loyaltyField}
onChange={e => setLoyaltyField(e.target.value)}
InputProps={{
style: {
backgroundColor: theme.palette.content.main,
color: theme.palette.secondary.main,
}
}}
InputLabelProps={{
style: {
color: theme.palette.secondary.main
}
}}
/>
</Box>
<Button onClick={handleCalcCartClick}>рассчитать</Button>
</Paper>
{cartTotal?.items && cartTotal.items.length > 0 &&
<>
<Table sx={{
width: "90%",
margin: "5px",
border: "2px solid",
borderColor: theme.palette.secondary.main,
}} aria-label="simple table">
<TableHead>
<TableRow sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px"
}}>
<TableCell>
<Typography
variant="h4"
sx={{ color: theme.palette.secondary.main }}
>Имя</Typography>
</TableCell>
<TableCell>
<Typography
variant="h4"
sx={{ color: theme.palette.secondary.main }}
>Описание</Typography>
</TableCell>
<TableCell>
<Typography
variant="h4"
sx={{ color: theme.palette.secondary.main }}
>Скидки</Typography>
</TableCell>
<TableCell>
<Typography
variant="h4"
sx={{ color: theme.palette.secondary.main }}
>стоимость</Typography>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cartRows?.map(row => (
<TableRow
key={row.id}
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
}}
>
<TableCell sx={{
color: theme.palette.secondary.main,
}}>{row.tariffName}</TableCell>
<TableCell sx={{
color: theme.palette.secondary.main,
}}>{row.privilegeDesc}</TableCell>
<TableCell sx={{
color: theme.palette.secondary.main,
}}>{row.envolvedDiscounts}</TableCell>
<TableCell sx={{
color: theme.palette.secondary.main,
}}>{row.price.toFixed(2)} </TableCell>
</TableRow>
))}
</TableBody>
</Table>
<Typography id="transition-modal-title" variant="h6" sx={{
fontWeight: "normal",
textAlign: "center",
marginTop: "15px",
fontSize: "16px"
}}>
Скидки корзины: {envolvedCartDiscountsElement}
</Typography>
<Typography id="transition-modal-title" variant="h6" sx={{
fontWeight: "normal",
textAlign: "center",
marginTop: "10px"
}}>
ИТОГО: <span>{cartTotal?.totalPrice.toFixed(2)} </span>
</Typography>
</>
}
{errorMessage !== null &&
<Alert variant="filled" severity="error" sx={{ mt: "20px" }}>
{errorMessage}
</Alert>
}
</Box>
);
}
function DiscountTooltip({ discount, cartItemTotal }: {
discount: AnyDiscount;
cartItemTotal?: CartItemTotal;
}) {
const discountText = formatDiscountFactor(findDiscountFactor(discount));
return (
<Tooltip title={
<>
<Typography>Скидка: {discount?.name}</Typography>
<Typography>{discount?.description}</Typography>
<Typography>-------</Typography>
<Typography>layer: {discount?.layer}</Typography>
<Typography>id: {discount?._id}</Typography>
</>
}>
<span>{discountText}</span>
</Tooltip>
);
}