fix: logout

This commit is contained in:
IlyaDoronin 2024-04-11 13:07:22 +03:00
parent 8f393679eb
commit 14b63921a5
6 changed files with 199 additions and 141 deletions

@ -5,36 +5,37 @@ import { parseAxiosError } from "@root/utils/parse-error";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import useSWR from "swr"; import useSWR from "swr";
const apiUrl = process.env.REACT_APP_DOMAIN + "/price"; const apiUrl = process.env.REACT_APP_DOMAIN + "/price";
export async function getDiscounts(userId:string|null) { export async function getDiscounts(userId: string | null) {
console.log("перед запросом я получил айдишник юзера ", userId) if (userId === null) {
if (userId === null) throw new Error(`Не авторизован.`); return;
try { }
const discountsResponse = await makeRequest<never, GetDiscountsResponse>({
url: `${apiUrl}/discount/user/${userId}`,
method: "get",
useToken: true,
});
return discountsResponse.Discounts; try {
} catch (nativeError) { const discountsResponse = await makeRequest<never, GetDiscountsResponse>({
const [error] = parseAxiosError(nativeError); url: `${apiUrl}/discount/user/${userId}`,
method: "get",
throw new Error(`Ошибка получения списка скидок. ${error}`); useToken: true,
}
}
export function useDiscounts(userId:string|null) {
const { data } = useSWR("discounts", () => getDiscounts(userId), {
keepPreviousData: true,
onError: (error) => {
if (!(error instanceof Error)) return;
enqueueSnackbar(error.message, { variant: "error" });
}
}); });
return data; return discountsResponse.Discounts;
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
throw new Error(`Ошибка получения списка скидок. ${error}`);
}
}
export function useDiscounts(userId: string | null) {
const { data } = useSWR("discounts", () => getDiscounts(userId), {
keepPreviousData: true,
onError: (error) => {
if (!(error instanceof Error)) return;
enqueueSnackbar(error.message, { variant: "error" });
},
});
return data;
} }

@ -1,6 +1,14 @@
import { useState } from "react"; import { useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import { Box, Button, Container, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material"; import {
Box,
Button,
Container,
IconButton,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import SectionWrapper from "../SectionWrapper"; import SectionWrapper from "../SectionWrapper";
import LogoutIcon from "../icons/LogoutIcon"; import LogoutIcon from "../icons/LogoutIcon";
import DialogMenu from "./DialogMenu"; import DialogMenu from "./DialogMenu";
@ -12,7 +20,11 @@ import Menu from "../Menu";
import { logout } from "@root/api/auth"; import { logout } from "@root/api/auth";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { clearUserData, useUserStore } from "@root/stores/user"; import { clearUserData, useUserStore } from "@root/stores/user";
import { BurgerButton, clearAuthToken, getMessageFromFetchError } from "@frontend/kitui"; import {
BurgerButton,
clearAuthToken,
getMessageFromFetchError,
} from "@frontend/kitui";
import { currencyFormatter } from "@root/utils/currencyFormatter"; import { currencyFormatter } from "@root/utils/currencyFormatter";
import { clearCustomTariffs } from "@root/stores/customTariffs"; import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets"; import { clearTickets } from "@root/stores/tickets";
@ -31,17 +43,17 @@ export default function NavbarFull({ isLoggedIn }: Props) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
async function handleLogoutClick() { async function handleLogoutClick() {
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
clearAuthToken(); clearAuthToken();
clearUserData(); clearUserData();
clearCustomTariffs(); clearCustomTariffs();
clearTickets(); clearTickets();
navigate("/"); navigate("/");
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
} }
return isLoggedIn ? ( return isLoggedIn ? (
@ -71,7 +83,10 @@ export default function NavbarFull({ isLoggedIn }: Props) {
}} }}
> >
<Drawers /> <Drawers />
<IconButton sx={{ p: 0, ml: "8px" }} onClick={() => navigate("/wallet")}> <IconButton
sx={{ p: 0, ml: "8px" }}
onClick={() => navigate("/wallet")}
>
<WalletIcon color={theme.palette.gray.main} bgcolor="#F2F3F7" /> <WalletIcon color={theme.palette.gray.main} bgcolor="#F2F3F7" />
</IconButton> </IconButton>
<Box sx={{ ml: "8px", whiteSpace: "nowrap" }}> <Box sx={{ ml: "8px", whiteSpace: "nowrap" }}>
@ -124,7 +139,12 @@ export default function NavbarFull({ isLoggedIn }: Props) {
gap: "50px", gap: "50px",
}} }}
> >
<Box width="457px" justifyContent="space-between" display="inline-flex" alignItems="center"> <Box
width="457px"
justifyContent="space-between"
display="inline-flex"
alignItems="center"
>
<PenaLogo width={150} color="white" /> <PenaLogo width={150} color="white" />
{!isTablet ? null : <Menu />} {!isTablet ? null : <Menu />}
</Box> </Box>
@ -151,7 +171,10 @@ export default function NavbarFull({ isLoggedIn }: Props) {
</Button> </Button>
)} )}
<BurgerButton onClick={() => setOpen(!open)} sx={{ color: "white", display: !isTablet ? "block" : "none" }} /> <BurgerButton
onClick={() => setOpen(!open)}
sx={{ color: "white", display: !isTablet ? "block" : "none" }}
/>
</SectionWrapper> </SectionWrapper>
<DialogMenu open={open} handleClose={() => setOpen(false)} /> <DialogMenu open={open} handleClose={() => setOpen(false)} />
</> </>

