fix: SidebarMobile

This commit is contained in:
IlyaDoronin 2023-12-29 13:17:43 +03:00
parent c9c344c737
commit 1d912c70e8
4 changed files with 192 additions and 146 deletions

@ -12,8 +12,12 @@ import {
useMediaQuery, useMediaQuery,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { addQuestionVariant, deleteQuestionVariant, setQuestionVariantField } from "@root/questions/actions"; import {
import type { KeyboardEvent, ReactNode } from "react"; addQuestionVariant,
deleteQuestionVariant,
setQuestionVariantField,
} from "@root/questions/actions";
import type { ChangeEvent, KeyboardEvent, ReactNode } from "react";
import { useState } from "react"; import { useState } from "react";
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import type { QuestionVariant } from "../../../model/questionTypes/shared"; import type { QuestionVariant } from "../../../model/questionTypes/shared";
@ -78,28 +82,37 @@ export const AnswerItem = ({
focused={false} focused={false}
placeholder={"Добавьте ответ"} placeholder={"Добавьте ответ"}
multiline={largeCheck} multiline={largeCheck}
onChange={({ target }) => { onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
setQuestionVariantAnswer(target.value || " "); setQuestionVariantAnswer(target.value || " ");
}} }}
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => { onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
// if (disableKeyDown) { if (disableKeyDown) {
// enqueueSnackbar("100 максимальное количество вопросов"); enqueueSnackbar("100 максимальное количество вопросов");
// } else if (event.code === "Enter" && !largeCheck) { } else if (event.code === "Enter" && !largeCheck) {
addQuestionVariant(questionId); addQuestionVariant(questionId);
// } }
}} }}
InputProps={{ InputProps={{
startAdornment: ( startAdornment: (
<> <>
<InputAdornment {...provided.dragHandleProps} position="start"> <InputAdornment
<PointsIcon style={{ color: "#9A9AAF", fontSize: "30px" }} /> {...provided.dragHandleProps}
position="start"
>
<PointsIcon
style={{ color: "#9A9AAF", fontSize: "30px" }}
/>
</InputAdornment> </InputAdornment>
{additionalContent} {additionalContent}
</> </>
), ),
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
<IconButton sx={{ padding: "0" }} aria-describedby="my-popover-id" onClick={handleClick}> <IconButton
sx={{ padding: "0" }}
aria-describedby="my-popover-id"
onClick={handleClick}
>
<MessageIcon <MessageIcon
style={{ style={{
color: "#9A9AAF", color: "#9A9AAF",
@ -119,11 +132,20 @@ export const AnswerItem = ({
style={{ margin: "10px" }} style={{ margin: "10px" }}
placeholder="Подсказка для этого ответа" placeholder="Подсказка для этого ответа"
value={variant.hints} value={variant.hints}
onChange={(e) => setQuestionVariantAnswer(e.target.value || " ")} onChange={(e) =>
onKeyDown={(event: KeyboardEvent<HTMLTextAreaElement>) => event.stopPropagation()} setQuestionVariantAnswer(e.target.value || " ")
}
onKeyDown={(
event: KeyboardEvent<HTMLTextAreaElement>
) => event.stopPropagation()}
/> />
</Popover> </Popover>
<IconButton sx={{ padding: "0" }} onClick={() => deleteQuestionVariant(questionId, variant.id)}> <IconButton
sx={{ padding: "0" }}
onClick={() =>
deleteQuestionVariant(questionId, variant.id)
}
>
<DeleteIcon <DeleteIcon
style={{ style={{
color: theme.palette.grey2.main, color: theme.palette.grey2.main,

@ -18,7 +18,13 @@ import {
useMediaQuery, useMediaQuery,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { decrementCurrentStep, resetEditConfig, setQuizes, updateQuiz, setCurrentStep } from "@root/quizes/actions"; import {
decrementCurrentStep,
resetEditConfig,
setQuizes,
updateQuiz,
setCurrentStep,
} from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuizStore } from "@root/quizes/store"; import { useQuizStore } from "@root/quizes/store";
import CustomAvatar from "@ui_kit/Header/Avatar"; import CustomAvatar from "@ui_kit/Header/Avatar";
@ -34,7 +40,11 @@ import { Link, useNavigate } from "react-router-dom";
import useSWR from "swr"; import useSWR from "swr";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import { SidebarMobile } from "./Sidebar/SidebarMobile"; import { SidebarMobile } from "./Sidebar/SidebarMobile";
import { cleanQuestions, createResult, setQuestions } from "@root/questions/actions"; import {
cleanQuestions,
createResult,
setQuestions,
} from "@root/questions/actions";
import { import {
updateOpenBranchingPanel, updateOpenBranchingPanel,
updateCanCreatePublic, updateCanCreatePublic,
@ -82,7 +92,9 @@ export default function EditPage() {
if ( if (
!questions?.find( !questions?.find(
(q) => (q.type === "result" && q.content.includes(':"line"')) || q.content.includes(":'line'") (q) =>
(q.type === "result" && q.content.includes(':"line"')) ||
q.content.includes(":'line'")
) )
) { ) {
createResult(quiz?.backendId, "line"); createResult(quiz?.backendId, "line");
@ -93,7 +105,12 @@ export default function EditPage() {
getData(); getData();
}, []); }, []);
const { openBranchingPanel, whyCantCreatePublic, canCreatePublic, showConfirmLeaveModal } = useUiTools(); const {
openBranchingPanel,
whyCantCreatePublic,
canCreatePublic,
showConfirmLeaveModal,
} = useUiTools();
const theme = useTheme(); const theme = useTheme();
const navigate = useNavigate(); const navigate = useNavigate();
const currentStep = useQuizStore((state) => state.currentStep); const currentStep = useQuizStore((state) => state.currentStep);
@ -107,7 +124,6 @@ export default function EditPage() {
const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false); const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false);
const [buttonText, setButtonText] = useState("Опубликовать"); const [buttonText, setButtonText] = useState("Опубликовать");
const openBranchingPageHC = () => { const openBranchingPageHC = () => {
if (!openBranchingPage) { if (!openBranchingPage) {
deleteTimeoutedQuestions(questions, quiz); deleteTimeoutedQuestions(questions, quiz);
@ -124,23 +140,26 @@ export default function EditPage() {
resetEditConfig(); resetEditConfig();
cleanQuestions(); cleanQuestions();
updateModalInfoWhyCantCreate(false); updateModalInfoWhyCantCreate(false);
updateSomeWorkBackend(false) updateSomeWorkBackend(false);
}, },
[] []
); );
const updateQuestionHint = useDebouncedCallback((questions: AnyTypedQuizQuestion[]) => { const updateQuestionHint = useDebouncedCallback(
const problems = checkQuestionHint(questions, quiz); (questions: AnyTypedQuizQuestion[]) => {
useUiTools.setState({ whyCantCreatePublic: problems }); const problems = checkQuestionHint(questions, quiz);
if (Object.keys(problems).length > 0) { useUiTools.setState({ whyCantCreatePublic: problems });
updateQuiz(quiz?.id, (state) => { if (Object.keys(problems).length > 0) {
state.status = "stop"; updateQuiz(quiz?.id, (state) => {
}); state.status = "stop";
updateCanCreatePublic(false); });
} else { updateCanCreatePublic(false);
updateCanCreatePublic(true); } else {
} updateCanCreatePublic(true);
}, 600); }
},
600
);
useEffect(() => { useEffect(() => {
updateQuestionHint(questions); updateQuestionHint(questions);
@ -165,9 +184,11 @@ export default function EditPage() {
if (!quizConfig) return <></>; if (!quizConfig) return <></>;
const isConditionMet = [1].includes(currentStep) && !openBranchingPanel && quizConfig.type !== "form"; const isConditionMet =
[1].includes(currentStep) &&
!openBranchingPanel &&
quizConfig.type !== "form";
const handleClickStatusQuiz = () => { const handleClickStatusQuiz = () => {
if (Object.keys(whyCantCreatePublic).length === 0) { if (Object.keys(whyCantCreatePublic).length === 0) {
if (buttonText === "Опубликовать") { if (buttonText === "Опубликовать") {
@ -187,6 +208,17 @@ export default function EditPage() {
} }
}; };
const changePage = (index: number) => {
if (currentStep === 2) {
setNextStep(index);
setShowConfirmLeaveModal(true);
return;
}
setCurrentStep(index);
};
return ( return (
<> <>
{/*хедер*/} {/*хедер*/}
@ -221,12 +253,12 @@ export default function EditPage() {
</Link> </Link>
<FormControl fullWidth variant="standard"> <FormControl fullWidth variant="standard">
<TextField <TextField
value={quiz.name} value={quiz.name}
onChange={(e) => onChange={(e) =>
updateQuiz(quiz.id, (quiz) => { updateQuiz(quiz.id, (quiz) => {
quiz.name = e.target.value; quiz.name = e.target.value;
}) })
} }
fullWidth fullWidth
id="project-name" id="project-name"
placeholder="Название проекта окно" placeholder="Название проекта окно"
@ -321,7 +353,11 @@ export default function EditPage() {
display: isMobile ? "block" : "flex", display: isMobile ? "block" : "flex",
}} }}
> >
{isMobile ? <SidebarMobile open={mobileSidebar} /> : <Sidebar setNextStep={setNextStep} />} {isMobile ? (
<SidebarMobile open={mobileSidebar} changePage={changePage} />
) : (
<Sidebar changePage={changePage} />
)}
<Box <Box
sx={{ sx={{
background: theme.palette.background.default, background: theme.palette.background.default,
@ -333,7 +369,9 @@ export default function EditPage() {
sx={{ sx={{
padding: isMobile ? "16px 16px 20px 16px" : "25px 25px 20px 25px", padding: isMobile ? "16px 16px 20px 16px" : "25px 25px 20px 25px",
overflow: "auto", overflow: "auto",
height: isMobile ? ` calc(100vh - 125px) ` : `calc(100vh - ${isConditionMet ? "186px" : "166px"})`, height: isMobile
? ` calc(100vh - 125px) `
: `calc(100vh - ${isConditionMet ? "186px" : "166px"})`,
boxSizing: "border-box", boxSizing: "border-box",
}} }}
> >
@ -357,7 +395,11 @@ export default function EditPage() {
width: "100%", width: "100%",
padding: isMobile ? "20px 16px" : "20px 20px", padding: isMobile ? "20px 16px" : "20px 20px",
display: "flex", display: "flex",
justifyContent: isMobile ? (isMobileSm ? "center" : "flex-end") : "flex-start", justifyContent: isMobile
? isMobileSm
? "center"
: "flex-end"
: "flex-start",
flexDirection: isMobile ? "row-reverse" : "-moz-initial", flexDirection: isMobile ? "row-reverse" : "-moz-initial",
alignItems: "center", alignItems: "center",
gap: "15px", gap: "15px",
@ -398,7 +440,10 @@ export default function EditPage() {
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 }, "&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
}, },
"&.Mui-disabled .MuiSwitch-thumb": { "&.Mui-disabled .MuiSwitch-thumb": {
color: theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[600], color:
theme.palette.mode === "light"
? theme.palette.grey[100]
: theme.palette.grey[600],
}, },
"&.Mui-disabled + .MuiSwitch-track": { "&.Mui-disabled + .MuiSwitch-track": {
opacity: theme.palette.mode === "light" ? 0.7 : 0.3, opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
@ -411,16 +456,22 @@ export default function EditPage() {
}, },
"& .MuiSwitch-track": { "& .MuiSwitch-track": {
borderRadius: 13, borderRadius: 13,
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D", backgroundColor:
theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
opacity: 1, opacity: 1,
transition: theme.transitions.create(["background-color"], { transition: theme.transitions.create(
duration: 500, ["background-color"],
}), {
duration: 500,
}
),
}, },
}} }}
/> />
<Box> <Box>
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>Логика ветвления</Typography> <Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>
Логика ветвления
</Typography>
</Box> </Box>
</Box> </Box>
)} )}
@ -437,13 +488,20 @@ export default function EditPage() {
minWidth: "130px", minWidth: "130px",
}} }}
onClick={() => onClick={() =>
Object.keys(whyCantCreatePublic).length === 0 ? () => {} : updateModalInfoWhyCantCreate(true) Object.keys(whyCantCreatePublic).length === 0
? () => {}
: updateModalInfoWhyCantCreate(true)
} }
> >
Тестовый просмотр Тестовый просмотр
</Button> </Button>
) : ( ) : (
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}> <a
href={`/view`}
target="_blank"
rel="noreferrer"
style={{ textDecoration: "none" }}
>
<Button <Button
variant="contained" variant="contained"
sx={{ sx={{
@ -465,7 +523,8 @@ export default function EditPage() {
fontSize: "14px", fontSize: "14px",
lineHeight: "18px", lineHeight: "18px",
height: "34px", height: "34px",
background: buttonText === "Опубликовано" ? "#FA5B0E" : "#7E2AEA", background:
buttonText === "Опубликовано" ? "#FA5B0E" : "#7E2AEA",
}} }}
onClick={handleClickStatusQuiz} onClick={handleClickStatusQuiz}
> >

@ -11,9 +11,22 @@ import { ArrowDown } from "./icons/ArrowDown";
interface Iprops { interface Iprops {
open: boolean; open: boolean;
changePage: (step: number) => void;
} }
export const SidebarMobile: FC<Iprops> = ({ open }) => ( const quizSetupSteps = [
{ sidebarIcon: <Pencil style={{ color: "#974BFA", fontSize: "24px" }} /> },
{ sidebarIcon: <People style={{ color: "#974BFA", fontSize: "24px" }} /> },
{
sidebarIcon: <ChartLineUp style={{ color: "#974BFA", fontSize: "24px" }} />,
},
{
sidebarIcon: <ReturnTime style={{ color: "#974BFA", fontSize: "24px" }} />,
},
{ sidebarIcon: <Question style={{ color: "#974BFA", fontSize: "24px" }} /> },
] as const;
export const SidebarMobile: FC<Iprops> = ({ open, changePage }) => (
<Box <Box
sx={{ sx={{
display: open ? "block" : "none", display: open ? "block" : "none",
@ -31,89 +44,52 @@ export const SidebarMobile: FC<Iprops> = ({ open }) => (
<Box sx={{ ml: "15px", display: "flex", alignItems: "end" }}> <Box sx={{ ml: "15px", display: "flex", alignItems: "end" }}>
<Box> <Box>
<Typography sx={{ fontSize: "12px", color: "#9A9AAF" }}>Название</Typography> <Typography sx={{ fontSize: "12px", color: "#9A9AAF" }}>
<Typography sx={{ color: "#FFF", fontSize: "18px", fontWeight: "500" }}>Название проекта</Typography> Название
</Typography>
<Typography
sx={{ color: "#FFF", fontSize: "18px", fontWeight: "500" }}
>
Название проекта
</Typography>
</Box> </Box>
<Pencil style={{ position: "absolute", right: "0", color: "white", fontSize: "24px" }} /> <Pencil
style={{
position: "absolute",
right: "0",
color: "white",
fontSize: "24px",
}}
/>
</Box> </Box>
</Box> </Box>
<Box <Box
sx={{ width: "100%", justifyContent: "center", display: "flex", marginTop: "20px", flexWrap: "wrap", gap: "5px" }} sx={{
width: "100%",
justifyContent: "center",
display: "flex",
marginTop: "20px",
flexWrap: "wrap",
gap: "5px",
}}
> >
<Box {quizSetupSteps.map(({ sidebarIcon }, index) => (
sx={{ <Box
cursor: "pointer", onClick={() => changePage(index)}
width: "44px", sx={{
height: "44px", cursor: "pointer",
background: "#262835", width: "44px",
display: "flex", height: "44px",
justifyContent: "center", background: "#262835",
alignItems: "center", display: "flex",
borderRadius: "8px", justifyContent: "center",
}} alignItems: "center",
> borderRadius: "8px",
<Pencil style={{ color: "#974BFA", fontSize: "24px" }} /> }}
</Box> >
{sidebarIcon}
<Box </Box>
sx={{ ))}
cursor: "pointer",
width: "44px",
height: "44px",
background: "#262835",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
<People style={{ color: "#974BFA", fontSize: "24px" }} />
</Box>
<Box
sx={{
cursor: "pointer",
width: "44px",
height: "44px",
background: "#262835",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
<ChartLineUp style={{ color: "#974BFA", fontSize: "24px" }} />
</Box>
<Box
sx={{
cursor: "pointer",
width: "44px",
height: "44px",
background: "#262835",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
<ReturnTime style={{ color: "#974BFA", fontSize: "24px" }} />
</Box>
<Box
sx={{
cursor: "pointer",
width: "44px",
height: "44px",
background: "#262835",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
<Question style={{ color: "#974BFA", fontSize: "24px" }} />
</Box>
<Box <Box
sx={{ sx={{
@ -129,7 +105,9 @@ export const SidebarMobile: FC<Iprops> = ({ open }) => (
marginLeft: "28px", marginLeft: "28px",
}} }}
> >
<Settings style={{ color: "#974BFA", fontSize: "24px", marginLeft: "10px" }} /> <Settings
style={{ color: "#974BFA", fontSize: "24px", marginLeft: "10px" }}
/>
<ArrowDown style={{ color: "#F2F3F7" }} /> <ArrowDown style={{ color: "#F2F3F7" }} />
</Box> </Box>
</Box> </Box>

@ -5,12 +5,10 @@ import PuzzlePieceIcon from "@icons/PuzzlePieceIcon";
import TagIcon from "@icons/TagIcon"; import TagIcon from "@icons/TagIcon";
import { quizSetupSteps } from "@model/quizSettings"; import { quizSetupSteps } from "@model/quizSettings";
import { Box, IconButton, List, Typography, useTheme } from "@mui/material"; import { Box, IconButton, List, Typography, useTheme } from "@mui/material";
import { setCurrentStep } from "@root/quizes/actions";
import { useQuizStore } from "@root/quizes/store"; import { useQuizStore } from "@root/quizes/store";
import { useState } from "react"; import { useState } from "react";
import MenuItem from "./MenuItem"; import MenuItem from "./MenuItem";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { setShowConfirmLeaveModal } from "@root/uiTools/actions";
const quizSettingsMenuItems = [ const quizSettingsMenuItems = [
[TagIcon, "Дополнения"], [TagIcon, "Дополнения"],
@ -20,10 +18,10 @@ const quizSettingsMenuItems = [
] as const; ] as const;
type SidebarProps = { type SidebarProps = {
setNextStep: (step: number) => void; changePage: (step: number) => void;
}; };
export default function Sidebar({ setNextStep }: SidebarProps) { export default function Sidebar({ changePage }: SidebarProps) {
const theme = useTheme(); const theme = useTheme();
const [isMenuCollapsed, setIsMenuCollapsed] = useState(false); const [isMenuCollapsed, setIsMenuCollapsed] = useState(false);
const currentStep = useQuizStore((state) => state.currentStep); const currentStep = useQuizStore((state) => state.currentStep);
@ -31,17 +29,6 @@ export default function Sidebar({ setNextStep }: SidebarProps) {
const handleMenuCollapseToggle = () => setIsMenuCollapsed((prev) => !prev); const handleMenuCollapseToggle = () => setIsMenuCollapsed((prev) => !prev);
const changePage = (index: number) => {
if (currentStep === 2) {
setNextStep(index);
setShowConfirmLeaveModal(true);
return;
}
setCurrentStep(index);
};
return ( return (
<Box <Box
sx={{ sx={{