show amo token expired dialog on route changes

This commit is contained in:
nflnkr 2024-06-24 20:40:13 +03:00
parent 55ebc8a768
commit 1794ce032a
7 changed files with 93 additions and 112 deletions

@ -1,32 +1,30 @@
import type { SuspenseProps } from "react";
import { lazy, Suspense } from "react";
import { lazily } from "react-lazily";
import ContactFormModal from "@ui_kit/ContactForm";
import SigninDialog from "./pages/auth/Signin";
import SignupDialog from "./pages/auth/Signup";
import { Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom";
import "./index.css";
import Landing from "./pages/Landing/Landing";
import Main from "./pages/main";
import { clearAuthToken, getMessageFromFetchError, UserAccount, useUserFetcher } from "@frontend/kitui";
import type { OriginalUserAccount } from "@root/user";
import { clearUserData, setCustomerAccount, setUser, setUserAccount, useUserStore } from "@root/user";
import { enqueueSnackbar } from "notistack";
import PrivateRoute from "@ui_kit/PrivateRoute";
import ContactFormModal from "@ui_kit/ContactForm";
import FloatingSupportChat from "@ui_kit/FloatingSupportChat";
import { Restore } from "./pages/auth/Restore";
import { isAxiosError } from "axios";
import RecoverPassword from "./pages/auth/RecoverPassword";
import { InfoPrivilege } from "./pages/InfoPrivilege";
import OutdatedLink from "./pages/auth/OutdatedLink";
import PrivateRoute from "@ui_kit/PrivateRoute";
import { useAfterpay } from "@utils/hooks/useAfterpay";
import { useUserAccountFetcher } from "@utils/hooks/useUserAccountFetcher";
import { enqueueSnackbar } from "notistack";
import type { SuspenseProps } from "react";
import { lazy, Suspense } from "react";
import { lazily } from "react-lazily";
import { Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom";
import { useAmoAccount } from "./api/integration";
import ListPageDummy from "./components/Dummys/pageDummys/listPageDummy";
import "./index.css";
import OutdatedLink from "./pages/auth/OutdatedLink";
import RecoverPassword from "./pages/auth/RecoverPassword";
import { Restore } from "./pages/auth/Restore";
import SigninDialog from "./pages/auth/Signin";
import SignupDialog from "./pages/auth/Signup";
import { InfoPrivilege } from "./pages/InfoPrivilege";
import AmoTokenExpiredDialog from "./pages/IntegrationsPage/IntegrationsModal/AmoTokenExpiredDialog";
import Landing from "./pages/Landing/Landing";
import Main from "./pages/main";
const MyQuizzesFull = lazy(() => import("./pages/createQuize/MyQuizzesFull"));
const QuizGallery = lazy(() => import("./pages/createQuize/QuizGallery"));
const ViewPage = lazy(() => import("./pages/ViewPublicationPage"));
const Analytics = lazy(() => import("./pages/Analytics/Analytics"));
@ -69,6 +67,7 @@ export default function App() {
const userId = useUserStore((state) => state.userId);
const location = useLocation();
const navigate = useNavigate();
const { data: amoAccount } = useAmoAccount();
useUserFetcher({
url: `${process.env.REACT_APP_DOMAIN}/user/${userId}`,
@ -127,6 +126,7 @@ export default function App() {
return (
<>
{amoAccount && <AmoTokenExpiredDialog isAmoTokenExpired={amoAccount.stale} />}
<ContactFormModal />
<FloatingSupportChat />
{location.state?.backgroundLocation && (

@ -1,23 +1,22 @@
import { connectAmo } from "@/api/integration";
import { setTryShowAmoTokenExpiredDialog } from "@/stores/uiTools/actions";
import { useUiTools } from "@/stores/uiTools/store";
import CustomCheckbox from "@/ui_kit/CustomCheckbox";
import { Box, Button, Dialog, Typography, useMediaQuery, useTheme } from "@mui/material";
import { useState } from "react";
import { Box, Button, Dialog, Typography, useTheme } from "@mui/material";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
const HIDE_DIALOG_EXPIRATION_PERIOD = 24 * 60 * 60 * 1000;
interface Props {
initialOpen: boolean;
isAmoTokenExpired: boolean;
}
export default function AmoTokenExpiredDialog({ initialOpen }: Props) {
export default function AmoTokenExpiredDialog({ isAmoTokenExpired }: Props) {
const theme = useTheme();
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(() => {
const hideExpirationTime = Number(localStorage.getItem("hideAmoTokenExpiredDialogExpirationTime"));
if (hideExpirationTime && hideExpirationTime > Date.now()) return false;
return initialOpen;
});
const tryShowAmoTokenExpiredDialog = useUiTools((state) => state.tryShowAmoTokenExpiredDialog);
const [isHideDialogForADayChecked, setIsHideDialogForADayChecked] = useState<boolean>(false);
const location = useLocation();
const onAmoClick = async () => {
const [url, error] = await connectAmo();
@ -32,12 +31,16 @@ export default function AmoTokenExpiredDialog({ initialOpen }: Props) {
localStorage.setItem("hideAmoTokenExpiredDialogExpirationTime", expirationDate.toString());
}
setIsDialogOpen(false);
setTryShowAmoTokenExpiredDialog(false);
}
useEffect(() => {
setTryShowAmoTokenExpiredDialog(true);
}, [location]);
return (
<Dialog
open={isDialogOpen}
open={isAmoTokenExpired && tryShowAmoTokenExpiredDialog}
onClose={handleDialogClose}
PaperProps={{
sx: {
@ -103,9 +106,7 @@ export default function AmoTokenExpiredDialog({ initialOpen }: Props) {
<CustomCheckbox
label={"Не показывать сутки"}
checked={isHideDialogForADayChecked}
handleChange={({ target }) => {
setIsHideDialogForADayChecked(target.checked);
}}
handleChange={({ target }) => setIsHideDialogForADayChecked(target.checked)}
/>
</Box>
</Dialog>

@ -43,7 +43,6 @@ export default function EditPage({
setScrollDown,
}: Props) {
const quiz = useCurrentQuiz();
const { data: amoAccount } = useAmoAccount();
const { editQuizId } = useQuizStore();
const { questions } = useQuestionsStore();
const { showConfirmLeaveModal, nextStep } = useUiTools();
@ -108,7 +107,6 @@ export default function EditPage({
return (
<>
{amoAccount && <AmoTokenExpiredDialog initialOpen={amoAccount.stale} />}
<Box
sx={{
display: isMobile ? "block" : "flex",

@ -28,27 +28,27 @@ export const updateEditSomeQuestion = (contentId?: string) => {
export const updateOpenedModalSettingsId = (id?: string) =>
useUiTools.setState({ openedModalSettingsId: id ? id : null });
export const updateCanCreatePublic = (can: boolean) =>
useUiTools.setState({ canCreatePublic: can });
export const updateCanCreatePublic = (can: boolean) => useUiTools.setState({ canCreatePublic: can });
export const updateModalInfoWhyCantCreate = (can: boolean) =>
useUiTools.setState({ openModalInfoWhyCantCreate: can });
export const updateDeleteId = (deleteNodeId: string | null = null) =>
useUiTools.setState({ deleteNodeId });
export const updateModalInfoWhyCantCreate = (can: boolean) => useUiTools.setState({ openModalInfoWhyCantCreate: can });
export const updateDeleteId = (deleteNodeId: string | null = null) => useUiTools.setState({ deleteNodeId });
export const setShowConfirmLeaveModal = (showConfirmLeaveModal: boolean) =>
useUiTools.setState({ showConfirmLeaveModal });
export const updateSomeWorkBackend = (someWorkBackend: boolean) =>
useUiTools.setState({ someWorkBackend });
export const updateSomeWorkBackend = (someWorkBackend: boolean) => useUiTools.setState({ someWorkBackend });
export const updateNextStep = (nextStep: number) =>
useUiTools.setState({ nextStep });
export const updateNextStep = (nextStep: number) => useUiTools.setState({ nextStep });
export const setModalQuestionParentContentId = (
modalQuestionParentContentId: string,
) => useUiTools.setState({ modalQuestionParentContentId });
export const setModalQuestionTargetContentId = (
modalQuestionTargetContentId: string,
) => useUiTools.setState({ modalQuestionTargetContentId });
export const setOpenedModalQuestions = (open: boolean) =>
useUiTools.setState({ openedModalQuestions: open });
export const setModalQuestionParentContentId = (modalQuestionParentContentId: string) =>
useUiTools.setState({ modalQuestionParentContentId });
export const setModalQuestionTargetContentId = (modalQuestionTargetContentId: string) =>
useUiTools.setState({ modalQuestionTargetContentId });
export const setOpenedModalQuestions = (open: boolean) => useUiTools.setState({ openedModalQuestions: open });
export const setTryShowAmoTokenExpiredDialog = (tryShowAmoTokenExpiredDialog: boolean) => {
const hideExpirationTime = Number(localStorage.getItem("hideAmoTokenExpiredDialogExpirationTime"));
useUiTools.setState({
tryShowAmoTokenExpiredDialog: hideExpirationTime > Date.now() ? false : tryShowAmoTokenExpiredDialog,
});
};

@ -16,6 +16,7 @@ export type UiTools = {
modalQuestionParentContentId: string;
modalQuestionTargetContentId: string;
openedModalQuestions: boolean;
tryShowAmoTokenExpiredDialog: boolean;
};
export type WhyCantCreatePublic = {
@ -23,6 +24,9 @@ export type WhyCantCreatePublic = {
problems: string[];
};
const hideAmoTokenExpiredDialogExpirationTime = Number(localStorage.getItem("hideAmoTokenExpiredDialogExpirationTime"));
const tryShowAmoTokenExpiredDialog = hideAmoTokenExpiredDialogExpirationTime > Date.now() ? false : true;
const initialState: UiTools = {
openedModalSettingsId: null as null,
dragQuestionContentId: null,
@ -38,6 +42,7 @@ const initialState: UiTools = {
modalQuestionParentContentId: "",
modalQuestionTargetContentId: "",
openedModalQuestions: false,
tryShowAmoTokenExpiredDialog,
};
export const useUiTools = create<UiTools>()(
@ -45,5 +50,5 @@ export const useUiTools = create<UiTools>()(
name: "UiTools",
enabled: process.env.NODE_ENV === "development",
trace: process.env.NODE_ENV === "development",
}),
})
);

@ -11,7 +11,7 @@ import MenuItem from "../MenuItem";
import { useCurrentQuiz } from "@root/quizes/hooks";
import { useLocation, useNavigate } from "react-router-dom";
import { setCurrentStep } from "@root/quizes/actions";
import { updateNextStep } from "@root/uiTools/actions";
import { setTryShowAmoTokenExpiredDialog, updateNextStep } from "@root/uiTools/actions";
const quizSettingsMenuItems = [
[TagIcon, "Дополнения"],
@ -40,6 +40,7 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
updateNextStep(index);
changePage(index);
setTryShowAmoTokenExpiredDialog(true);
};
const handleMenuCollapseToggle = () => setIsMenuCollapsed((prev) => !prev);
@ -109,13 +110,7 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
text={menuItem.sidebarText}
isCollapsed={isMenuCollapsed}
isActive={currentStep === index && pathname.startsWith("/edit")}
disabled={
pathname.startsWith("/edit")
? false
: quiz === undefined
? true
: quiz?.config.type === null
}
disabled={pathname.startsWith("/edit") ? false : quiz === undefined ? true : quiz?.config.type === null}
icon={
<Icon
color={
@ -153,17 +148,12 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
onClick={() => {
navigate("/design");
setCurrentStep(15);
setTryShowAmoTokenExpiredDialog(true);
}}
text={"Дизайн"}
isCollapsed={isMenuCollapsed}
isActive={pathname.startsWith("/design")}
disabled={
pathname.startsWith("/design")
? false
: quiz === undefined
? true
: quiz?.config.type === null
}
disabled={pathname.startsWith("/design") ? false : quiz === undefined ? true : quiz?.config.type === null}
icon={
<PencilCircleIcon
color={
@ -182,16 +172,13 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
onClick={() => {
navigate("/integrations");
setCurrentStep(16);
setTryShowAmoTokenExpiredDialog(true);
}}
text={"Интеграции"}
isCollapsed={isMenuCollapsed}
isActive={pathname.startsWith("/integrations")}
disabled={
pathname.startsWith("/integrations")
? false
: quiz === undefined
? true
: quiz?.config.type === null
pathname.startsWith("/integrations") ? false : quiz === undefined ? true : quiz?.config.type === null
}
icon={
<PuzzlePieceIcon

@ -1,13 +1,5 @@
import React, { ChangeEvent, FC, useEffect, useRef, useState } from "react";
import {
Box,
FormControl,
IconButton,
TextField,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { Box, FormControl, IconButton, TextField, Typography, useMediaQuery, useTheme } from "@mui/material";
import { SidebarModal } from "./SidebarModal";
@ -21,7 +13,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
import { LogoutButton } from "@ui_kit/LogoutButton";
import PencilCircleIcon from "@icons/PencilCircleIcon";
import { quizSetupSteps } from "@model/quizSettings";
import { updateNextStep } from "@root/uiTools/actions";
import { setTryShowAmoTokenExpiredDialog, updateNextStep } from "@root/uiTools/actions";
import { handleLogoutClick } from "@utils/HandleLogoutClick";
interface SidebarIconProps {
@ -37,12 +29,7 @@ interface Iprops {
scrollDown: boolean;
}
export const SidebarMobile: FC<Iprops> = ({
open,
changePage,
setHeightSitebar,
scrollDown,
}) => {
export const SidebarMobile: FC<Iprops> = ({ open, changePage, setHeightSitebar, scrollDown }) => {
const theme = useTheme();
const isWrappSidebar = useMediaQuery(theme.breakpoints.down(400));
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@ -58,7 +45,7 @@ export const SidebarMobile: FC<Iprops> = ({
new ResizeObserver((entries) => {
const { height } = entries[0].contentRect;
setHeightSitebar(height);
}),
})
);
useEffect(() => {
@ -72,8 +59,7 @@ export const SidebarMobile: FC<Iprops> = ({
};
const clickInput = (event: MouseEvent) => {
if (ref.current && !ref.current?.contains(event.target as Node))
setInputOpen(false);
if (ref.current && !ref.current?.contains(event.target as Node)) setInputOpen(false);
};
useEffect(() => {
document.addEventListener("mousedown", clickInput);
@ -89,6 +75,7 @@ export const SidebarMobile: FC<Iprops> = ({
updateNextStep(index);
changePage(index);
setTryShowAmoTokenExpiredDialog(true);
};
const openPopper = Boolean(anchorEl);
const id = openPopper ? "simple-popper" : "";
@ -130,11 +117,12 @@ export const SidebarMobile: FC<Iprops> = ({
}}
>
<Box>
<Typography sx={{ fontSize: "12px", color: "#9A9AAF" }}>
Название
</Typography>
<Typography sx={{ fontSize: "12px", color: "#9A9AAF" }}>Название</Typography>
{inputOpen ? (
<FormControl fullWidth variant="standard">
<FormControl
fullWidth
variant="standard"
>
<TextField
ref={ref}
value={inputValue}
@ -173,12 +161,18 @@ export const SidebarMobile: FC<Iprops> = ({
/>
</FormControl>
) : (
<Typography color={"white"} sx={{ wordBreak: "break-word" }}>
<Typography
color={"white"}
sx={{ wordBreak: "break-word" }}
>
{quiz.name}
</Typography>
)}
</Box>
<IconButton onClick={() => setInputOpen(true)} sx={{ mt: "10px" }}>
<IconButton
onClick={() => setInputOpen(true)}
sx={{ mt: "10px" }}
>
<Pencil
style={{
position: "absolute",
@ -242,20 +236,18 @@ export const SidebarMobile: FC<Iprops> = ({
borderRadius: "8px",
}}
>
{React.createElement(
sidebarIcon as React.FC<SidebarIconProps>,
{
height: isWrappSidebar ? "25px" : "32px",
width: isWrappSidebar ? "25px" : "32px",
color: `${theme.palette.brightPurple.main}`,
},
)}
{React.createElement(sidebarIcon as React.FC<SidebarIconProps>, {
height: isWrappSidebar ? "25px" : "32px",
width: isWrappSidebar ? "25px" : "32px",
color: `${theme.palette.brightPurple.main}`,
})}
</Box>
))}
<Box
onClick={() => {
navigate("/design");
setCurrentStep(15);
setTryShowAmoTokenExpiredDialog(true);
}}
sx={{
cursor: "pointer",
@ -293,9 +285,7 @@ export const SidebarMobile: FC<Iprops> = ({
marginLeft: "0",
}}
>
<Settings
style={{ color: "#974BFA", fontSize: "24px", marginLeft: "5px" }}
/>
<Settings style={{ color: "#974BFA", fontSize: "24px", marginLeft: "5px" }} />
<ArrowDown style={{ color: "#F2F3F7" }} />
</Box>
</Box>