fix cart drawer not enough money autocomplete

This commit is contained in:
nflnkr 2024-03-11 21:00:24 +03:00
parent c730993fef
commit 3f23b7b2aa

@ -1,5 +1,5 @@
import { useState, useRef } from "react";
import { Typography, Drawer, useMediaQuery, useTheme, Box, IconButton, Badge, Button } from "@mui/material";
import { Typography, Drawer, useMediaQuery, useTheme, Box, IconButton, Badge, Button, Alert } from "@mui/material";
import SectionWrapper from "./SectionWrapper";
import CustomWrapperDrawer from "./CustomWrapperDrawer";
import { NotificationsModal } from "./NotificationsModal";
@ -22,328 +22,342 @@ import { handleComponentError } from "@root/utils/handleComponentError";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
function Drawers() {
const [openNotificationsModal, setOpenNotificationsModal] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const bellRef = useRef<HTMLButtonElement | null>(null);
const navigate = useNavigate();
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isDrawerOpen = useCartStore((state) => state.isDrawerOpen);
const cart = useCart();
const userAccount = useUserStore((state) => state.userAccount);
const tickets = useTicketStore((state) => state.tickets);
const [notEnoughMoneyAmount, setNotEnoughMoneyAmount] = useState<number>(0);
const [openNotificationsModal, setOpenNotificationsModal] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const bellRef = useRef<HTMLButtonElement | null>(null);
const navigate = useNavigate();
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isDrawerOpen = useCartStore((state) => state.isDrawerOpen);
const cart = useCart();
const userAccount = useUserStore((state) => state.userAccount);
const tickets = useTicketStore((state) => state.tickets);
const [notEnoughMoneyAmount, setNotEnoughMoneyAmount] = useState<number>(0);
const notificationsCount = tickets.filter(
({ user, top_message }) => user !== top_message.user_id && top_message.shown.me !== 1
).length;
const notificationsCount = tickets.filter(
({ user, top_message }) => user !== top_message.user_id && top_message.shown.me !== 1
).length;
async function handlePayClick() {
setLoading(true);
async function handlePayClick() {
setLoading(true);
const [payCartResponse, payCartError] = await payCart();
const [payCartResponse, payCartError] = await payCart();
if (payCartError) {
if (payCartError.includes("insufficient funds: ")) {
const notEnoughMoneyAmount = parseInt(payCartError.replace(/^.*insufficient\sfunds:\s(?=\d+$)/, ""));
setNotEnoughMoneyAmount(notEnoughMoneyAmount);
}
if (payCartError) {
if (payCartError.includes("insufficient funds: ")) {
const notEnoughMoneyAmount = parseInt(payCartError.replace(/^.*insufficient\sfunds:\s(?=\d+$)/, ""));
setNotEnoughMoneyAmount(notEnoughMoneyAmount);
}
setLoading(false);
setLoading(false);
closeCartDrawer()
navigate("payment")
if (!payCartError.includes("insufficient funds: ")) enqueueSnackbar(payCartError);
return
if (!payCartError.includes("insufficient funds: ")) enqueueSnackbar(payCartError);
return;
}
if (payCartResponse) {
setUserAccount(payCartResponse);
}
setLoading(false);
closeCartDrawer();
}
if (payCartResponse) {
setUserAccount(payCartResponse);
function handleReplenishWallet() {
closeCartDrawer();
navigate("/payment", { state: { notEnoughMoneyAmount } });
}
setLoading(false);
closeCartDrawer();
}
function handleReplenishWallet() {
navigate("/payment", { state: { notEnoughMoneyAmount } });
}
return (
<Box sx={{ display: "flex", gap: isTablet ? "10px" : "20px" }}>
<IconButton
ref={bellRef}
aria-label="cart"
onClick={() => setOpenNotificationsModal((isOpened) => !isOpened)}
sx={{
cursor: "pointer",
borderRadius: "6px",
background: openNotificationsModal ? theme.palette.purple.main : theme.palette.background.default,
"& .MuiBadge-badge": {
background: openNotificationsModal ? theme.palette.background.default : theme.palette.purple.main,
color: openNotificationsModal ? theme.palette.purple.main : theme.palette.background.default,
},
"& svg > path:first-of-type": {
fill: openNotificationsModal ? "#FFFFFF" : "#9A9AAF",
},
"& svg > path:last-child": {
stroke: openNotificationsModal ? "#FFFFFF" : "#9A9AAF",
},
"&:hover": {
background: theme.palette.purple.main,
"& .MuiBox-root": {
background: theme.palette.purple.main,
},
"& .MuiBadge-badge": {
background: theme.palette.background.default,
color: theme.palette.purple.main,
},
"& svg > path:first-of-type": { fill: "#FFFFFF" },
"& svg > path:last-child": { stroke: "#FFFFFF" },
},
}}
>
<Badge
badgeContent={notificationsCount}
sx={{
"& .MuiBadge-badge": {
display: notificationsCount ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.purple.main,
transform: "scale(0.8) translate(50%, -50%)",
top: "2px",
right: "2px",
fontWeight: 400,
},
}}
>
<BellIcon />
</Badge>
</IconButton>
<NotificationsModal
open={openNotificationsModal}
setOpen={setOpenNotificationsModal}
anchorElement={bellRef.current}
notifications={tickets
.filter(({ user, top_message }) => user !== top_message.user_id)
.map((ticket) => ({
text: "У вас новое сообщение от техподдержки",
date: new Date(ticket.updated_at).toLocaleDateString(),
url: `/support/${ticket.id}`,
watched: ticket.user === ticket.top_message.user_id || ticket.top_message.shown.me === 1,
}))}
/>
<IconButton
onClick={openCartDrawer}
component="div"
sx={{
cursor: "pointer",
background: theme.palette.background.default,
borderRadius: "6px",
"&:hover": {
background: theme.palette.purple.main,
"& .MuiBox-root": {
background: theme.palette.purple.main,
},
"& .MuiBadge-badge": {
background: theme.palette.background.default,
color: theme.palette.purple.main,
},
"& svg > path:nth-of-type(1)": { fill: "#FFFFFF" },
"& svg > path:nth-of-type(2)": { fill: "#FFFFFF" },
"& svg > path:nth-of-type(3)": { stroke: "#FFFFFF" },
},
}}
>
<Badge
badgeContent={userAccount?.cart.length}
sx={{
"& .MuiBadge-badge": {
display: userAccount?.cart.length ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.purple.main,
transform: "scale(0.8) translate(50%, -50%)",
top: "2px",
right: "2px",
fontWeight: 400,
},
}}
>
<CartIcon />
</Badge>
</IconButton>
<Drawer anchor={"right"} open={isDrawerOpen} onClose={closeCartDrawer} sx={{ background: "rgba(0, 0, 0, 0.55)" }}>
<SectionWrapper
maxWidth="lg"
sx={{
pl: "0px",
pr: "0px",
width: "450px",
}}
>
<Box
sx={{
width: "100%",
pt: "12px",
pb: "12px",
display: "flex",
justifyContent: "space-between",
bgcolor: "#F2F3F7",
gap: "10px",
pl: "20px",
pr: "20px",
}}
>
<Typography
component="div"
sx={{
fontSize: "18px",
lineHeight: "21px",
font: "Rubick",
}}
>
Корзина
</Typography>
<IconButton onClick={closeCartDrawer} sx={{ p: 0 }}>
<CrossIcon />
</IconButton>
</Box>
<Box sx={{ pl: "20px", pr: "20px" }}>
{cart.services.map((serviceData) => {
console.log('aaaaaaaaaaAAAAAAAAAAAAAA', (cart.appliedCartPurchasesDiscount?.Target?.Factor || 1)*(cart.appliedLoyaltyDiscount?.Target?.Factor || 1), (cart.appliedCartPurchasesDiscount?.Target?.Factor || 1),(cart.appliedLoyaltyDiscount?.Target?.Factor || 1))
return (
<CustomWrapperDrawer key={serviceData.serviceKey} outsideFactor={(cart.appliedCartPurchasesDiscount?.Target?.Factor || 1)*(cart.appliedLoyaltyDiscount?.Target?.Factor || 1)} serviceData={serviceData} />
)})}
<Box
sx={{
mt: "40px",
pt: upMd ? "30px" : undefined,
borderTop: upMd ? `1px solid ${theme.palette.gray.main}` : undefined,
}}
>
<Box
return (
<Box sx={{ display: "flex", gap: isTablet ? "10px" : "20px" }}>
<IconButton
ref={bellRef}
aria-label="cart"
onClick={() => setOpenNotificationsModal((isOpened) => !isOpened)}
sx={{
width: upMd ? "100%" : undefined,
display: "flex",
flexWrap: "wrap",
flexDirection: "column",
cursor: "pointer",
borderRadius: "6px",
background: openNotificationsModal ? theme.palette.purple.main : theme.palette.background.default,
"& .MuiBadge-badge": {
background: openNotificationsModal ? theme.palette.background.default : theme.palette.purple.main,
color: openNotificationsModal ? theme.palette.purple.main : theme.palette.background.default,
},
"& svg > path:first-of-type": {
fill: openNotificationsModal ? "#FFFFFF" : "#9A9AAF",
},
"& svg > path:last-child": {
stroke: openNotificationsModal ? "#FFFFFF" : "#9A9AAF",
},
"&:hover": {
background: theme.palette.purple.main,
"& .MuiBox-root": {
background: theme.palette.purple.main,
},
"& .MuiBadge-badge": {
background: theme.palette.background.default,
color: theme.palette.purple.main,
},
"& svg > path:first-of-type": { fill: "#FFFFFF" },
"& svg > path:last-child": { stroke: "#FFFFFF" },
},
}}
>
<Typography variant="h4" mb={upMd ? "18px" : "30px"}>
Итоговая цена
</Typography>
<Typography color={theme.palette.gray.dark} mb={upMd ? "18px" : "30px"}>
Здесь написана окончательная стоимость всех услуг сложенных в корзину с учётом всех скидок.
</Typography>
<Typography color={theme.palette.gray.dark}>
После нажатия кнопки оплатить, вы будете перенаправлены на форму оплаты, для оплаты ВСЕЙ корзины (рекомендуем перед оплатой, убрать все лишнее)
</Typography>
</Box>
<Box
sx={{
color: theme.palette.gray.dark,
pb: "100px",
pt: "38px",
}}
>
>
<Badge
badgeContent={
cart.priceBeforeDiscounts - cart.priceAfterDiscounts ? (
<span
style={{
backgroundColor: "#ff4904",
color: "white",
fontSize: "14px",
}}
>
-
{`${
((cart.priceBeforeDiscounts - cart.priceAfterDiscounts) / (cart.priceBeforeDiscounts / 100)).toFixed(0)
}%`}
</span>
) : null
}
color="success"
sx={{
"& .MuiBadge-dot": {
backgroundColor: "#ff4904",
width: "10px",
height: "10px",
},
"& .MuiBadge-anchorOriginTopRightRectangle": {
backgroundColor: "#ff4904",
top: "5px",
right: "5px",
},
"& .MuiBadge-anchorOriginTopRightRectangular": {
backgroundColor: "#ff4904",
height: "31px",
padding: "5px 10px",
right: "20px",
},
}}
>
<Box
badgeContent={notificationsCount}
sx={{
display: "flex",
flexDirection: upMd ? "column" : "row",
alignItems: upMd ? "start" : "center",
mt: upMd ? "10px" : "30px",
gap: "15px",
"& .MuiBadge-badge": {
display: notificationsCount ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.purple.main,
transform: "scale(0.8) translate(50%, -50%)",
top: "2px",
right: "2px",
fontWeight: 400,
},
}}
>
<Typography
color={theme.palette.orange.main}
sx={{
textDecoration: "line-through",
order: upMd ? 1 : 2,
}}
>
{currencyFormatter.format(cart.priceBeforeDiscounts / 100)}
</Typography>
<Typography
variant="p1"
sx={{
fontWeight: 500,
fontSize: "26px",
lineHeight: "31px",
order: upMd ? 2 : 1,
mr: "20px",
}}
>
{currencyFormatter.format(cart.priceAfterDiscounts / 100)}
</Typography>
</Box>
</Badge>
<Button
disabled = {cart.priceAfterDiscounts === 0}
variant="pena-contained-dark"
onClick={() => (notEnoughMoneyAmount === 0 ? !loading && handlePayClick() : handleReplenishWallet())}
sx={{ mt: "25px", display: "block" }}
>
{loading ? <Loader size={24} /> : notEnoughMoneyAmount === 0 ? "Оплатить" : "Пополнить"}
</Button>
</Box>
</Box>
</Box>
</SectionWrapper>
</Drawer>
</Box>
);
<BellIcon />
</Badge>
</IconButton>
<NotificationsModal
open={openNotificationsModal}
setOpen={setOpenNotificationsModal}
anchorElement={bellRef.current}
notifications={tickets
.filter(({ user, top_message }) => user !== top_message.user_id)
.map((ticket) => ({
text: "У вас новое сообщение от техподдержки",
date: new Date(ticket.updated_at).toLocaleDateString(),
url: `/support/${ticket.id}`,
watched: ticket.user === ticket.top_message.user_id || ticket.top_message.shown.me === 1,
}))}
/>
<IconButton
onClick={openCartDrawer}
component="div"
sx={{
cursor: "pointer",
background: theme.palette.background.default,
borderRadius: "6px",
"&:hover": {
background: theme.palette.purple.main,
"& .MuiBox-root": {
background: theme.palette.purple.main,
},
"& .MuiBadge-badge": {
background: theme.palette.background.default,
color: theme.palette.purple.main,
},
"& svg > path:nth-of-type(1)": { fill: "#FFFFFF" },
"& svg > path:nth-of-type(2)": { fill: "#FFFFFF" },
"& svg > path:nth-of-type(3)": { stroke: "#FFFFFF" },
},
}}
>
<Badge
badgeContent={userAccount?.cart.length}
sx={{
"& .MuiBadge-badge": {
display: userAccount?.cart.length ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.purple.main,
transform: "scale(0.8) translate(50%, -50%)",
top: "2px",
right: "2px",
fontWeight: 400,
},
}}
>
<CartIcon />
</Badge>
</IconButton>
<Drawer anchor={"right"} open={isDrawerOpen} onClose={closeCartDrawer} sx={{ background: "rgba(0, 0, 0, 0.55)" }}>
<SectionWrapper
maxWidth="lg"
sx={{
pl: "0px",
pr: "0px",
width: "450px",
}}
>
<Box
sx={{
width: "100%",
pt: "12px",
pb: "12px",
display: "flex",
justifyContent: "space-between",
bgcolor: "#F2F3F7",
gap: "10px",
pl: "20px",
pr: "20px",
}}
>
<Typography
component="div"
sx={{
fontSize: "18px",
lineHeight: "21px",
font: "Rubick",
}}
>
Корзина
</Typography>
<IconButton onClick={closeCartDrawer} sx={{ p: 0 }}>
<CrossIcon />
</IconButton>
</Box>
<Box sx={{ pl: "20px", pr: "20px" }}>
{cart.services.map((serviceData) => {
console.log('aaaaaaaaaaAAAAAAAAAAAAAA', (cart.appliedCartPurchasesDiscount?.Target?.Factor || 1)*(cart.appliedLoyaltyDiscount?.Target?.Factor || 1), (cart.appliedCartPurchasesDiscount?.Target?.Factor || 1),(cart.appliedLoyaltyDiscount?.Target?.Factor || 1))
return (
<CustomWrapperDrawer key={serviceData.serviceKey} outsideFactor={(cart.appliedCartPurchasesDiscount?.Target?.Factor || 1)*(cart.appliedLoyaltyDiscount?.Target?.Factor || 1)} serviceData={serviceData} />
)})}
<Box
sx={{
mt: "40px",
pt: upMd ? "30px" : undefined,
borderTop: upMd ? `1px solid ${theme.palette.gray.main}` : undefined,
}}
>
<Box
sx={{
width: upMd ? "100%" : undefined,
display: "flex",
flexWrap: "wrap",
flexDirection: "column",
}}
>
<Typography variant="h4" mb={upMd ? "18px" : "30px"}>
Итоговая цена
</Typography>
<Typography color={theme.palette.gray.dark} mb={upMd ? "18px" : "30px"}>
Здесь написана окончательная стоимость всех услуг сложенных в корзину с учётом всех скидок.
</Typography>
<Typography color={theme.palette.gray.dark}>
После нажатия кнопки оплатить, вы будете перенаправлены на форму оплаты, для оплаты ВСЕЙ корзины (рекомендуем перед оплатой, убрать все лишнее)
</Typography>
</Box>
<Box
sx={{
color: theme.palette.gray.dark,
pb: "100px",
pt: "38px",
}}
>
<Badge
badgeContent={
cart.priceBeforeDiscounts - cart.priceAfterDiscounts ? (
<span
style={{
backgroundColor: "#ff4904",
color: "white",
fontSize: "14px",
}}
>
-
{`${
((cart.priceBeforeDiscounts - cart.priceAfterDiscounts) / (cart.priceBeforeDiscounts / 100)).toFixed(0)
}%`}
</span>
) : null
}
color="success"
sx={{
"& .MuiBadge-dot": {
backgroundColor: "#ff4904",
width: "10px",
height: "10px",
},
"& .MuiBadge-anchorOriginTopRightRectangle": {
backgroundColor: "#ff4904",
top: "5px",
right: "5px",
},
"& .MuiBadge-anchorOriginTopRightRectangular": {
backgroundColor: "#ff4904",
height: "31px",
padding: "5px 10px",
right: "20px",
},
}}
>
<Box
sx={{
display: "flex",
flexDirection: upMd ? "column" : "row",
alignItems: upMd ? "start" : "center",
mt: upMd ? "10px" : "30px",
gap: "15px",
}}
>
<Typography
color={theme.palette.orange.main}
sx={{
textDecoration: "line-through",
order: upMd ? 1 : 2,
}}
>
{currencyFormatter.format(cart.priceBeforeDiscounts / 100)}
</Typography>
<Typography
variant="p1"
sx={{
fontWeight: 500,
fontSize: "26px",
lineHeight: "31px",
order: upMd ? 2 : 1,
mr: "20px",
}}
>
{currencyFormatter.format(cart.priceAfterDiscounts / 100)}
</Typography>
</Box>
</Badge>
<Box
sx={{
display: "flex",
alignItems: "center",
flexWrap: "wrap",
mt: "25px",
gap: "15px",
}}
>
{notEnoughMoneyAmount > 0 && (
<Alert severity="error" variant="filled">
Не хватает {currencyFormatter.format(notEnoughMoneyAmount / 100)}
</Alert>
)}
<Button
disabled={cart.priceAfterDiscounts === 0}
variant="pena-contained-dark"
onClick={() => (notEnoughMoneyAmount === 0 ? !loading && handlePayClick() : handleReplenishWallet())}
sx={{ display: "block" }}
>
{loading ? <Loader size={24} /> : notEnoughMoneyAmount === 0 ? "Оплатить" : "Пополнить"}
</Button>
</Box>
</Box>
</Box>
</Box>
</SectionWrapper>
</Drawer>
</Box>
);
}
export default withErrorBoundary(Drawers, {
fallback: (
<Box
sx={{
display: "flex",
alignItems: "center",
}}
>
<ErrorOutlineIcon color="error" />
</Box>
),
onError: handleComponentError,
fallback: (
<Box
sx={{
display: "flex",
alignItems: "center",
}}
>
<ErrorOutlineIcon color="error" />
</Box>
),
onError: handleComponentError,
});