Merge branch 'dev' into style-previw
This commit is contained in:
commit
a6bd21d228
@ -1,72 +1,86 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import Box from '@mui/material/Box';
|
import Box from "@mui/material/Box";
|
||||||
import Button from '@mui/material/Button';
|
import Button from "@mui/material/Button";
|
||||||
import SectionStyled from './SectionStyled';
|
import SectionStyled from "./SectionStyled";
|
||||||
import NavMenuItem from "@ui_kit/Header/NavMenuItem";
|
import NavMenuItem from "@ui_kit/Header/NavMenuItem";
|
||||||
import QuizLogo from "./images/icons/QuizLogo";
|
import QuizLogo from "./images/icons/QuizLogo";
|
||||||
import { useMediaQuery, useTheme } from "@mui/material";
|
import { useMediaQuery, useTheme } from "@mui/material";
|
||||||
import { setIsContactFormOpen } from "../../stores/contactForm";
|
import { setIsContactFormOpen } from "../../stores/contactForm";
|
||||||
|
import { useUserStore } from "@root/user";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const buttonMenu = ['Меню 1', 'Меню 2', 'Меню 3', 'Меню 4', 'Меню 5', 'Меню 1', 'Меню 2']
|
const buttonMenu = ["Меню 1", "Меню 2", "Меню 3", "Меню 4", "Меню 5", "Меню 1", "Меню 2"];
|
||||||
|
|
||||||
export default function Component() {
|
export default function Component() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000))
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
const [select, setSelect] = React.useState(0)
|
const [select, setSelect] = React.useState(0);
|
||||||
return (
|
const userId = useUserStore((state) => state.userId);
|
||||||
<SectionStyled tag={'header'} bg={'#F2F3F7'} mwidth={'1160px'}
|
const navigate = useNavigate();
|
||||||
sxsect={{
|
|
||||||
minHeight: '80px',
|
|
||||||
borderBottom: '1px solid #E3E3E3',
|
|
||||||
position: "relative",
|
|
||||||
padding: isMobile ? "0 16px" : isTablet ? "0 40px" : 0,
|
|
||||||
zIndex: 3
|
|
||||||
}}
|
|
||||||
sxcont={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: 0
|
|
||||||
}}>
|
|
||||||
<QuizLogo width={isMobile ? 100 : 150} />
|
|
||||||
{/*<Box*/}
|
|
||||||
{/* sx={{*/}
|
|
||||||
{/* maxWidth: '595px',*/}
|
|
||||||
{/* width: '100%',*/}
|
|
||||||
{/* display: 'flex',*/}
|
|
||||||
{/* justifyContent: 'space-between',*/}
|
|
||||||
{/* flexWrap: 'wrap',*/}
|
|
||||||
{/* marginRight: "138px",*/}
|
|
||||||
|
|
||||||
{/* }}*/}
|
const onClick = () => (userId ? navigate("/list") : setIsContactFormOpen(true));
|
||||||
{/*>*/}
|
|
||||||
{/* {buttonMenu.map( (element, index) => (*/}
|
return (
|
||||||
{/* <NavMenuItem*/}
|
<SectionStyled
|
||||||
{/* text={element}*/}
|
tag={"header"}
|
||||||
{/* // component={Link}*/}
|
bg={"#F2F3F7"}
|
||||||
{/* // to={url}*/}
|
mwidth={"1160px"}
|
||||||
{/* key={index}*/}
|
sxsect={{
|
||||||
{/* onClick={() => {*/}
|
minHeight: "80px",
|
||||||
{/* setSelect(index);*/}
|
borderBottom: "1px solid #E3E3E3",
|
||||||
{/* }}*/}
|
position: "relative",
|
||||||
{/* isActive={select === index}*/}
|
padding: isMobile ? "0 16px" : isTablet ? "0 40px" : 0,
|
||||||
{/* />*/}
|
zIndex: 3,
|
||||||
{/* ))}*/}
|
}}
|
||||||
{/*</Box>*/}
|
sxcont={{
|
||||||
<Button variant="outlined"
|
display: "flex",
|
||||||
onClick={() => setIsContactFormOpen(true)}
|
justifyContent: "space-between",
|
||||||
sx={{
|
alignItems: "center",
|
||||||
color: 'black',
|
padding: 0,
|
||||||
border: '1px solid black',
|
}}
|
||||||
textTransform: 'none',
|
>
|
||||||
fontWeight: '400',
|
<QuizLogo width={isMobile ? 100 : 150} />
|
||||||
fontSize: '18px',
|
{/*<Box*/}
|
||||||
lineHeight: '24px',
|
{/* sx={{*/}
|
||||||
borderRadius: '8px',
|
{/* maxWidth: '595px',*/}
|
||||||
padding: '8px 17px',
|
{/* width: '100%',*/}
|
||||||
}}
|
{/* display: 'flex',*/}
|
||||||
>Предрегистрация</Button>
|
{/* justifyContent: 'space-between',*/}
|
||||||
</SectionStyled>
|
{/* flexWrap: 'wrap',*/}
|
||||||
)
|
{/* marginRight: "138px",*/}
|
||||||
}
|
|
||||||
|
{/* }}*/}
|
||||||
|
{/*>*/}
|
||||||
|
{/* {buttonMenu.map( (element, index) => (*/}
|
||||||
|
{/* <NavMenuItem*/}
|
||||||
|
{/* text={element}*/}
|
||||||
|
{/* // component={Link}*/}
|
||||||
|
{/* // to={url}*/}
|
||||||
|
{/* key={index}*/}
|
||||||
|
{/* onClick={() => {*/}
|
||||||
|
{/* setSelect(index);*/}
|
||||||
|
{/* }}*/}
|
||||||
|
{/* isActive={select === index}*/}
|
||||||
|
{/* />*/}
|
||||||
|
{/* ))}*/}
|
||||||
|
{/*</Box>*/}
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onClick}
|
||||||
|
sx={{
|
||||||
|
color: "black",
|
||||||
|
border: "1px solid black",
|
||||||
|
textTransform: "none",
|
||||||
|
fontWeight: "400",
|
||||||
|
fontSize: "18px",
|
||||||
|
lineHeight: "24px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
padding: "8px 17px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{userId ? "Войти" : " Регистрация / Войти"}
|
||||||
|
</Button>
|
||||||
|
</SectionStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,75 +1,82 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import Box from '@mui/material/Box';
|
import Box from "@mui/material/Box";
|
||||||
import Button from '@mui/material/Button';
|
import Button from "@mui/material/Button";
|
||||||
import {Typography, useMediaQuery, useTheme} from "@mui/material";
|
import { Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import abstraction from '../../assets/Quiz-main.png'
|
import abstraction from "../../assets/Quiz-main.png";
|
||||||
import SectionStyled from './SectionStyled';
|
import SectionStyled from "./SectionStyled";
|
||||||
import { Link, redirect } from 'react-router-dom';
|
import { Link, redirect, useNavigate } from "react-router-dom";
|
||||||
import {setIsContactFormOpen} from "@root/contactForm";
|
import { setIsContactFormOpen } from "@root/contactForm";
|
||||||
|
import { useUserStore } from "@root/user";
|
||||||
|
|
||||||
export default function Component() {
|
export default function Component() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000))
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
return(
|
const userId = useUserStore((state) => state.userId);
|
||||||
<SectionStyled tag={'section'} bg={'#f2f3f7'} mwidth={'1160px'}
|
const navigate = useNavigate();
|
||||||
sxsect={{
|
|
||||||
height: isMobile ? '702px' : (isTablet ? '986px' : '660px'),
|
|
||||||
}}
|
|
||||||
sxcont={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: isMobile ? "300px 16px 0 16px" : (isTablet ? "494px 40px 0 40px" : 0),
|
|
||||||
marginBottom: isMobile ? '55px' : (isTablet ? 0 : "55px"),
|
|
||||||
}}>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: '30px',
|
|
||||||
height: '100%',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: "flex-start",
|
|
||||||
position: 'relative',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant='h2'>
|
|
||||||
Pena Quiz
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
maxWidth: isTablet ? '715px' : '420px',
|
|
||||||
minHeight: '64px',
|
|
||||||
}}>
|
|
||||||
<Typography variant='body1'>
|
|
||||||
Помогаем посетителю оставить заявку. <br style={{display: isTablet ? 'flex' : "none"}}/> Готовые шаблоны квизов с легкой установкой на любой сайт и социальные сети
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
{/*<Link */}
|
|
||||||
{/* to="/list"*/}
|
|
||||||
{/* style={{textDecoration: "none"}}>*/}
|
|
||||||
<Button variant="contained"
|
|
||||||
onClick={() => setIsContactFormOpen(true)}
|
|
||||||
>
|
|
||||||
Попробуйте бесплатно
|
|
||||||
|
|
||||||
</Button>
|
|
||||||
{/*</Link>*/}
|
|
||||||
|
|
||||||
<Box
|
const tryItForFreeonClick = () => (userId ? navigate("/list") : setIsContactFormOpen(true));
|
||||||
component={"img"}
|
|
||||||
src={abstraction}
|
return (
|
||||||
sx={{
|
<SectionStyled
|
||||||
position: "absolute",
|
tag={"section"}
|
||||||
bottom: isMobile ? undefined : (isTablet? "138px" : "-291px"),
|
bg={"#f2f3f7"}
|
||||||
maxWidth: isMobile ? "403px" : "810px",
|
mwidth={"1160px"}
|
||||||
width: isMobile ? "100%" : undefined,
|
sxsect={{
|
||||||
left: isMobile ? "-20px" : (isTablet? "54px" : "401px"),
|
height: isMobile ? "702px" : isTablet ? "986px" : "660px",
|
||||||
top: isMobile ? "-345px" : undefined
|
}}
|
||||||
}}
|
sxcont={{
|
||||||
/>
|
display: "flex",
|
||||||
</Box>
|
justifyContent: "space-between",
|
||||||
</SectionStyled>
|
alignItems: "center",
|
||||||
)
|
padding: isMobile ? "300px 16px 0 16px" : isTablet ? "494px 40px 0 40px" : 0,
|
||||||
}
|
marginBottom: isMobile ? "55px" : isTablet ? 0 : "55px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "30px",
|
||||||
|
height: "100%",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h2">Pena Quiz</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
maxWidth: isTablet ? "715px" : "420px",
|
||||||
|
minHeight: "64px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body1">
|
||||||
|
Помогаем посетителю оставить заявку. <br style={{ display: isTablet ? "flex" : "none" }} /> Готовые шаблоны
|
||||||
|
квизов с легкой установкой на любой сайт и социальные сети
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{/*<Link */}
|
||||||
|
{/* to="/list"*/}
|
||||||
|
{/* style={{textDecoration: "none"}}>*/}
|
||||||
|
<Button variant="contained" onClick={tryItForFreeonClick}>
|
||||||
|
Попробуйте бесплатно
|
||||||
|
</Button>
|
||||||
|
{/*</Link>*/}
|
||||||
|
|
||||||
|
<Box
|
||||||
|
component={"img"}
|
||||||
|
src={abstraction}
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: isMobile ? undefined : isTablet ? "138px" : "-291px",
|
||||||
|
maxWidth: isMobile ? "403px" : "810px",
|
||||||
|
width: isMobile ? "100%" : undefined,
|
||||||
|
left: isMobile ? "-20px" : isTablet ? "54px" : "401px",
|
||||||
|
top: isMobile ? "-345px" : undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</SectionStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -216,6 +216,7 @@ function CsComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
||||||
const deleteNodes = [] as string[]
|
const deleteNodes = [] as string[]
|
||||||
const deleteEdges: any = []
|
const deleteEdges: any = []
|
||||||
@ -331,6 +332,7 @@ function CsComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (startCreate) {
|
if (startCreate) {
|
||||||
addNode({ parentNodeContentId: startCreate });
|
addNode({ parentNodeContentId: startCreate });
|
||||||
@ -348,7 +350,6 @@ function CsComponent({
|
|||||||
|
|
||||||
|
|
||||||
const readyLO = (e) => {
|
const readyLO = (e) => {
|
||||||
console.log('REAdy')
|
|
||||||
if (e.cy.data('firstNode') === 'nonroot') {
|
if (e.cy.data('firstNode') === 'nonroot') {
|
||||||
e.cy.data('firstNode', 'root')
|
e.cy.data('firstNode', 'root')
|
||||||
e.cy.nodes().sort((a, b) => (a.data('root') ? 1 : -1)).layout(lyopts).run()
|
e.cy.nodes().sort((a, b) => (a.data('root') ? 1 : -1)).layout(lyopts).run()
|
||||||
@ -433,7 +434,6 @@ function CsComponent({
|
|||||||
task.task.forEach(n => {
|
task.task.forEach(n => {
|
||||||
const width = n.data('subtreeWidth')
|
const width = n.data('subtreeWidth')
|
||||||
|
|
||||||
console.log('ORORORORO', n.data(), yoffset, width, oldPos, task.parent.data('subtreeWidth'))
|
|
||||||
n.data('oldPos', { x: 250 * n.data('layer'), y: yoffset + width / 2 })
|
n.data('oldPos', { x: 250 * n.data('layer'), y: yoffset + width / 2 })
|
||||||
yoffset += width
|
yoffset += width
|
||||||
queue.push({ task: n.cy().edges(`[source="${n.id()}"]`).targets(), parent: n })
|
queue.push({ task: n.cy().edges(`[source="${n.id()}"]`).targets(), parent: n })
|
||||||
@ -462,7 +462,6 @@ function CsComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('KEKEKE')
|
|
||||||
document.querySelector("#root")?.addEventListener("mouseup", cleardragQuestionContentId);
|
document.querySelector("#root")?.addEventListener("mouseup", cleardragQuestionContentId);
|
||||||
const cy = cyRef.current;
|
const cy = cyRef.current;
|
||||||
const eles = cy?.add(storeToNodes(questions.filter((question: AnyTypedQuizQuestion) => (question.type !== "result" && question.type !== null))))
|
const eles = cy?.add(storeToNodes(questions.filter((question: AnyTypedQuizQuestion) => (question.type !== "result" && question.type !== null))))
|
||||||
@ -510,7 +509,6 @@ function CsComponent({
|
|||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('POP')
|
|
||||||
|
|
||||||
container.style.overflow = "hidden";
|
container.style.overflow = "hidden";
|
||||||
|
|
||||||
@ -540,7 +538,6 @@ function CsComponent({
|
|||||||
const bb = n.boundingBox()
|
const bb = n.boundingBox()
|
||||||
return bb.x2 > ext.x1 && bb.x1 < ext.x2 && bb.y2 > ext.y1 && bb.y1 < ext.y2
|
return bb.x2 > ext.x1 && bb.x1 < ext.x2 && bb.y2 > ext.y1 && bb.y1 < ext.y2
|
||||||
})
|
})
|
||||||
console.log('POPE')
|
|
||||||
|
|
||||||
nodesInView
|
nodesInView
|
||||||
.toArray()
|
.toArray()
|
||||||
@ -553,7 +550,6 @@ function CsComponent({
|
|||||||
modifiers: [{ name: "flip", options: { boundary: node } }],
|
modifiers: [{ name: "flip", options: { boundary: node } }],
|
||||||
},
|
},
|
||||||
content: ([item]) => {
|
content: ([item]) => {
|
||||||
console.log('POPPER', item.id())
|
|
||||||
const itemId = item.id();
|
const itemId = item.id();
|
||||||
const itemElement = layoutsContainer.current?.querySelector(
|
const itemElement = layoutsContainer.current?.querySelector(
|
||||||
`.popper-layout[data-id='${itemId}']`
|
`.popper-layout[data-id='${itemId}']`
|
||||||
@ -583,7 +579,6 @@ function CsComponent({
|
|||||||
modifiers: [{ name: "flip", options: { boundary: node } }],
|
modifiers: [{ name: "flip", options: { boundary: node } }],
|
||||||
},
|
},
|
||||||
content: ([item]) => {
|
content: ([item]) => {
|
||||||
console.log('POPPER+', item.id())
|
|
||||||
const itemId = item.id();
|
const itemId = item.id();
|
||||||
const itemElement = plusesContainer.current?.querySelector(
|
const itemElement = plusesContainer.current?.querySelector(
|
||||||
`.popper-plus[data-id='${itemId}']`
|
`.popper-plus[data-id='${itemId}']`
|
||||||
@ -612,7 +607,6 @@ function CsComponent({
|
|||||||
modifiers: [{ name: "flip", options: { boundary: node } }],
|
modifiers: [{ name: "flip", options: { boundary: node } }],
|
||||||
},
|
},
|
||||||
content: ([item]) => {
|
content: ([item]) => {
|
||||||
console.log('POPPERx', item.id())
|
|
||||||
const itemId = item.id();
|
const itemId = item.id();
|
||||||
const itemElement = crossesContainer.current?.querySelector(
|
const itemElement = crossesContainer.current?.querySelector(
|
||||||
`.popper-cross[data-id='${itemId}']`
|
`.popper-cross[data-id='${itemId}']`
|
||||||
@ -636,18 +630,17 @@ function CsComponent({
|
|||||||
return crossElement;
|
return crossElement;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
let gearsPopper = null
|
||||||
const gearsPopper = node.popper({
|
console.log('POPE', node.data())
|
||||||
|
if (node.data().root !== true) {
|
||||||
|
gearsPopper = node.popper({
|
||||||
popper: {
|
popper: {
|
||||||
placement: "left",
|
placement: "left",
|
||||||
modifiers: [{ name: "flip", options: { boundary: node } }],
|
modifiers: [{ name: "flip", options: { boundary: node } }],
|
||||||
},
|
},
|
||||||
content: ([item]) => {
|
content: ([item]) => {
|
||||||
console.log('POPPERg', item.id())
|
console.log('PEPO', item.id())
|
||||||
const itemId = item.id();
|
const itemId = item.id();
|
||||||
if (item.cy().edges(`[target="${itemId}"]`).sources().length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemElement = gearsContainer.current?.querySelector(
|
const itemElement = gearsContainer.current?.querySelector(
|
||||||
`.popper-gear[data-id='${itemId}']`
|
`.popper-gear[data-id='${itemId}']`
|
||||||
@ -668,12 +661,11 @@ function CsComponent({
|
|||||||
return gearElement;
|
return gearElement;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
const update = async () => {
|
const update = async () => {
|
||||||
console.log('POPPERi=u', item.id())
|
|
||||||
await plusesPopper.update();
|
await plusesPopper.update();
|
||||||
await crossesPopper.update();
|
await crossesPopper.update();
|
||||||
await gearsPopper.update();
|
await gearsPopper?.update();
|
||||||
await layoutsPopper.update();
|
await layoutsPopper.update();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -696,6 +688,18 @@ function CsComponent({
|
|||||||
{ name: "offset", options: { offset: [0, -130 * zoom] } },
|
{ name: "offset", options: { offset: [0, -130 * zoom] } },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
plusesPopper.setOptions({
|
||||||
|
modifiers: [
|
||||||
|
{ name: "flip", options: { boundary: node } },
|
||||||
|
{ name: "offset", options: { offset: [0, 0 * zoom] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
gearsPopper?.setOptions({
|
||||||
|
modifiers: [
|
||||||
|
{ name: "flip", options: { boundary: node } },
|
||||||
|
{ name: "offset", options: { offset: [0, 0] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
layoutsContainer.current
|
layoutsContainer.current
|
||||||
?.querySelectorAll("#popper-layouts > .popper-layout")
|
?.querySelectorAll("#popper-layouts > .popper-layout")
|
||||||
@ -725,7 +729,7 @@ function CsComponent({
|
|||||||
element.style.borderRadius = `${6 * zoom}px`;
|
element.style.borderRadius = `${6 * zoom}px`;
|
||||||
});
|
});
|
||||||
|
|
||||||
gearsContainer.current
|
gearsContainer?.current
|
||||||
?.querySelectorAll("#popper-gears > .popper-gear")
|
?.querySelectorAll("#popper-gears > .popper-gear")
|
||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
const element = item as HTMLDivElement;
|
const element = item as HTMLDivElement;
|
||||||
@ -735,13 +739,13 @@ function CsComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
//node?.on("position", update);
|
//node?.on("position", update);
|
||||||
let pressed = false
|
let pressed = false
|
||||||
let hide = false
|
let hide = false
|
||||||
cy?.on('mousedown',() => {pressed = true})
|
cy?.on('mousedown', () => { pressed = true })
|
||||||
cy?.on('mouseup',() => {
|
cy?.on('mouseup', () => {
|
||||||
pressed = false
|
pressed = false
|
||||||
hide = false
|
hide = false
|
||||||
|
|
||||||
|
|
||||||
const gc = gearsContainer.current
|
const gc = gearsContainer.current
|
||||||
if (gc) gc.style.display = 'block'
|
if (gc) gc.style.display = 'block'
|
||||||
@ -751,23 +755,23 @@ let pressed = false
|
|||||||
if (pc) pc.style.display = 'block'
|
if (pc) pc.style.display = 'block'
|
||||||
if (xc) xc.style.display = 'block'
|
if (xc) xc.style.display = 'block'
|
||||||
if (lc) lc.style.display = 'block'
|
if (lc) lc.style.display = 'block'
|
||||||
update()
|
update()
|
||||||
})
|
})
|
||||||
|
|
||||||
cy?.on('mousemove',() => {
|
cy?.on('mousemove', () => {
|
||||||
if (pressed && !hide) {
|
if (pressed && !hide) {
|
||||||
hide = true
|
hide = true
|
||||||
const gc = gearsContainer.current
|
const gc = gearsContainer.current
|
||||||
if (gc) gc.style.display = 'none'
|
if (gc) gc.style.display = 'none'
|
||||||
const pc = plusesContainer.current
|
const pc = plusesContainer.current
|
||||||
const xc = crossesContainer.current
|
const xc = crossesContainer.current
|
||||||
const lc = layoutsContainer.current
|
const lc = layoutsContainer.current
|
||||||
if (pc) pc.style.display = 'none'
|
if (pc) pc.style.display = 'none'
|
||||||
if (xc) xc.style.display = 'none'
|
if (xc) xc.style.display = 'none'
|
||||||
if (lc) lc.style.display = 'block'
|
if (lc) lc.style.display = 'block'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cy?.on("zoom render", onZoom);
|
cy?.on("zoom render", onZoom);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -785,7 +789,7 @@ let pressed = false
|
|||||||
variant="text"
|
variant="text"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
||||||
//код сюда
|
cyRef.current?.fit()
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Box } from "@mui/material"
|
import { Box } from "@mui/material"
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { updateDragQuestionContentId, updateQuestion } from "@root/questions/actions"
|
import { deleteQuestion, updateDragQuestionContentId, updateQuestion } from "@root/questions/actions"
|
||||||
import { updateRootContentId } from "@root/quizes/actions"
|
import { updateRootContentId } from "@root/quizes/actions"
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks"
|
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||||
import { useQuestionsStore } from "@root/questions/store"
|
import { useQuestionsStore } from "@root/questions/store"
|
||||||
@ -11,8 +11,9 @@ interface Props {
|
|||||||
modalQuestionTargetContentId: string;
|
modalQuestionTargetContentId: string;
|
||||||
}
|
}
|
||||||
export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetContentId }: Props) => {
|
export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetContentId }: Props) => {
|
||||||
|
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const { dragQuestionContentId } = useQuestionsStore()
|
const { dragQuestionContentId, questions } = useQuestionsStore()
|
||||||
const Container = useRef<HTMLDivElement | null>(null);
|
const Container = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const modalOpen = () => setOpenedModalQuestions(true)
|
const modalOpen = () => setOpenedModalQuestions(true)
|
||||||
@ -22,6 +23,11 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
|||||||
if (dragQuestionContentId) {
|
if (dragQuestionContentId) {
|
||||||
updateRootContentId(quiz?.id, dragQuestionContentId)
|
updateRootContentId(quiz?.id, dragQuestionContentId)
|
||||||
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")
|
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")
|
||||||
|
//если были результаты - удалить
|
||||||
|
questions.forEach((q) => {
|
||||||
|
if (q.type === 'result') deleteQuestion(q.id)
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Нет информации о взятом опроснике")
|
enqueueSnackbar("Нет информации о взятом опроснике")
|
||||||
@ -44,6 +50,10 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
|||||||
if (modalQuestionTargetContentId) {
|
if (modalQuestionTargetContentId) {
|
||||||
updateRootContentId(quiz?.id, modalQuestionTargetContentId)
|
updateRootContentId(quiz?.id, modalQuestionTargetContentId)
|
||||||
updateQuestion(modalQuestionTargetContentId, (question) => question.content.rule.parentId = "root")
|
updateQuestion(modalQuestionTargetContentId, (question) => question.content.rule.parentId = "root")
|
||||||
|
//если были результаты - удалить
|
||||||
|
questions.forEach((q) => {
|
||||||
|
if (q.type === 'result') deleteQuestion(q.id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Нет информации о взятом опроснике")
|
enqueueSnackbar("Нет информации о взятом опроснике")
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { copyQuestion, deleteQuestion, updateOpenBranchingPanel, updateDesireToOpenABranchingModal } from "@root/questions/actions";
|
import { copyQuestion, deleteQuestion, updateOpenBranchingPanel, updateDesireToOpenABranchingModal, deleteQuestionWithTimeout } from "@root/questions/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
||||||
import Branching from "../../assets/icons/questionsPage/branching";
|
import Branching from "../../assets/icons/questionsPage/branching";
|
||||||
@ -40,10 +40,10 @@ export default function ButtonsOptions({
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920));
|
const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920));
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const { openBranchingPanel } = useQuestionsStore.getState()
|
const { openBranchingPanel, questions } = useQuestionsStore.getState();
|
||||||
|
|
||||||
const openedModal = () => {
|
const openedModal = () => {
|
||||||
updateOpenedModalSettingsId(question.id)
|
updateOpenedModalSettingsId(question.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -84,8 +84,8 @@ export default function ButtonsOptions({
|
|||||||
title: "Ветвление",
|
title: "Ветвление",
|
||||||
value: "branching",
|
value: "branching",
|
||||||
myFunc: (question) => {
|
myFunc: (question) => {
|
||||||
updateOpenBranchingPanel(true)
|
updateOpenBranchingPanel(true);
|
||||||
updateDesireToOpenABranchingModal(question.content.id)
|
updateDesireToOpenABranchingModal(question.content.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -161,7 +161,7 @@ export default function ButtonsOptions({
|
|||||||
<MiniButtonSetting
|
<MiniButtonSetting
|
||||||
key={title}
|
key={title}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openedModal()
|
openedModal();
|
||||||
// SSHC(value);
|
// SSHC(value);
|
||||||
// myFunc(question);
|
// myFunc(question);
|
||||||
}}
|
}}
|
||||||
@ -269,76 +269,67 @@ export default function ButtonsOptions({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{ borderRadius: "6px", padding: "2px" }}
|
sx={{ borderRadius: "6px", padding: "2px" }}
|
||||||
onClick={() => { // TODO
|
onClick={() => {
|
||||||
// const removedId = question.id;
|
const deleteFn = () => {
|
||||||
// if (question.deleteTimeoutId) {
|
if (question.type !== null) {
|
||||||
// clearTimeout(question.deleteTimeoutId);
|
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||||
// }
|
updateRootContentId(quiz.id, "");
|
||||||
|
clearRuleForAll();
|
||||||
// removeQuestion(quizId, totalIndex);
|
questions.forEach(q => {
|
||||||
|
if (q.type === "result") {
|
||||||
// const newTimeoutId = window.setTimeout(() => {
|
deleteQuestion(q.id);
|
||||||
// removeQuestionForce(quizId, removedId);
|
|
||||||
// }, 5000);
|
|
||||||
|
|
||||||
// updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
|
||||||
// ...question,
|
|
||||||
// deleteTimeoutId: newTimeoutId,
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (question.type !== null) {
|
|
||||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
|
||||||
updateRootContentId(quiz.id, "")
|
|
||||||
clearRuleForAll()
|
|
||||||
questions.forEach(q => {
|
|
||||||
if (q.type === "result") {
|
|
||||||
deleteQuestion(q.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
deleteQuestion(question.id);
|
|
||||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
|
||||||
const clearQuestions = [] as string[]
|
|
||||||
|
|
||||||
//записываем потомков , а их результаты удаляем
|
|
||||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
|
||||||
questions.forEach((targetQuestion) => {
|
|
||||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
|
||||||
if (targetQuestion.type === "result") {
|
|
||||||
deleteQuestion(targetQuestion.id);
|
|
||||||
} else {
|
|
||||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
|
||||||
getChildren(targetQuestion) //и ищем его потомков
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
deleteQuestion(question.id);
|
||||||
|
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||||
|
const clearQuestions = [] as string[];
|
||||||
|
|
||||||
|
//записываем потомков , а их результаты удаляем
|
||||||
|
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||||
|
questions.forEach((targetQuestion) => {
|
||||||
|
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||||
|
if (targetQuestion.type === "result") {
|
||||||
|
deleteQuestion(targetQuestion.id);
|
||||||
|
} else {
|
||||||
|
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
|
||||||
|
getChildren(targetQuestion); //и ищем его потомков
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
getChildren(question);
|
||||||
|
//чистим потомков от инфы ветвления
|
||||||
|
clearQuestions.forEach((id) => {
|
||||||
|
updateQuestion(id, question => {
|
||||||
|
question.content.rule.parentId = "";
|
||||||
|
question.content.rule.main = [];
|
||||||
|
question.content.rule.default = "";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//чистим rule родителя
|
||||||
|
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
|
||||||
|
const newRule = {};
|
||||||
|
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
|
||||||
|
newRule.parentId = parentQuestion.content.rule.parentId;
|
||||||
|
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId;
|
||||||
|
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||||
|
|
||||||
|
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||||
|
PQ.content.rule = newRule;
|
||||||
|
});
|
||||||
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
getChildren(question)
|
|
||||||
//чистим потомков от инфы ветвления
|
|
||||||
clearQuestions.forEach((id) => {
|
|
||||||
updateQuestion(id, question => {
|
|
||||||
question.content.rule.parentId = ""
|
|
||||||
question.content.rule.main = []
|
|
||||||
question.content.rule.default = ""
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
//чистим rule родителя
|
deleteQuestion(question.id);
|
||||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
|
||||||
const newRule = {}
|
|
||||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
|
||||||
newRule.parentId = parentQuestion.content.rule.parentId
|
|
||||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
|
||||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
|
||||||
|
|
||||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
} else {
|
||||||
PQ.content.rule = newRule
|
console.log("удаляю безтипогово");
|
||||||
})
|
deleteQuestion(question.id);
|
||||||
deleteQuestion(question.id)
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
deleteQuestion(question.id)
|
deleteQuestionWithTimeout(question.id, deleteFn);
|
||||||
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { copyQuestion, deleteQuestion, updateQuestion, clearRuleForAll, getQuestionByContentId } from "@root/questions/actions";
|
import { copyQuestion, deleteQuestion, updateQuestion, clearRuleForAll, getQuestionByContentId, deleteQuestionWithTimeout } from "@root/questions/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
|
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@ -47,7 +47,7 @@ export default function ButtonsOptionsAndPict({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
|
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
|
||||||
const { questions } = useQuestionsStore.getState()
|
const { questions } = useQuestionsStore.getState();
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -191,8 +191,8 @@ export default function ButtonsOptionsAndPict({
|
|||||||
onMouseEnter={() => setButtonHover("branching")}
|
onMouseEnter={() => setButtonHover("branching")}
|
||||||
onMouseLeave={() => setButtonHover("")}
|
onMouseLeave={() => setButtonHover("")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateOpenBranchingPanel(true)
|
updateOpenBranchingPanel(true);
|
||||||
updateDesireToOpenABranchingModal(question.content.id)
|
updateDesireToOpenABranchingModal(question.content.id);
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
height: "30px",
|
height: "30px",
|
||||||
@ -307,76 +307,67 @@ export default function ButtonsOptionsAndPict({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{ borderRadius: "6px", padding: "2px" }}
|
sx={{ borderRadius: "6px", padding: "2px" }}
|
||||||
onClick={() => { // TODO
|
onClick={() => {
|
||||||
// const removedId = question.id;
|
const deleteFn = () => {
|
||||||
// if (question.deleteTimeoutId) {
|
if (question.type !== null) {
|
||||||
// clearTimeout(question.deleteTimeoutId);
|
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||||
// }
|
updateRootContentId(quiz.id, "");
|
||||||
|
clearRuleForAll();
|
||||||
// removeQuestion(quizId, totalIndex);
|
questions.forEach(q => {
|
||||||
|
if (q.type === "result") {
|
||||||
// const newTimeoutId = window.setTimeout(() => {
|
deleteQuestion(q.id);
|
||||||
// removeQuestionForce(quizId, removedId);
|
|
||||||
// }, 5000);
|
|
||||||
|
|
||||||
// updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
|
||||||
// ...question,
|
|
||||||
// deleteTimeoutId: newTimeoutId,
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (question.type !== null) {
|
|
||||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
|
||||||
updateRootContentId(quiz.id, "")
|
|
||||||
clearRuleForAll()
|
|
||||||
questions.forEach(q => {
|
|
||||||
if (q.type === "result") {
|
|
||||||
deleteQuestion(q.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
deleteQuestion(question.id);
|
|
||||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
|
||||||
const clearQuestions = [] as string[]
|
|
||||||
|
|
||||||
//записываем потомков , а их результаты удаляем
|
|
||||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
|
||||||
questions.forEach((targetQuestion) => {
|
|
||||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
|
||||||
if (targetQuestion.type === "result") {
|
|
||||||
deleteQuestion(targetQuestion.id);
|
|
||||||
} else {
|
|
||||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
|
||||||
getChildren(targetQuestion) //и ищем его потомков
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
deleteQuestion(question.id);
|
||||||
|
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||||
|
const clearQuestions = [] as string[];
|
||||||
|
|
||||||
|
//записываем потомков , а их результаты удаляем
|
||||||
|
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||||
|
questions.forEach((targetQuestion) => {
|
||||||
|
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||||
|
if (targetQuestion.type === "result") {
|
||||||
|
deleteQuestion(targetQuestion.id);
|
||||||
|
} else {
|
||||||
|
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
|
||||||
|
getChildren(targetQuestion); //и ищем его потомков
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
getChildren(question);
|
||||||
|
//чистим потомков от инфы ветвления
|
||||||
|
clearQuestions.forEach((id) => {
|
||||||
|
updateQuestion(id, question => {
|
||||||
|
question.content.rule.parentId = "";
|
||||||
|
question.content.rule.main = [];
|
||||||
|
question.content.rule.default = "";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//чистим rule родителя
|
||||||
|
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
|
||||||
|
const newRule = {};
|
||||||
|
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
|
||||||
|
newRule.parentId = parentQuestion.content.rule.parentId;
|
||||||
|
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId;
|
||||||
|
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||||
|
|
||||||
|
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||||
|
PQ.content.rule = newRule;
|
||||||
|
});
|
||||||
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
getChildren(question)
|
|
||||||
//чистим потомков от инфы ветвления
|
|
||||||
clearQuestions.forEach((id) => {
|
|
||||||
updateQuestion(id, question => {
|
|
||||||
question.content.rule.parentId = ""
|
|
||||||
question.content.rule.main = []
|
|
||||||
question.content.rule.default = ""
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
//чистим rule родителя
|
deleteQuestion(question.id);
|
||||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
|
||||||
const newRule = {}
|
|
||||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
|
||||||
newRule.parentId = parentQuestion.content.rule.parentId
|
|
||||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
|
||||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
|
||||||
|
|
||||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
} else {
|
||||||
PQ.content.rule = newRule
|
console.log("удаляю безтипогово");
|
||||||
})
|
deleteQuestion(question.id);
|
||||||
deleteQuestion(question.id)
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
deleteQuestion(question.id)
|
deleteQuestionWithTimeout(question.id, deleteFn);
|
||||||
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
|
@ -3,8 +3,8 @@ import { Box, ListItem, Typography, useTheme } from "@mui/material";
|
|||||||
import { memo, useEffect } from "react";
|
import { memo, useEffect } from "react";
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
import QuestionsPageCard from "./QuestionPageCard";
|
import QuestionsPageCard from "./QuestionPageCard";
|
||||||
import { updateEditSomeQuestion } from "@root/questions/actions"
|
import { cancelQuestionDeletion, updateEditSomeQuestion } from "@root/questions/actions";
|
||||||
import { useQuestionsStore } from "@root/questions/store"
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -15,21 +15,21 @@ type Props = {
|
|||||||
|
|
||||||
function DraggableListItem({ question, isDragging, index }: Props) {
|
function DraggableListItem({ question, isDragging, index }: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { editSomeQuestion } = useQuestionsStore()
|
const { editSomeQuestion } = useQuestionsStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editSomeQuestion !== null) {
|
if (editSomeQuestion !== null) {
|
||||||
const setI = setInterval(() => {
|
const setI = setInterval(() => {
|
||||||
let comp = document.getElementById(editSomeQuestion)
|
let comp = document.getElementById(editSomeQuestion);
|
||||||
if(comp !== null) {
|
if (comp !== null) {
|
||||||
clearInterval(setI)
|
clearInterval(setI);
|
||||||
comp.scrollIntoView({behavior: 'instant'})
|
comp.scrollIntoView({ behavior: 'instant' });
|
||||||
updateEditSomeQuestion()
|
updateEditSomeQuestion();
|
||||||
}
|
}
|
||||||
}, 200)
|
}, 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [editSomeQuestion])
|
}, [editSomeQuestion]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={question.id.toString()} index={index}>
|
<Draggable draggableId={question.id.toString()} index={index}>
|
||||||
@ -60,11 +60,8 @@ function DraggableListItem({ question, isDragging, index }: Props) {
|
|||||||
Вопрос удалён.
|
Вопрос удалён.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
onClick={() => { // TODO
|
onClick={() => {
|
||||||
// updateQuestionsList<QuizQuestionBase>(quizId, index, {
|
cancelQuestionDeletion(question.id);
|
||||||
// ...questionData,
|
|
||||||
// deleted: false,
|
|
||||||
// });
|
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
|
@ -29,7 +29,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { copyQuestion, createUntypedQuestion, deleteQuestion, clearRuleForAll, toggleExpandQuestion, updateQuestion, updateUntypedQuestion, getQuestionByContentId } from "@root/questions/actions";
|
import { copyQuestion, createUntypedQuestion, deleteQuestion, clearRuleForAll, toggleExpandQuestion, updateQuestion, updateUntypedQuestion, getQuestionByContentId, deleteQuestionWithTimeout } from "@root/questions/actions";
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
import { updateRootContentId } from "@root/quizes/actions";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
||||||
@ -51,7 +51,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function QuestionsPageCard({ question, draggableProps, isDragging, index }: Props) {
|
export default function QuestionsPageCard({ question, draggableProps, isDragging, index }: Props) {
|
||||||
const { questions } = useQuestionsStore()
|
const { questions } = useQuestionsStore();
|
||||||
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -241,79 +241,67 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
|||||||
padding: "0",
|
padding: "0",
|
||||||
margin: "0 5px 0 10px",
|
margin: "0 5px 0 10px",
|
||||||
}}
|
}}
|
||||||
onClick={() => { // TODO
|
onClick={() => {
|
||||||
const removedId = question.id;
|
const deleteFn = () => {
|
||||||
// if (question.deleteTimeoutId) {
|
if (question.type !== null) {
|
||||||
// clearTimeout(question.deleteTimeoutId);
|
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||||
// }
|
updateRootContentId(quiz.id, "");
|
||||||
|
clearRuleForAll();
|
||||||
// removeQuestion(quizId, totalIndex);
|
deleteQuestion(question.id);
|
||||||
|
questions.forEach(q => {
|
||||||
// const newTimeoutId = window.setTimeout(() => {
|
if (q.type === "result") {
|
||||||
// removeQuestionForce(quizId, removedId);
|
deleteQuestion(q.id);
|
||||||
// }, 5000);
|
|
||||||
|
|
||||||
// updateQuestionsList<AnyTypedQuizQuestion>(quizId, totalIndex, {
|
|
||||||
// ...question,
|
|
||||||
// deleteTimeoutId: newTimeoutId,
|
|
||||||
// });
|
|
||||||
console.log(question.type)
|
|
||||||
if (question.type !== null) {
|
|
||||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
|
||||||
updateRootContentId(quiz.id, "")
|
|
||||||
clearRuleForAll()
|
|
||||||
deleteQuestion(question.id);
|
|
||||||
questions.forEach(q => {
|
|
||||||
if (q.type === "result") {
|
|
||||||
deleteQuestion(q.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
|
||||||
const clearQuestions = [] as string[]
|
|
||||||
|
|
||||||
//записываем потомков , а их результаты удаляем
|
|
||||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
|
||||||
questions.forEach((targetQuestion) => {
|
|
||||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
|
||||||
if (targetQuestion.type === "result") {
|
|
||||||
deleteQuestion(targetQuestion.id);
|
|
||||||
} else {
|
|
||||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
|
||||||
getChildren(targetQuestion) //и ищем его потомков
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||||
|
const clearQuestions = [] as string[];
|
||||||
|
|
||||||
|
//записываем потомков , а их результаты удаляем
|
||||||
|
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||||
|
questions.forEach((targetQuestion) => {
|
||||||
|
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||||
|
if (targetQuestion.type === "result") {
|
||||||
|
deleteQuestion(targetQuestion.id);
|
||||||
|
} else {
|
||||||
|
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
|
||||||
|
getChildren(targetQuestion); //и ищем его потомков
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
getChildren(question);
|
||||||
|
//чистим потомков от инфы ветвления
|
||||||
|
clearQuestions.forEach((id) => {
|
||||||
|
updateQuestion(id, question => {
|
||||||
|
question.content.rule.parentId = "";
|
||||||
|
question.content.rule.main = [];
|
||||||
|
question.content.rule.default = "";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//чистим rule родителя
|
||||||
|
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
|
||||||
|
const newRule = {};
|
||||||
|
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
|
||||||
|
newRule.parentId = parentQuestion.content.rule.parentId;
|
||||||
|
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId;
|
||||||
|
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||||
|
|
||||||
|
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||||
|
PQ.content.rule = newRule;
|
||||||
|
});
|
||||||
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
getChildren(question)
|
|
||||||
//чистим потомков от инфы ветвления
|
|
||||||
clearQuestions.forEach((id) => {
|
|
||||||
updateQuestion(id, question => {
|
|
||||||
question.content.rule.parentId = ""
|
|
||||||
question.content.rule.main = []
|
|
||||||
question.content.rule.default = ""
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
//чистим rule родителя
|
|
||||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
|
||||||
const newRule = {}
|
|
||||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
|
||||||
newRule.parentId = parentQuestion.content.rule.parentId
|
|
||||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
|
||||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
|
||||||
|
|
||||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
deleteQuestion(question.id);
|
||||||
PQ.content.rule = newRule
|
} else {
|
||||||
})
|
console.log("удаляю безтипогово");
|
||||||
deleteQuestion(question.id)
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteQuestionWithTimeout(question.id, deleteFn);
|
||||||
deleteQuestion(question.id)
|
|
||||||
} else {
|
|
||||||
console.log("удаляю безтипогово")
|
|
||||||
deleteQuestion(question.id)
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
@ -387,7 +375,7 @@ console.log(question.type)
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
onClick={() => createUntypedQuestion(question.quizId)}
|
onClick={() => createUntypedQuestion(question.quizId, question.id)}
|
||||||
sx={{
|
sx={{
|
||||||
display: plusVisible && !isDragging ? "flex" : "none",
|
display: plusVisible && !isDragging ? "flex" : "none",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
@ -18,74 +18,74 @@ import type {
|
|||||||
|
|
||||||
|
|
||||||
type ButtonTypeQuestion = {
|
type ButtonTypeQuestion = {
|
||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
title: string;
|
title: string;
|
||||||
value: QuestionType;
|
value: QuestionType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BUTTON_TYPE_SHORT_QUESTIONS: ButtonTypeQuestion[] = [
|
const BUTTON_TYPE_SHORT_QUESTIONS: ButtonTypeQuestion[] = [
|
||||||
{
|
{
|
||||||
icon: <Answer color="#9A9AAF" />,
|
icon: <Answer color="#9A9AAF" />,
|
||||||
title: "Варианты ответов",
|
title: "Варианты ответов",
|
||||||
value: "variant",
|
value: "variant",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Input color="#9A9AAF" />,
|
icon: <Input color="#9A9AAF" />,
|
||||||
title: "Своё поле для ввода",
|
title: "Своё поле для ввода",
|
||||||
value: "text",
|
value: "text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <DropDown color="#9A9AAF" />,
|
icon: <DropDown color="#9A9AAF" />,
|
||||||
title: "Выпадающий список",
|
title: "Выпадающий список",
|
||||||
value: "select",
|
value: "select",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Date color="#9A9AAF" />,
|
icon: <Date color="#9A9AAF" />,
|
||||||
title: "Дата",
|
title: "Дата",
|
||||||
value: "date",
|
value: "date",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Slider color="#9A9AAF" />,
|
icon: <Slider color="#9A9AAF" />,
|
||||||
title: "Ползунок",
|
title: "Ползунок",
|
||||||
value: "number",
|
value: "number",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Download color="#9A9AAF" />,
|
icon: <Download color="#9A9AAF" />,
|
||||||
title: "Загрузка файла",
|
title: "Загрузка файла",
|
||||||
value: "file",
|
value: "file",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: UntypedQuizQuestion;
|
question: UntypedQuizQuestion;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FormTypeQuestions({ question }: Props) {
|
export default function FormTypeQuestions({ question }: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexWrap: "wrap",
|
flexWrap: "wrap",
|
||||||
gap: "20px",
|
gap: "20px",
|
||||||
margin: "20px",
|
margin: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(true /* TODO только первый вопрос */
|
{(("page" in question) && question.page === 0
|
||||||
? BUTTON_TYPE_QUESTIONS
|
? BUTTON_TYPE_QUESTIONS
|
||||||
: BUTTON_TYPE_SHORT_QUESTIONS
|
: BUTTON_TYPE_SHORT_QUESTIONS
|
||||||
).map(({ icon, title, value: questionType }) => (
|
).map(({ icon, title, value: questionType }) => (
|
||||||
<QuestionsMiniButton
|
<QuestionsMiniButton
|
||||||
key={title}
|
key={title}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
createTypedQuestion(question.id, questionType);
|
createTypedQuestion(question.id, questionType);
|
||||||
}}
|
}}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
text={title}
|
text={title}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export default function ImageAndVideoButtons() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: "12px", mt: "20px", mb: "20px" }}>
|
<Box sx={{ display: "flex", alignItems: "center", gap: "12px", mt: "20px", mb: "20px" }}>
|
||||||
<AddImage onClick={undefined/* TODO () => openCropModal("", "") */} />
|
<AddImage onClick={undefined} />
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
|
@ -33,7 +33,6 @@ export const ResultSettings = () => {
|
|||||||
isReadyToLeave = false;
|
isReadyToLeave = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(`setting isReadyToLeaveRef to ${isReadyToLeave}`);
|
|
||||||
isReadyToLeaveRef.current = isReadyToLeave;
|
isReadyToLeaveRef.current = isReadyToLeave;
|
||||||
}, [results])
|
}, [results])
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
import { DatePicker } from "@mui/x-date-pickers";
|
import { DatePicker } from "@mui/x-date-pickers";
|
||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Typography } from "@mui/material";
|
||||||
|
|
||||||
@ -14,10 +15,9 @@ type DateProps = {
|
|||||||
|
|
||||||
export const Date = ({ currentQuestion }: DateProps) => {
|
export const Date = ({ currentQuestion }: DateProps) => {
|
||||||
const { answers } = useQuizViewStore();
|
const { answers } = useQuizViewStore();
|
||||||
const { answer } =
|
const answer = answers.find(
|
||||||
answers.find(
|
({ questionId }) => questionId === currentQuestion.content.id
|
||||||
({ questionId }) => questionId === currentQuestion.content.id
|
)?.answer as string;
|
||||||
) ?? {};
|
|
||||||
const [day, month, year] = answer?.split(".") || [];
|
const [day, month, year] = answer?.split(".") || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -32,50 +32,54 @@ export const Date = ({ currentQuestion }: DateProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
slots={{
|
slots={{
|
||||||
openPickerIcon: () => <CalendarIcon />,
|
openPickerIcon: () => <CalendarIcon />,
|
||||||
}}
|
}}
|
||||||
selected={
|
value={dayjs(
|
||||||
answer
|
answer
|
||||||
? new window.Date(`${month}.${day}.${year}`)
|
? new window.Date(`${month}.${day}.${year}`)
|
||||||
: new window.Date()
|
: new window.Date()
|
||||||
}
|
)}
|
||||||
onChange={(date) =>
|
onChange={(date) => {
|
||||||
|
if (!date) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateAnswer(
|
updateAnswer(
|
||||||
currentQuestion.content.id,
|
currentQuestion.content.id,
|
||||||
String(
|
String(
|
||||||
date?.toLocaleDateString("ru-RU", {
|
new window.Date(date.toDate()).toLocaleDateString("ru-RU", {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
}
|
}}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
openPickerButton: {
|
openPickerButton: {
|
||||||
sx: {
|
sx: {
|
||||||
p: 0,
|
p: 0,
|
||||||
},
|
},
|
||||||
"data-cy": "open-datepicker",
|
"data-cy": "open-datepicker",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
"& .MuiInputBase-root": {
|
"& .MuiInputBase-root": {
|
||||||
backgroundColor: "#F2F3F7",
|
backgroundColor: "#F2F3F7",
|
||||||
borderRadius: "10px",
|
borderRadius: "10px",
|
||||||
maxWidth: "250px",
|
maxWidth: "250px",
|
||||||
pr: "22px",
|
pr: "22px",
|
||||||
"& input": {
|
"& input": {
|
||||||
py: "11px",
|
py: "11px",
|
||||||
pl: "20px",
|
pl: "20px",
|
||||||
lineHeight: "19px",
|
lineHeight: "19px",
|
||||||
},
|
},
|
||||||
"& fieldset": {
|
"& fieldset": {
|
||||||
borderColor: "#9A9AAF",
|
borderColor: "#9A9AAF",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -14,13 +14,18 @@ type FileProps = {
|
|||||||
|
|
||||||
export const File = ({ currentQuestion }: FileProps) => {
|
export const File = ({ currentQuestion }: FileProps) => {
|
||||||
const { answers } = useQuizViewStore();
|
const { answers } = useQuizViewStore();
|
||||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
const answer = answers.find(
|
||||||
|
({ questionId }) => questionId === currentQuestion.content.id
|
||||||
|
)?.answer as string;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const uploadFile = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
const uploadFile = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = target.files?.[0];
|
const file = target.files?.[0];
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
updateAnswer(currentQuestion.content.id, `${file.name}|${URL.createObjectURL(file)}`);
|
updateAnswer(
|
||||||
|
currentQuestion.content.id,
|
||||||
|
`${file.name}|${URL.createObjectURL(file)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,75 +41,43 @@ export const File = ({ currentQuestion }: FileProps) => {
|
|||||||
maxWidth: answer?.split("|")[0] ? "640px" : "550px"
|
maxWidth: answer?.split("|")[0] ? "640px" : "550px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{answer?.split("|")[0] && (
|
<ButtonBase component="label" sx={{ justifyContent: "flex-start" }}>
|
||||||
<Box sx={{display: "flex", alignItems: "center", gap: "15px"}}>
|
<input
|
||||||
<Typography>Вы загрузили:</Typography>
|
onChange={uploadFile}
|
||||||
<Box sx={{padding: "5px 5px 5px 16px", backgroundColor: theme.palette.brightPurple.main,
|
hidden
|
||||||
borderRadius: "8px",
|
accept={UPLOAD_FILE_TYPES_MAP[currentQuestion.content.type]}
|
||||||
color: "#FFFFFF",
|
multiple
|
||||||
display: "flex",
|
type="file"
|
||||||
alignItems: "center",
|
/>
|
||||||
gap: "15px"
|
<UploadBox icon={<UploadIcon />} text="5 MB максимум" />
|
||||||
}}>
|
</ButtonBase>
|
||||||
<Typography>
|
{answer && currentQuestion.content.type === "picture" && (
|
||||||
{answer?.split("|")[0]}
|
<img
|
||||||
</Typography>
|
src={answer.split("|")[1]}
|
||||||
<IconButton
|
alt=""
|
||||||
sx={{p: 0}}
|
style={{
|
||||||
onClick={() => {updateAnswer(currentQuestion.content.id, "");}}
|
marginTop: "15px",
|
||||||
>
|
maxWidth: "300px",
|
||||||
<X/>
|
maxHeight: "300px",
|
||||||
</IconButton>
|
}}
|
||||||
</Box>
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
{answer && currentQuestion.content.type === "video" && (
|
||||||
|
<video
|
||||||
)}
|
src={answer.split("|")[1]}
|
||||||
{!answer?.split("|")[0] && (
|
style={{
|
||||||
<ButtonBase component="label" sx={{ justifyContent: "flex-start" }}>
|
marginTop: "15px",
|
||||||
<input
|
maxWidth: "300px",
|
||||||
onChange={uploadFile}
|
maxHeight: "300px",
|
||||||
hidden
|
objectFit: "cover",
|
||||||
accept={UPLOAD_FILE_TYPES_MAP[currentQuestion.content.type]}
|
}}
|
||||||
multiple
|
/>
|
||||||
type="file"
|
)}
|
||||||
/>
|
{answer?.split("|")[0] && (
|
||||||
<Box
|
<Typography sx={{ marginTop: "15px" }}>
|
||||||
onDragOver={(event: DragEvent<HTMLDivElement>) => event.preventDefault()}
|
{answer?.split("|")[0]}
|
||||||
sx={{
|
</Typography>
|
||||||
width: "100%",
|
)}
|
||||||
height: "120px",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: "33px 44px 33px 55px",
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
border: `1px solid ${theme.palette.grey2.main}`,
|
|
||||||
borderRadius: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<UploadIcon />
|
|
||||||
<Box>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.grey2.main,
|
|
||||||
fontWeight: 500
|
|
||||||
}}
|
|
||||||
>Добавить видео</Typography>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.grey2.main,
|
|
||||||
fontSize: "16px",
|
|
||||||
lineHeight: "19px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Принимает .mp4 и .mov формат — максимум 100мб
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
</ButtonBase>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -60,9 +60,22 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
|
|||||||
<Box
|
<Box
|
||||||
key={index}
|
key={index}
|
||||||
sx={{
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
borderRadius: "5px",
|
borderRadius: "5px",
|
||||||
border: `1px solid ${theme.palette.grey2.main}`,
|
border: `1px solid ${theme.palette.grey2.main}`,
|
||||||
}}
|
}}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
updateAnswer(
|
||||||
|
currentQuestion.content.id,
|
||||||
|
currentQuestion.content.variants[index].id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (answer === currentQuestion.content.variants[index].id) {
|
||||||
|
deleteAnswer(currentQuestion.content.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||||
<Box sx={{ width: "100%", height: "300px" }}>
|
<Box sx={{ width: "100%", height: "300px" }}>
|
||||||
@ -88,18 +101,6 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
|
|||||||
color: theme.palette.grey2.main,
|
color: theme.palette.grey2.main,
|
||||||
marginTop: "10px",
|
marginTop: "10px",
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
updateAnswer(
|
|
||||||
currentQuestion.content.id,
|
|
||||||
currentQuestion.content.variants[index].id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (answer === currentQuestion.content.variants[index].id) {
|
|
||||||
deleteAnswer(currentQuestion.content.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={index}
|
value={index}
|
||||||
control={
|
control={
|
||||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
||||||
|
@ -7,7 +7,6 @@ import CustomTextField from "@ui_kit/CustomTextField";
|
|||||||
import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||||
|
|
||||||
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
|
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
|
||||||
import {CustomSlider} from "@ui_kit/CustomSlider";
|
|
||||||
|
|
||||||
type NumberProps = {
|
type NumberProps = {
|
||||||
currentQuestion: QuizQuestionNumber;
|
currentQuestion: QuizQuestionNumber;
|
||||||
@ -124,7 +123,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{currentQuestion.content.chooseRange && (
|
{currentQuestion.content.chooseRange && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -177,7 +176,6 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -44,12 +44,14 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
|
|||||||
<StarIconMini
|
<StarIconMini
|
||||||
color={theme.palette.brightPurple.main}
|
color={theme.palette.brightPurple.main}
|
||||||
width={50}
|
width={50}
|
||||||
|
sx={{ transform: "scale(1.4)" }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
emptyIcon={
|
emptyIcon={
|
||||||
<StarIconMini
|
<StarIconMini
|
||||||
color={theme.palette.grey2.main}
|
color={theme.palette.grey2.main}
|
||||||
width={50}
|
width={50}
|
||||||
|
sx={{ transform: "scale(1.4)" }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -2,8 +2,10 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
|
FormGroup,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Radio,
|
Radio,
|
||||||
|
Checkbox,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
@ -27,11 +29,13 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
|
|||||||
({ questionId }) => questionId === currentQuestion.content.id
|
({ questionId }) => questionId === currentQuestion.content.id
|
||||||
) ?? {};
|
) ?? {};
|
||||||
|
|
||||||
|
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||||
<Box sx={{ display: "flex" }}>
|
<Box sx={{ display: "flex" }}>
|
||||||
<RadioGroup
|
<Group
|
||||||
name={currentQuestion.id}
|
name={currentQuestion.id}
|
||||||
value={currentQuestion.content.variants.findIndex(
|
value={currentQuestion.content.variants.findIndex(
|
||||||
({ id }) => answer === id
|
({ id }) => answer === id
|
||||||
@ -70,25 +74,45 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
|
|||||||
value={index}
|
value={index}
|
||||||
labelPlacement="start"
|
labelPlacement="start"
|
||||||
control={
|
control={
|
||||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
currentQuestion.content.multi ? (
|
||||||
|
<Checkbox
|
||||||
|
checked={!!answer?.includes(variant.id)}
|
||||||
|
checkedIcon={<RadioCheck />}
|
||||||
|
icon={<RadioIcon />}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
label={variant.answer}
|
label={variant.answer}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
const variantId = currentQuestion.content.variants[index].id;
|
||||||
|
|
||||||
updateAnswer(
|
if (currentQuestion.content.multi) {
|
||||||
currentQuestion.content.id,
|
const currentAnswer =
|
||||||
currentQuestion.content.variants[index].id
|
typeof answer !== "string" ? answer || [] : [];
|
||||||
);
|
|
||||||
|
|
||||||
if (answer === currentQuestion.content.variants[index].id) {
|
updateAnswer(
|
||||||
|
currentQuestion.content.id,
|
||||||
|
currentAnswer?.includes(variantId)
|
||||||
|
? currentAnswer?.filter((item) => item !== variantId)
|
||||||
|
: [...currentAnswer, variantId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAnswer(currentQuestion.content.id, variantId);
|
||||||
|
|
||||||
|
if (answer === variantId) {
|
||||||
deleteAnswer(currentQuestion.content.id);
|
deleteAnswer(currentQuestion.content.id);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</RadioGroup>
|
</Group>
|
||||||
{currentQuestion.content.back && (
|
{currentQuestion.content.back && (
|
||||||
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
|
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
|
||||||
<img
|
<img
|
||||||
|
@ -21,7 +21,7 @@ export default function FaviconDropZone({ imageUrl, onImageUploadClick, onDelete
|
|||||||
const [isDropReady, setIsDropReady] = useState<boolean>(false);
|
const [isDropReady, setIsDropReady] = useState<boolean>(false);
|
||||||
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
|
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
|
||||||
|
|
||||||
if (!quiz) return null; // TODO throw and catch with error boundary
|
if (!quiz) return null;
|
||||||
|
|
||||||
async function handleImageUpload(file: File) {
|
async function handleImageUpload(file: File) {
|
||||||
if (file.size > 5 * 2 ** 20) return enqueueSnackbar("Размер картинки слишком велик");
|
if (file.size > 5 * 2 ** 20) return enqueueSnackbar("Размер картинки слишком велик");
|
||||||
|
@ -63,12 +63,12 @@ export default function StartPageSettings() {
|
|||||||
const [formState, setFormState] = useState<"design" | "content">("design");
|
const [formState, setFormState] = useState<"design" | "content">("design");
|
||||||
const [mobileVersion, setMobileVersion] = useState(false);
|
const [mobileVersion, setMobileVersion] = useState(false);
|
||||||
|
|
||||||
if (!quiz) return null; // TODO throw and catch with error boundary
|
if (!quiz) return null;
|
||||||
|
|
||||||
const MobileVersionHC = (bool: boolean) => {
|
const MobileVersionHC = (bool: boolean) => {
|
||||||
setMobileVersion(bool);
|
setMobileVersion(bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
const designType = quiz?.config?.startpageType;
|
const designType = quiz?.config?.startpageType;
|
||||||
|
|
||||||
const favIconDropZoneElement = (
|
const favIconDropZoneElement = (
|
||||||
@ -475,36 +475,37 @@ export default function StartPageSettings() {
|
|||||||
>
|
>
|
||||||
Расположение элементов
|
Расположение элементов
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
{designType !== "centered" &&
|
||||||
sx={{
|
<Box
|
||||||
display: "flex",
|
sx={{
|
||||||
gap: "10px",
|
display: "flex",
|
||||||
}}
|
gap: "10px",
|
||||||
>
|
}}
|
||||||
<SelectableIconButton
|
>
|
||||||
onClick={() => updateQuiz(quiz.id, quiz => {
|
<SelectableIconButton
|
||||||
quiz.config.startpage.position = "left";
|
onClick={() => updateQuiz(quiz.id, quiz => {
|
||||||
})}
|
quiz.config.startpage.position = "left";
|
||||||
isActive={quiz.config.startpage.position === "left"}
|
})}
|
||||||
Icon={AlignLeftIcon}
|
isActive={quiz.config.startpage.position === "left"}
|
||||||
/>
|
Icon={AlignLeftIcon}
|
||||||
<SelectableIconButton
|
/>
|
||||||
onClick={() => updateQuiz(quiz.id, quiz => {
|
<SelectableIconButton
|
||||||
quiz.config.startpage.position = "center";
|
onClick={() => updateQuiz(quiz.id, quiz => {
|
||||||
})}
|
quiz.config.startpage.position = "center";
|
||||||
isActive={quiz.config.startpage.position === "center"}
|
})}
|
||||||
Icon={AlignCenterIcon}
|
isActive={quiz.config.startpage.position === "center"}
|
||||||
sx={{ display: designType === "centered" ? "flex" : "none" }}
|
Icon={AlignCenterIcon}
|
||||||
/>
|
sx={{ display: designType === "standard" ? "none" : "flex" }}
|
||||||
<SelectableIconButton
|
/>
|
||||||
onClick={() => updateQuiz(quiz.id, quiz => {
|
<SelectableIconButton
|
||||||
quiz.config.startpage.position = "right";
|
onClick={() => updateQuiz(quiz.id, quiz => {
|
||||||
})}
|
quiz.config.startpage.position = "right";
|
||||||
isActive={quiz.config.startpage.position === "right"}
|
})}
|
||||||
Icon={AlignRightIcon}
|
isActive={quiz.config.startpage.position === "right"}
|
||||||
/>
|
Icon={AlignRightIcon}
|
||||||
</Box>
|
/>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
{(isTablet || !isSmallMonitor) && (
|
{(isTablet || !isSmallMonitor) && (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
|
@ -44,7 +44,7 @@ export const DropZone = ({ text, sx, deleteIconSx, imageUrl, originalImageUrl, o
|
|||||||
setCropModalImageBlob,
|
setCropModalImageBlob,
|
||||||
} = useCropModalState();
|
} = useCropModalState();
|
||||||
|
|
||||||
if (!quiz) return null; // TODO throw and catch with error boundary
|
if (!quiz) return null;
|
||||||
|
|
||||||
async function handleImageUpload(file: File) {
|
async function handleImageUpload(file: File) {
|
||||||
if (file.size > 5 * 2 ** 20) return enqueueSnackbar("Размер картинки слишком велик");
|
if (file.size > 5 * 2 ** 20) return enqueueSnackbar("Размер картинки слишком велик");
|
||||||
|
@ -10,7 +10,7 @@ export default function StepOne() {
|
|||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const config = quiz?.config;
|
const config = quiz?.config;
|
||||||
|
|
||||||
if (!config) return null; // TODO throw and catch with error boundary
|
if (!config) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
@ -20,7 +20,7 @@ export default function Steptwo() {
|
|||||||
|
|
||||||
const config = quiz?.config;
|
const config = quiz?.config;
|
||||||
|
|
||||||
if (!config) return null; // TODO throw and catch with error boundary
|
if (!config) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: "60px" }}>
|
<Box sx={{ mt: "60px" }}>
|
||||||
|
@ -26,8 +26,8 @@ export const setQuestions = (questions: RawQuestion[] | null) => setProducedStat
|
|||||||
questions,
|
questions,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const createUntypedQuestion = (quizId: number) => setProducedState(state => {
|
export const createUntypedQuestion = (quizId: number, insertAfterQuestionId?: string) => setProducedState(state => {
|
||||||
state.questions.push({
|
const newUntypedQuestion = {
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
quizId,
|
quizId,
|
||||||
type: null,
|
type: null,
|
||||||
@ -35,7 +35,16 @@ export const createUntypedQuestion = (quizId: number) => setProducedState(state
|
|||||||
description: "",
|
description: "",
|
||||||
deleted: false,
|
deleted: false,
|
||||||
expanded: true,
|
expanded: true,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (insertAfterQuestionId) {
|
||||||
|
const index = state.questions.findIndex(q => q.id === insertAfterQuestionId);
|
||||||
|
if (index === -1) return;
|
||||||
|
state.questions.splice(index + 1, 0, newUntypedQuestion);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.questions.push(newUntypedQuestion);
|
||||||
}, {
|
}, {
|
||||||
type: "createUntypedQuestion",
|
type: "createUntypedQuestion",
|
||||||
quizId,
|
quizId,
|
||||||
@ -131,6 +140,37 @@ export const collapseAllQuestions = () => setProducedState(state => {
|
|||||||
state.questions.forEach(question => question.expanded = false);
|
state.questions.forEach(question => question.expanded = false);
|
||||||
}, "collapseAllQuestions");
|
}, "collapseAllQuestions");
|
||||||
|
|
||||||
|
const DELETE_TIMEOUT = 5000;
|
||||||
|
|
||||||
|
export const deleteQuestionWithTimeout = (questionId: string, deleteFn: (questionId: string) => void) => setProducedState(state => {
|
||||||
|
const question = state.questions.find(q => q.id === questionId);
|
||||||
|
if (!question) return;
|
||||||
|
if (question.type === null || question.type === "result") {
|
||||||
|
deleteFn(questionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
question.deleted = true;
|
||||||
|
clearTimeout(question.deleteTimeoutId);
|
||||||
|
question.deleteTimeoutId = window.setTimeout(() => {
|
||||||
|
deleteFn(questionId);
|
||||||
|
}, DELETE_TIMEOUT);
|
||||||
|
}, {
|
||||||
|
type: "deleteQuestionWithTimeout",
|
||||||
|
questionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const cancelQuestionDeletion = (questionId: string) => setProducedState(state => {
|
||||||
|
const question = state.questions.find(q => q.id === questionId);
|
||||||
|
if (!question || question.type === null || question.type === "result") return;
|
||||||
|
|
||||||
|
question.deleted = false;
|
||||||
|
clearTimeout(question.deleteTimeoutId);
|
||||||
|
}, {
|
||||||
|
type: "cancelQuestionDeletion",
|
||||||
|
questionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const REQUEST_DEBOUNCE = 200;
|
const REQUEST_DEBOUNCE = 200;
|
||||||
const requestQueue = new RequestQueue();
|
const requestQueue = new RequestQueue();
|
||||||
@ -335,6 +375,8 @@ export const createTypedQuestion = async (
|
|||||||
type: "createTypedQuestion",
|
type: "createTypedQuestion",
|
||||||
question,
|
question,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateQuestionOrders();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
devlog("Error creating question", error);
|
devlog("Error creating question", error);
|
||||||
enqueueSnackbar("Не удалось создать вопрос");
|
enqueueSnackbar("Не удалось создать вопрос");
|
||||||
@ -355,7 +397,7 @@ export const deleteQuestion = async (questionId: string) => requestQueue.enqueue
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await questionApi.delete(question.backendId);
|
await questionApi.delete(question.backendId);
|
||||||
|
|
||||||
removeQuestion(questionId);
|
removeQuestion(questionId);
|
||||||
|
|
||||||
updateQuestionOrders();
|
updateQuestionOrders();
|
||||||
@ -521,7 +563,7 @@ export const createBackResult = async (
|
|||||||
rawQuestionToQuestion(createdQuestion)
|
rawQuestionToQuestion(createdQuestion)
|
||||||
);
|
);
|
||||||
}, {
|
}, {
|
||||||
type: "createTypedQuestion",
|
type: "createBackResult",
|
||||||
question,
|
question,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -3,7 +3,7 @@ import { devtools } from "zustand/middleware";
|
|||||||
|
|
||||||
type Answer = {
|
type Answer = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
answer: string;
|
answer: string | string[];
|
||||||
// Поле отвечающее за первое изменение ответа, нужно для галочки "Необязательный вопрос"
|
// Поле отвечающее за первое изменение ответа, нужно для галочки "Необязательный вопрос"
|
||||||
changed: boolean;
|
changed: boolean;
|
||||||
};
|
};
|
||||||
@ -25,7 +25,7 @@ export const useQuizViewStore = create<QuizViewStore>()(
|
|||||||
|
|
||||||
export const updateAnswer = (
|
export const updateAnswer = (
|
||||||
questionId: string,
|
questionId: string,
|
||||||
answer: string,
|
answer: string | string[],
|
||||||
changed = true
|
changed = true
|
||||||
) => {
|
) => {
|
||||||
const answers = [...useQuizViewStore.getState().answers];
|
const answers = [...useQuizViewStore.getState().answers];
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
|
ButtonBase,
|
||||||
|
Link,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
@ -8,51 +10,53 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import YoutubeEmbedIframe from "./YoutubeEmbedIframe";
|
import YoutubeEmbedIframe from "./YoutubeEmbedIframe";
|
||||||
|
import { QuizStartpageAlignType, QuizStartpageType } from "@model/quizSettings";
|
||||||
|
import { notReachable } from "../../utils/notReachable";
|
||||||
|
import { useUADevice } from "../../utils/hooks/useUADevice";
|
||||||
|
|
||||||
|
|
||||||
export default function QuizPreviewLayout() {
|
export default function QuizPreviewLayout() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(630));
|
const { isMobileDevice } = useUADevice();
|
||||||
|
|
||||||
if (!quiz) return null;
|
if (!quiz) return null;
|
||||||
|
|
||||||
const isMediaFileExist =
|
const handleCopyNumber = () => {
|
||||||
(quiz.config.startpage.background.type === "image" &&
|
navigator.clipboard.writeText(quiz.config.info.phonenumber);
|
||||||
quiz.config.startpage.background.desktop) ||
|
};
|
||||||
(quiz.config.startpage.background.type === "video" &&
|
|
||||||
quiz.config.startpage.background.video);
|
const background = quiz.config.startpage.background.type === "image"
|
||||||
|
? quiz.config.startpage.background.desktop
|
||||||
|
? (
|
||||||
|
<img
|
||||||
|
src={quiz.config.startpage.background.desktop}
|
||||||
|
alt=""
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "cover",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
: quiz.config.startpage.background.type === "video"
|
||||||
|
? quiz.config.startpage.background.video
|
||||||
|
? (
|
||||||
|
<YoutubeEmbedIframe videoUrl={quiz.config.startpage.background.video} />
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className="quiz-preview-draghandle" sx={{ height: "100%" }}>
|
<Paper className="quiz-preview-draghandle" sx={{ height: "100%" }}>
|
||||||
<Box
|
<QuizPreviewLayoutByType
|
||||||
sx={{
|
quizHeaderBlock={<>
|
||||||
display: "flex",
|
<Box sx={{
|
||||||
flexDirection:
|
|
||||||
quiz.config.startpage.position === "left"
|
|
||||||
? "row"
|
|
||||||
: "row-reverse",
|
|
||||||
flexGrow: 1,
|
|
||||||
height: "100%",
|
|
||||||
"&::-webkit-scrollbar": { width: 0 },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: isMediaFileExist && !isTablet ? "40%" : "100%",
|
|
||||||
padding: "16px",
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
alignItems: "center",
|
||||||
alignItems: isMediaFileExist && !isTablet ? "flex-start" : "center",
|
gap: "20px",
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{quiz.config.startpage.logo && (
|
{quiz.config.startpage.logo && (
|
||||||
<img
|
<img
|
||||||
src={quiz.config.startpage.logo}
|
src={quiz.config.startpage.logo}
|
||||||
@ -68,15 +72,17 @@ export default function QuizPreviewLayout() {
|
|||||||
{quiz.config.info.orgname}
|
{quiz.config.info.orgname}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
</>}
|
||||||
sx={{
|
quizMainBlock={<>
|
||||||
flexGrow: 1,
|
<Box sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
gap: "10px",
|
gap: "10px",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
alignItems: (quiz.config.startpageType === "expanded" && quiz.config.startpage.position === "center")
|
||||||
>
|
? "center"
|
||||||
|
: "start",
|
||||||
|
}}>
|
||||||
<Typography sx={{ fontWeight: "bold" }}>{quiz.name}</Typography>
|
<Typography sx={{ fontWeight: "bold" }}>{quiz.name}</Typography>
|
||||||
<Typography sx={{ fontSize: "12px" }}>
|
<Typography sx={{ fontSize: "12px" }}>
|
||||||
{quiz.config.startpage.description}
|
{quiz.config.startpage.description}
|
||||||
@ -89,42 +95,146 @@ export default function QuizPreviewLayout() {
|
|||||||
padding: "10px 15px",
|
padding: "10px 15px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{quiz.config.startpage.button ? quiz.config.startpage.button : "Пройти тест"}
|
{quiz.config.startpage.button.trim() ? quiz.config.startpage.button : "Пройти тест"}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography
|
{quiz.config.info.clickable ? (
|
||||||
sx={{ fontSize: "16px", color: theme.palette.brightPurple.main }}
|
isMobileDevice ? (
|
||||||
>
|
<Link href={`tel:${quiz.config.info.phonenumber}`}>
|
||||||
{quiz.config.info.phonenumber}
|
<Typography sx={{ fontSize: "16px", color: theme.palette.brightPurple.main }}>
|
||||||
</Typography>
|
{quiz.config.info.phonenumber}
|
||||||
|
</Typography>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<ButtonBase onClick={handleCopyNumber}>
|
||||||
|
<Typography sx={{ fontSize: "16px", color: theme.palette.brightPurple.main }}>
|
||||||
|
{quiz.config.info.phonenumber}
|
||||||
|
</Typography>
|
||||||
|
</ButtonBase>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Typography sx={{ fontSize: "16px", color: theme.palette.brightPurple.main }}>
|
||||||
|
{quiz.config.info.phonenumber}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
<Typography sx={{ fontSize: "12px" }}>
|
<Typography sx={{ fontSize: "12px" }}>
|
||||||
{quiz.config.info.law}
|
{quiz.config.info.law}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</>}
|
||||||
{!isTablet && isMediaFileExist && (
|
backgroundBlock={background}
|
||||||
<Box sx={{ width: "60%" }}>
|
startpageType={quiz.config.startpageType}
|
||||||
{quiz.config.startpage.background.type === "image" &&
|
alignType={quiz.config.startpage.position}
|
||||||
quiz.config.startpage.background.desktop && (
|
/>
|
||||||
<img
|
|
||||||
src={quiz.config.startpage.background.desktop}
|
|
||||||
alt=""
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "cover",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{quiz.config.startpage.background.type === "video" &&
|
|
||||||
quiz.config.startpage.background.video && (
|
|
||||||
<YoutubeEmbedIframe videoUrl={quiz.config.startpage.background.video} />
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function QuizPreviewLayoutByType({ quizHeaderBlock, quizMainBlock, backgroundBlock, startpageType, alignType }: {
|
||||||
|
quizHeaderBlock: JSX.Element;
|
||||||
|
quizMainBlock: JSX.Element;
|
||||||
|
backgroundBlock: JSX.Element | null;
|
||||||
|
startpageType: QuizStartpageType;
|
||||||
|
alignType: QuizStartpageAlignType;
|
||||||
|
}) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(630));
|
||||||
|
|
||||||
|
switch (startpageType) {
|
||||||
|
case null:
|
||||||
|
case "standard": {
|
||||||
|
return (
|
||||||
|
<Box sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: alignType === "left" ? "row" : "row-reverse",
|
||||||
|
flexGrow: 1,
|
||||||
|
height: "100%",
|
||||||
|
"&::-webkit-scrollbar": { width: 0 },
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
width: !isTablet ? "40%" : "100%",
|
||||||
|
padding: "16px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: !isTablet ? "flex-start" : "center",
|
||||||
|
}}>
|
||||||
|
{quizHeaderBlock}
|
||||||
|
{quizMainBlock}
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
width: "60%",
|
||||||
|
}}>
|
||||||
|
{backgroundBlock}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "expanded": {
|
||||||
|
return (
|
||||||
|
<Box sx={{
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: startpageAlignTypeToJustifyContent[alignType],
|
||||||
|
flexGrow: 1,
|
||||||
|
height: "100%",
|
||||||
|
"&::-webkit-scrollbar": { width: 0 },
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
width: "40%",
|
||||||
|
position: "relative",
|
||||||
|
padding: "16px",
|
||||||
|
zIndex: 2,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: alignType === "center" ? "center" : "start",
|
||||||
|
}}>
|
||||||
|
{quizHeaderBlock}
|
||||||
|
{quizMainBlock}
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
|
zIndex: 1,
|
||||||
|
}}>
|
||||||
|
{backgroundBlock}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "centered": {
|
||||||
|
return (
|
||||||
|
<Box sx={{
|
||||||
|
padding: "16px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
height: "100%",
|
||||||
|
"&::-webkit-scrollbar": { width: 0 },
|
||||||
|
}}>
|
||||||
|
{quizHeaderBlock}
|
||||||
|
{backgroundBlock &&
|
||||||
|
<Box>
|
||||||
|
{backgroundBlock}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
{quizMainBlock}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default: notReachable(startpageType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const startpageAlignTypeToJustifyContent: Record<QuizStartpageAlignType, "start" | "center" | "end"> = {
|
||||||
|
left: "start",
|
||||||
|
center: "center",
|
||||||
|
right: "end",
|
||||||
|
};
|
||||||
|
@ -17,6 +17,7 @@ export default function YoutubeEmbedIframe({ videoUrl }: Props) {
|
|||||||
<Box sx={{
|
<Box sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
pointerEvents: "none",
|
||||||
"& iframe": {
|
"& iframe": {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
@ -107,6 +107,7 @@ export const StartPagePreview = () => {
|
|||||||
topLeft: {
|
topLeft: {
|
||||||
top: "-1px",
|
top: "-1px",
|
||||||
left: "-1px",
|
left: "-1px",
|
||||||
|
zIndex: 100,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
13
src/utils/hooks/useUADevice.ts
Normal file
13
src/utils/hooks/useUADevice.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function useUADevice(): { isMobileDevice: boolean; } {
|
||||||
|
const [isMobileDevice, setIsMobileDevice] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||||
|
|
||||||
|
setIsMobileDevice(isMobile);
|
||||||
|
}, [navigator.userAgent]);
|
||||||
|
|
||||||
|
return { isMobileDevice };
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user