frontPanel/src/pages/startPage/EditPage.tsx

555 lines
19 KiB
TypeScript
Executable File
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 { quizApi } from "@api/quiz";
import { LogoutButton } from "@ui_kit/LogoutButton";
import BackArrowIcon from "@icons/BackArrowIcon";
import { Burger } from "@icons/Burger";
import EyeIcon from "@icons/EyeIcon";
import { PenaLogoIcon } from "@icons/PenaLogoIcon";
import VisibilityIcon from "@mui/icons-material/Visibility";
import {
Box,
Button,
Container,
FormControl,
IconButton,
Switch,
TextField,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { decrementCurrentStep, resetEditConfig, setQuizes, updateQuiz, setCurrentStep } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuizStore } from "@root/quizes/store";
import CustomAvatar from "@ui_kit/Header/Avatar";
import NavMenuItem from "@ui_kit/Header/NavMenuItem";
import PenaLogo from "@ui_kit/PenaLogo";
import Sidebar from "@ui_kit/Sidebar";
import Stepper from "@ui_kit/Stepper";
import SwitchStepPages from "@ui_kit/switchStepPages";
import { isAxiosError } from "axios";
import { enqueueSnackbar } from "notistack";
import React, { useEffect, useLayoutEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import useSWR from "swr";
import { useDebouncedCallback } from "use-debounce";
import { SidebarMobile } from "./Sidebar/SidebarMobile";
import { cleanQuestions, createResult, setQuestions } from "@root/questions/actions";
import {
updateOpenBranchingPanel,
updateCanCreatePublic,
updateModalInfoWhyCantCreate,
setShowConfirmLeaveModal,
updateSomeWorkBackend,
} from "@root/uiTools/actions";
import { BranchingPanel } from "../Questions/BranchingPanel";
import { useQuestionsStore } from "@root/questions/store";
import { useQuizes } from "@root/quizes/hooks";
import { questionApi } from "@api/question";
import { useUiTools } from "@root/uiTools/store";
import Logotip from "../Landing/images/icons/QuizLogo";
import { clearUserData } from "@root/user";
import { clearAuthToken } from "@frontend/kitui";
import { logout } from "@api/auth";
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate";
import { ConfirmLeaveModal } from "./ConfirmLeaveModal";
import { checkQuestionHint } from "@utils/checkQuestionHint";
import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions";
import { toggleQuizPreview } from "@root/quizPreview";
import { LinkSimple } from "@icons/LinkSimple";
import { BackButtonIcon } from "@icons/BackButtonIcon";
let init: () => void;
export default function EditPage() {
const quiz = useCurrentQuiz();
const { editQuizId } = useQuizStore();
const { questions } = useQuestionsStore();
console.log("quiz ", quiz);
console.log(questions);
useEffect(() => {
const getData = async () => {
const quizes = await quizApi.getList();
setQuizes(quizes);
if (editQuizId) {
const questions = await questionApi.getList({ quiz_id: editQuizId });
setQuestions(questions);
//Всегда должен существовать хоть 1 резулт - "line"
// console.log("сейчас будем ворошиться в этих квешенах ", questions);
if (
!questions?.find(
(q) => (q.type === "result" && q.content.includes(':"line"')) || q.content.includes(":'line'")
)
) {
createResult(quiz?.backendId, "line");
console.log("Я не нашёл линейный резулт и собираюсь создать новый");
}
}
};
getData();
}, []);
const { openBranchingPanel, whyCantCreatePublic, canCreatePublic, showConfirmLeaveModal } = useUiTools();
const theme = useTheme();
const navigate = useNavigate();
const currentStep = useQuizStore((state) => state.currentStep);
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(660));
const isMobileSm = useMediaQuery(theme.breakpoints.down(370));
const [mobileSidebar, setMobileSidebar] = useState<boolean>(false);
const [nextStep, setNextStep] = useState<number>(0);
const quizConfig = quiz?.config;
const disableTest = quiz === undefined ? true : quiz.config.type === null;
const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false);
const [buttonText, setButtonText] = useState("Опубликовать");
const openBranchingPageHC = () => {
if (!openBranchingPage) {
deleteTimeoutedQuestions(questions, quiz);
}
setOpenBranchingPage((old) => !old);
};
useEffect(() => {
if (editQuizId === null) navigate("/list");
}, [navigate, editQuizId]);
useEffect(
() => () => {
resetEditConfig();
cleanQuestions();
updateModalInfoWhyCantCreate(false);
updateSomeWorkBackend(false)
},
[]
);
const updateQuestionHint = useDebouncedCallback((questions: AnyTypedQuizQuestion[]) => {
const problems = checkQuestionHint(questions, quiz);
useUiTools.setState({ whyCantCreatePublic: problems });
if (Object.keys(problems).length > 0) {
updateQuiz(quiz?.id, (state) => {
state.status = "stop";
});
updateCanCreatePublic(false);
} else {
updateCanCreatePublic(true);
}
}, 600);
useEffect(() => {
updateQuestionHint(questions);
}, [questions]);
async function handleLogoutClick() {
const [, logoutError] = await logout();
if (logoutError) {
return enqueueSnackbar(logoutError);
}
clearAuthToken();
clearUserData();
navigate("/");
}
const followNewPage = () => {
setShowConfirmLeaveModal(false);
setCurrentStep(nextStep);
};
if (!quizConfig) return <></>;
const isConditionMet = [1].includes(currentStep) && !openBranchingPanel && quizConfig.type !== "form";
const handleClickStatusQuiz = () => {
if (Object.keys(whyCantCreatePublic).length === 0) {
if (buttonText === "Опубликовать") {
setButtonText("Опубликовано");
setTimeout(() => {
setButtonText("Отозвать");
}, 3000);
} else {
setButtonText("Опубликовать");
}
updateQuiz(quiz?.id, (state) => {
state.status = quiz?.status === "start" ? "stop" : "start";
});
} else {
updateModalInfoWhyCantCreate(true);
}
};
return (
<>
{/*хедер*/}
<Container
component="nav"
maxWidth={false}
disableGutters
sx={{
px: "16px",
display: "flex",
height: isMobile ? "51px" : "80px",
alignItems: "center",
bgcolor: isMobile ? "#333647" : "white",
borderBottom: "1px solid #E3E3E3",
zIndex: theme.zIndex.drawer + 1,
}}
>
<Link to="/" style={{ display: "flex" }}>
{isMobile ? <Logotip width={100} /> : <Logotip width={124} />}
</Link>
<Box
sx={{
display: isMobile ? "none" : "flex",
alignItems: "center",
ml: "37px",
}}
>
<Link to="/list">
<IconButton sx={{ p: "6px" }}>
<BackArrowIcon />
</IconButton>
</Link>
<FormControl fullWidth variant="standard">
<TextField
fullWidth
id="project-name"
placeholder="Название проекта окно"
sx={{
width: "270px",
"& .MuiInputBase-root": {
height: "34px",
borderRadius: "8px",
p: 0,
},
}}
inputProps={{
sx: {
height: "20px",
borderRadius: "8px",
fontSize: "16px",
lineHeight: "20px",
p: "7px",
color: "black",
"&::placeholder": {
opacity: 1,
},
},
}}
/>
</FormControl>
</Box>
{isTablet ? (
<Box
sx={{
display: "flex",
ml: "auto",
}}
>
{isMobile ? (
<Burger
onClick={() => setMobileSidebar(!mobileSidebar)}
style={{ fontSize: "30px", color: "white", cursor: "pointer" }}
/>
) : (
<Box>
<CustomAvatar
sx={{
ml: "11px",
backgroundColor: theme.palette.orange.main,
height: "36px",
width: "36px",
}}
/>
</Box>
)}
</Box>
) : (
<>
<Box
sx={{
display: "flex",
gap: "30px",
overflow: "hidden",
ml: "20px",
}}
>
<NavMenuItem text="Редактировать" isActive />
<NavMenuItem text="Заявки" />
<NavMenuItem text="Аналитика" />
<NavMenuItem text="История" />
<NavMenuItem text="Помощь" />
</Box>
<Box
sx={{
display: "flex",
ml: "auto",
gap: "15px",
}}
>
<CustomAvatar
sx={{
ml: "11px",
backgroundColor: theme.palette.orange.main,
height: "36px",
width: "36px",
}}
/>
<LogoutButton onClick={handleLogoutClick} />
</Box>
</>
)}
</Container>
<Box
sx={{
display: isMobile ? "block" : "flex",
}}
>
{isMobile ? <SidebarMobile open={mobileSidebar} /> : <Sidebar setNextStep={setNextStep} />}
<Box
sx={{
background: theme.palette.background.default,
width: "100%",
overflow: "hidden",
}}
>
<Box
sx={{
padding: isMobile ? "16px 16px 20px 16px" : "25px 25px 20px 25px",
overflow: "auto",
height: isMobile ? ` calc(100vh - 125px) ` : `calc(100vh - ${isConditionMet ? "186px" : "166px"})`,
boxSizing: "border-box",
}}
>
{/* Выбор текущей страницы редактирования чего-либо находится здесь */}
{quizConfig && (
<>
<Stepper activeStep={currentStep} />
<SwitchStepPages
activeStep={currentStep}
quizType={quizConfig.type}
quizResults={quizConfig.results}
quizStartPageType={quizConfig.startpageType}
openBranchingPage={openBranchingPage}
setOpenBranchingPage={setOpenBranchingPage}
/>
</>
)}
</Box>
<Box
sx={{
width: "100%",
padding: isMobile ? "20px 16px" : "20px 20px",
display: "flex",
justifyContent: isMobile ? (isMobileSm ? "center" : "flex-end") : "flex-start",
flexDirection: isMobile ? "row-reverse" : "-moz-initial",
alignItems: "center",
gap: "15px",
background: "#FFF",
}}
>
{isConditionMet && (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "15px",
padding: "18px",
background: "#fff",
borderRadius: "12px",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Switch
checked={openBranchingPage}
onChange={openBranchingPageHC}
sx={{
width: 50,
height: 30,
padding: 0,
"& .MuiSwitch-switchBase": {
padding: 0,
margin: "2px",
transitionDuration: "300ms",
"&.Mui-checked": {
transform: "translateX(20px)",
color: theme.palette.brightPurple.main,
"& + .MuiSwitch-track": {
backgroundColor: "#E8DCF9",
opacity: 1,
border: 0,
},
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
},
"&.Mui-disabled .MuiSwitch-thumb": {
color: theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[600],
},
"&.Mui-disabled + .MuiSwitch-track": {
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
},
},
"& .MuiSwitch-thumb": {
boxSizing: "border-box",
width: 25,
height: 25,
},
"& .MuiSwitch-track": {
borderRadius: 13,
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
opacity: 1,
transition: theme.transitions.create(["background-color"], {
duration: 500,
}),
},
}}
/>
<Box>
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>Логика ветвления</Typography>
</Box>
</Box>
)}
<Box sx={{ display: isMobile ? "none" : "block" }}>
{!canCreatePublic && quiz.config.type !== "form" ? (
<Button
variant="contained"
// disabled
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
minWidth: "130px",
}}
onClick={() =>
Object.keys(whyCantCreatePublic).length === 0 ? () => {} : updateModalInfoWhyCantCreate(true)
}
>
Тестовый просмотр
</Button>
) : (
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
minWidth: "130px",
}}
>
Тестовый просмотр
</Button>
</a>
)}
</Box>
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
background: quiz?.status === "start" ? "#7E2AEA" : "#FA5B0E",
}}
onClick={handleClickStatusQuiz}
>
{buttonText === "Отозвать" ? (
<Box sx={{ display: "flex", gap: "4px", alignItems: "center" }}>
{buttonText} <BackButtonIcon />
</Box>
) : (
buttonText
)}
</Button>
{quiz?.status === "start" && (
<Box
component={Link}
sx={{
display: isMobile ? "none" : "block",
color: "#7E2AEA",
fontSize: "14px",
}}
target="_blank"
to={"https://hbpn.link/" + quiz.qid}
>
https://hbpn.link/{quiz.qid}
</Box>
)}
{isMobile ? (
<Button
onClick={toggleQuizPreview}
variant="outlined"
sx={{
display: "flex",
gap: "4px",
fontSize: "14px",
lineHeight: "18px",
height: "34px",
border: "1px solid #7E2AEA",
color: "#7E2AEA",
background: "white",
p: "8px 14px",
}}
>
<EyeIcon />
Предпросмотр
</Button>
) : (
<IconButton
onClick={toggleQuizPreview}
sx={{
pointerEvents: "auto",
marginLeft: "auto",
position: "relative",
zIndex: "999999",
}}
>
<VisibilityIcon sx={{ height: "30px", width: "30px" }} />
</IconButton>
)}
{isMobile && quiz?.status === "start" && (
<Box
component={Link}
sx={{
cursor: "pointer",
width: "34px",
height: "34px",
color: "#7E2AEA",
fontSize: "14px",
display: "flex",
justifyContent: "center",
alignItems: "Center",
background: "#EEE4FC",
borderRadius: "8px",
}}
target="_blank"
to={"https://hbpn.link/" + quiz.qid}
>
<LinkSimple />
</Box>
)}
</Box>
</Box>
</Box>
<ModalInfoWhyCantCreate />
<ConfirmLeaveModal
open={showConfirmLeaveModal}
follow={followNewPage}
cancel={() => setShowConfirmLeaveModal(false)}
/>
</>
);
}