@ -1,6 +1,14 @@
import { useState } from "react"; import { useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import { Box, Button, List, ListItem, Typography, useMediaQuery, useTheme } from "@mui/material"; import {
Box,
Button,
List,
ListItem,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { clearUserData, useUserStore } from "@root/stores/user"; import { clearUserData, useUserStore } from "@root/stores/user";
import { currencyFormatter } from "@root/utils/currencyFormatter"; import { currencyFormatter } from "@root/utils/currencyFormatter";
import { cardShadow } from "@root/utils/theme"; import { cardShadow } from "@root/utils/theme";
@ -31,7 +39,7 @@ const arrayMenu: MenuItem[] = [
{ name: "Корзина", url: "/cart" }, { name: "Корзина", url: "/cart" },
{ name: "Поддержка", url: "/support" }, { name: "Поддержка", url: "/support" },
{ name: "История", url: "/history" }, { name: "История", url: "/history" },
{name: "Мой кошелёк", url: "/wallet"}, { name: "Мой кошелёк", url: "/wallet" },
]; ];
interface DialogMenuProps { interface DialogMenuProps {
@ -57,20 +65,23 @@ export default function DialogMenu({ handleClose }: DialogMenuProps) {
}; };
async function handleLogoutClick() { async function handleLogoutClick() {
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
clearAuthToken(); clearAuthToken();
clearUserData(); clearUserData();
clearCustomTariffs(); clearCustomTariffs();
clearTickets(); clearTickets();
navigate("/"); navigate("/");
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
} }
const handleSubMenu = (index: number) => setActiveSubMenuIndex((activeIndex) => (activeIndex !== index ? index : -1)); const handleSubMenu = (index: number) =>
setActiveSubMenuIndex((activeIndex) =>
activeIndex !== index ? index : -1
);
return ( return (
<Box sx={{ height: "100%", maxHeight: "calc(100vh - 51px)" }}> <Box sx={{ height: "100%", maxHeight: "calc(100vh - 51px)" }}>
@ -98,18 +109,28 @@ export default function DialogMenu({ handleClose }: DialogMenuProps) {
state={{ previousUrl: location.pathname }} state={{ previousUrl: location.pathname }}
disableRipple disableRipple
variant="text" variant="text"
onClick={() => (!subMenu.length ? closeDialogMenu() : handleSubMenu(index))} onClick={() =>
!subMenu.length ? closeDialogMenu() : handleSubMenu(index)
}
sx={{ sx={{
padding: "10px 10px 10px 20px", padding: "10px 10px 10px 20px",
display: "block", display: "block",
fontWeight: 500, fontWeight: 500,
color: location.pathname === url ? "#7E2AEA" : location.pathname === "/" ? "white" : "black", color:
location.pathname === url
? "#7E2AEA"
: location.pathname === "/"
? "white"
: "black",
textTransform: "none", textTransform: "none",
fontSize: "16px", fontSize: "16px",
borderRadius: 0, borderRadius: 0,
"&:hover, &:active": { "&:hover, &:active": {
color: "#7E2AEA", color: "#7E2AEA",
background: index === activeSubMenuIndex ? theme.palette.background.default : "none", background:
index === activeSubMenuIndex
? theme.palette.background.default
: "none",
}, },
}} }}
> >
@ -143,7 +164,11 @@ export default function DialogMenu({ handleClose }: DialogMenuProps) {
whiteSpace: "nowrap", whiteSpace: "nowrap",
fontWeight: 400, fontWeight: 400,
color: color:
location.pathname === url ? "#7E2AEA" : location.pathname === "/" ? "white" : "black", location.pathname === url
? "#7E2AEA"
: location.pathname === "/"
? "white"
: "black",
}} }}
> >
{name} {name}

@ -1,94 +1,94 @@
import { Link, useNavigate } from "react-router-dom" import { Link, useNavigate } from "react-router-dom";
import { Box, Container, Typography, useTheme } from "@mui/material" import { Box, Container, Typography, useTheme } from "@mui/material";
import Drawers from "../Drawers" import Drawers from "../Drawers";
import PenaLogo from "../PenaLogo" import PenaLogo from "../PenaLogo";
import Menu from "../Menu" import Menu from "../Menu";
import { logout } from "@root/api/auth" import { logout } from "@root/api/auth";
import { enqueueSnackbar } from "notistack" import { enqueueSnackbar } from "notistack";
import { clearUserData, useUserStore } from "@root/stores/user" import { clearUserData, useUserStore } from "@root/stores/user";
import { import {
AvatarButton, AvatarButton,
LogoutButton, LogoutButton,
WalletButton, WalletButton,
clearAuthToken, clearAuthToken,
} from "@frontend/kitui" } from "@frontend/kitui";
import { clearCustomTariffs } from "@root/stores/customTariffs" import { clearCustomTariffs } from "@root/stores/customTariffs";
import { currencyFormatter } from "@root/utils/currencyFormatter" import { currencyFormatter } from "@root/utils/currencyFormatter";
import { clearTickets } from "@root/stores/tickets" import { clearTickets } from "@root/stores/tickets";
import type { ReactNode } from "react" import type { ReactNode } from "react";
interface Props { interface Props {
children: ReactNode; children: ReactNode;
} }
export default function NavbarFull({ children }: Props) { export default function NavbarFull({ children }: Props) {
const theme = useTheme() const theme = useTheme();
const navigate = useNavigate() const navigate = useNavigate();
const cash = useUserStore((state) => state.userAccount?.wallet.cash) ?? 0 const cash = useUserStore((state) => state.userAccount?.wallet.cash) ?? 0;
const initials = useUserStore((state) => state.initials) const initials = useUserStore((state) => state.initials);
async function handleLogoutClick() { async function handleLogoutClick() {
const [_, logoutError] = await logout() clearAuthToken();
clearUserData();
clearCustomTariffs();
clearTickets();
navigate("/");
if (logoutError) { const [_, logoutError] = await logout();
return enqueueSnackbar(logoutError)
}
clearAuthToken() if (logoutError) {
clearUserData() return enqueueSnackbar(logoutError);
clearCustomTariffs() }
clearTickets() }
navigate("/")
}
return ( return (
<Box> <Box>
<Container <Container
component="nav" component="nav"
disableGutters disableGutters
maxWidth={false} maxWidth={false}
sx={{ sx={{
zIndex: 1, zIndex: 1,
position: "fixed", position: "fixed",
top: "0", top: "0",
px: "16px", px: "16px",
display: "flex", display: "flex",
height: "80px", height: "80px",
alignItems: "center", alignItems: "center",
gap: "60px", gap: "60px",
bgcolor: "white", bgcolor: "white",
borderBottom: "1px solid #E3E3E3", borderBottom: "1px solid #E3E3E3",
}} }}
> >
<Link to="/"> <Link to="/">
<PenaLogo width={124} color="black" /> <PenaLogo width={124} color="black" />
</Link> </Link>
<Menu /> <Menu />
<Box sx={{ display: "flex", ml: "auto" }}> <Box sx={{ display: "flex", ml: "auto" }}>
<Drawers /> <Drawers />
<WalletButton component={Link} to="/wallet" sx={{ ml: "20px" }} /> <WalletButton component={Link} to="/wallet" sx={{ ml: "20px" }} />
<Box sx={{ ml: "8px", whiteSpace: "nowrap" }}> <Box sx={{ ml: "8px", whiteSpace: "nowrap" }}>
<Typography <Typography
sx={{ sx={{
fontSize: "12px", fontSize: "12px",
lineHeight: "14px", lineHeight: "14px",
color: theme.palette.gray.dark, color: theme.palette.gray.dark,
}} }}
> >
Мой баланс Мой баланс
</Typography> </Typography>
<Typography variant="body2" color={theme.palette.purple.main}> <Typography variant="body2" color={theme.palette.purple.main}>
{currencyFormatter.format(cash / 100)} {currencyFormatter.format(cash / 100)}
</Typography> </Typography>
</Box> </Box>
<AvatarButton component={Link} to="/settings" sx={{ ml: "27px" }}> <AvatarButton component={Link} to="/settings" sx={{ ml: "27px" }}>
{initials} {initials}
</AvatarButton> </AvatarButton>
<LogoutButton onClick={handleLogoutClick} sx={{ ml: "20px" }} /> <LogoutButton onClick={handleLogoutClick} sx={{ ml: "20px" }} />
</Box> </Box>
</Container> </Container>
<Box>{children}</Box> <Box>{children}</Box>
</Box> </Box>
) );
} }

@ -1,5 +1,11 @@
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { Box, IconButton, Typography, useTheme, useMediaQuery } from "@mui/material"; import {
Box,
IconButton,
Typography,
useTheme,
useMediaQuery,
} from "@mui/material";
import LogoutIcon from "../icons/LogoutIcon"; import LogoutIcon from "../icons/LogoutIcon";
import Drawers from "../Drawers"; import Drawers from "../Drawers";
import { logout } from "@root/api/auth"; import { logout } from "@root/api/auth";
@ -21,17 +27,17 @@ export const NavbarPanel = () => {
const initials = useUserStore((state) => state.initials); const initials = useUserStore((state) => state.initials);
async function handleLogoutClick() { async function handleLogoutClick() {
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
clearAuthToken(); clearAuthToken();
clearUserData(); clearUserData();
clearCustomTariffs(); clearCustomTariffs();
clearTickets(); clearTickets();
navigate("/"); navigate("/");
const [_, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
} }
return ( return (

@ -50,7 +50,9 @@ export default function QuizPayment() {
useEffect( useEffect(
function redirectIfSignedIn() { function redirectIfSignedIn() {
if (!first && user?._id === userId) if (!first && user?._id === userId)
navigate(`/payment?action=${action}&dif=${dif}&user=${userId}`, { replace: true }); navigate(`/payment?action=${action}&dif=${dif}&user=${userId}`, {
replace: true,
});
}, },
[navigate, user] [navigate, user]
); );
@ -61,7 +63,7 @@ export default function QuizPayment() {
history.pushState(null, document.title, "/quizpayment"); history.pushState(null, document.title, "/quizpayment");
try { try {
first = false; first = false;
if (user?._id === userId) { if (user?._id === userId) {
return; return;
} }
@ -71,11 +73,12 @@ export default function QuizPayment() {
// const data = await refresh(token) // const data = await refresh(token)
// console.log(token) // console.log(token)
if (getAuthToken()) { if (getAuthToken()) {
await logout();
clearAuthToken(); clearAuthToken();
clearUserData(); clearUserData();
clearCustomTariffs(); clearCustomTariffs();
clearTickets(); clearTickets();
await logout();
} }
setAuthToken(token); setAuthToken(token);