Merge branch 'fix-questions-store' into 'dev'

fix: questions store

See merge request frontend/squiz!9
This commit is contained in:
Mikhail 2023-09-12 17:35:12 +00:00
commit 354e97cb8f
21 changed files with 909 additions and 191 deletions

@ -1,29 +1,63 @@
import { Box } from "@mui/material"; import { Box } from "@mui/material";
interface Props { interface Props {
color: string; color: string;
} }
export default function DeleteIcon({color}: Props) { export default function DeleteIcon({ color = "#4D4D4D" }: Props) {
return (
return ( <Box
<Box sx={{
sx={{ height: "30px",
height: "30px", width: "30px",
width: "30px", display: "flex",
display: "flex", alignItems: "center",
alignItems: "center", justifyContent: "center",
justifyContent: "center", }}
}} >
> <svg
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> width="24"
<path d="M20.25 5.25H3.75" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/> height="24"
<path d="M9.75 9.75V15.75" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/> viewBox="0 0 24 24"
<path d="M14.25 9.75V15.75" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/> fill="none"
<path d="M18.75 5.25V19.5C18.75 19.6989 18.671 19.8897 18.5303 20.0303C18.3897 20.171 18.1989 20.25 18 20.25H6C5.80109 20.25 5.61032 20.171 5.46967 20.0303C5.32902 19.8897 5.25 19.6989 5.25 19.5V5.25" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/> xmlns="http://www.w3.org/2000/svg"
<path d="M15.75 5.25V3.75C15.75 3.35218 15.592 2.97064 15.3107 2.68934C15.0294 2.40804 14.6478 2.25 14.25 2.25H9.75C9.35218 2.25 8.97064 2.40804 8.68934 2.68934C8.40804 2.97064 8.25 3.35218 8.25 3.75V5.25" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/> >
</svg> <path
</Box> d="M20.25 5.25H3.75"
); stroke={color}
} strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.75 9.75V15.75"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M14.25 9.75V15.75"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M18.75 5.25V19.5C18.75 19.6989 18.671 19.8897 18.5303 20.0303C18.3897 20.171 18.1989 20.25 18 20.25H6C5.80109 20.25 5.61032 20.171 5.46967 20.0303C5.32902 19.8897 5.25 19.6989 5.25 19.5V5.25"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.75 5.25V3.75C15.75 3.35218 15.592 2.97064 15.3107 2.68934C15.0294 2.40804 14.6478 2.25 14.25 2.25H9.75C9.35218 2.25 8.97064 2.40804 8.68934 2.68934C8.40804 2.97064 8.25 3.35218 8.25 3.75V5.25"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</Box>
);
}

@ -1,25 +1,37 @@
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import type { SxProps } from "@mui/material";
interface Props { interface Props {
color: string; sx?: SxProps;
onClick?: () => void;
} }
export default function RatingStar({color}: Props) { export default function RatingStar({ sx, onClick }: Props) {
return (
return ( <Box
<Box sx={{
sx={{ height: "38px",
height: "38px", width: "45px",
width: "45px", display: "flex",
display: "flex", alignItems: "center",
alignItems: "center", justifyContent: "center",
justifyContent: "center", ...sx,
}} }}
> onClick={onClick}
<svg width="50" height="48" viewBox="0 0 50 48" fill="none" xmlns="http://www.w3.org/2000/svg"> >
<path d="M26.0576 40.0068L38.1721 47.6836C39.7345 48.6672 41.6574 47.2038 41.2007 45.4045L37.6914 31.6342C37.5965 31.2525 37.6116 30.8518 37.7349 30.4783C37.8582 30.1048 38.0848 29.7736 38.3884 29.523L49.253 20.4787C50.6712 19.3032 49.9501 16.9282 48.0992 16.8082L33.9176 15.8966C33.5307 15.8741 33.1586 15.7396 32.847 15.5096C32.5354 15.2795 32.2977 14.9638 32.1629 14.6011L26.8749 1.31053C26.7349 0.926449 26.4799 0.594665 26.1445 0.360213C25.8091 0.125762 25.4095 0 25 0C24.5905 0 24.1909 0.125762 23.8555 0.360213C23.5201 0.594665 23.2651 0.926449 23.1251 1.31053L17.8371 14.6011C17.7023 14.9638 17.4646 15.2795 17.153 15.5096C16.8414 15.7396 16.4693 15.8741 16.0824 15.8966L1.90076 16.8082C0.0499407 16.9282 -0.671159 19.3032 0.747004 20.4787L11.6116 29.523C11.9152 29.7736 12.1418 30.1048 12.2651 30.4783C12.3884 30.8518 12.4035 31.2525 12.3086 31.6342L9.06369 44.397C8.51085 46.5561 10.8184 48.3074 12.6692 47.1318L23.9424 40.0068C24.2585 39.8061 24.6254 39.6996 25 39.6996C25.3746 39.6996 25.7415 39.8061 26.0576 40.0068Z" fill={color}/> <svg
</svg> width="50"
</Box> height="48"
); viewBox="0 0 50 48"
} fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M26.0576 40.0068L38.1721 47.6836C39.7345 48.6672 41.6574 47.2038 41.2007 45.4045L37.6914 31.6342C37.5965 31.2525 37.6116 30.8518 37.7349 30.4783C37.8582 30.1048 38.0848 29.7736 38.3884 29.523L49.253 20.4787C50.6712 19.3032 49.9501 16.9282 48.0992 16.8082L33.9176 15.8966C33.5307 15.8741 33.1586 15.7396 32.847 15.5096C32.5354 15.2795 32.2977 14.9638 32.1629 14.6011L26.8749 1.31053C26.7349 0.926449 26.4799 0.594665 26.1445 0.360213C25.8091 0.125762 25.4095 0 25 0C24.5905 0 24.1909 0.125762 23.8555 0.360213C23.5201 0.594665 23.2651 0.926449 23.1251 1.31053L17.8371 14.6011C17.7023 14.9638 17.4646 15.2795 17.153 15.5096C16.8414 15.7396 16.4693 15.8741 16.0824 15.8966L1.90076 16.8082C0.0499407 16.9282 -0.671159 19.3032 0.747004 20.4787L11.6116 29.523C11.9152 29.7736 12.1418 30.1048 12.2651 30.4783C12.3884 30.8518 12.4035 31.2525 12.3086 31.6342L9.06369 44.397C8.51085 46.5561 10.8184 48.3074 12.6692 47.1318L23.9424 40.0068C24.2585 39.8061 24.6254 39.6996 25 39.6996C25.3746 39.6996 25.7415 39.8061 26.0576 40.0068Z"
fill="#9A9AAF"
/>
</svg>
</Box>
);
}

@ -109,7 +109,7 @@ export const AnswerItem = ({
key={index} key={index}
fullWidth fullWidth
variant="standard" variant="standard"
sx={{ p: "0 0 20px 0" }} sx={{ padding: "0 0 20px 0" }}
> >
<TextField <TextField
value={variant.answer} value={variant.answer}
@ -171,7 +171,7 @@ export const AnswerItem = ({
}} }}
sx={{ sx={{
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
padding: "13.5px", padding: icon ? "5px 13.5px" : "13.5px",
borderRadius: "10px", borderRadius: "10px",
background: "#ffffff", background: "#ffffff",
}, },

@ -1,45 +1,75 @@
import MiniButtonSetting from "@ui_kit/MiniButtonSetting"; import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import { useParams } from "react-router-dom";
import React from "react"; import React from "react";
import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
import Clue from "../../assets/icons/questionsPage/clue"; import Clue from "../../assets/icons/questionsPage/clue";
import Branching from "../../assets/icons/questionsPage/branching"; import Branching from "../../assets/icons/questionsPage/branching";
import { Box, IconButton, useTheme } from "@mui/material"; import { Box, Typography, Tooltip, IconButton, useTheme } from "@mui/material";
import HideIcon from "../../assets/icons/questionsPage/hideIcon"; import HideIcon from "../../assets/icons/questionsPage/hideIcon";
import CopyIcon from "../../assets/icons/questionsPage/CopyIcon"; import CopyIcon from "../../assets/icons/questionsPage/CopyIcon";
import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon"; import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon";
import {useParams} from "react-router-dom"; import {
import { questionStore, resetSomeField, removeQuestion } from "@root/questions"; questionStore,
resetSomeField,
copyQuestion,
removeQuestion,
} from "@root/questions";
interface Props { interface Props {
switchState: string; switchState: string;
SSHC: (data: string) => void; SSHC: (data: string) => void;
totalIndex: number totalIndex: number;
} }
export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props) { export default function ButtonsOptions({
SSHC,
switchState,
totalIndex,
}: Props) {
const quizId = Number(useParams().quizId); const quizId = Number(useParams().quizId);
const {openedModalSettings} = questionStore() const { openedModalSettings } = questionStore();
const openedModal = () => { const openedModal = () => {
resetSomeField({openedModalSettings: "open"}) resetSomeField({ openedModalSettings: "open" });
console.log(openedModalSettings) console.log(openedModalSettings);
} };
const theme = useTheme(); const theme = useTheme();
const buttonSetting: { icon: JSX.Element; title: string; value: string; myFunc?: any }[] = [ const buttonSetting: {
icon: JSX.Element;
title: string;
value: string;
myFunc?: any;
}[] = [
{ {
icon: <SettingIcon color={switchState === "setting" ? "#ffffff" : theme.palette.grey3.main} />, icon: (
<SettingIcon
color={
switchState === "setting" ? "#ffffff" : theme.palette.grey3.main
}
/>
),
title: "Настройки", title: "Настройки",
value: "setting", value: "setting",
}, },
{ {
icon: <Clue color={switchState === "help" ? "#ffffff" : theme.palette.grey3.main} />, icon: (
<Clue
color={switchState === "help" ? "#ffffff" : theme.palette.grey3.main}
/>
),
title: "Подсказка", title: "Подсказка",
value: "help", value: "help",
}, },
{ {
icon: <Branching color={switchState === "branching" ? "#ffffff" : theme.palette.grey3.main} />, icon: (
<Branching
color={
switchState === "branching" ? "#ffffff" : theme.palette.grey3.main
}
/>
),
title: "Ветвление", title: "Ветвление",
value: "branching", value: "branching",
myFunc: openedModal myFunc: openedModal,
}, },
]; ];
@ -59,21 +89,86 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
gap: "10px", gap: "10px",
}} }}
> >
{buttonSetting.map(({ icon, title, value, myFunc}) => ( {buttonSetting.map(({ icon, title, value, myFunc }) => (
<MiniButtonSetting <>
key={title} {value === "branching" ? (
onClick={() => { <Tooltip
SSHC(value); arrow
myFunc() placement="right"
}} title={
sx={{ <Box>
backgroundColor: switchState === value ? theme.palette.brightPurple.main : "transparent", <Typography
color: switchState === value ? "#ffffff" : theme.palette.grey3.main, sx={{
}} color: "#4D4D4D",
> fontWeight: "bold",
{icon} fontSize: "14px",
{title} marginBottom: "10px",
</MiniButtonSetting> }}
>
Будет показан при условии
</Typography>
<Typography sx={{ fontWeight: "bold", fontSize: "12px" }}>
Название
</Typography>
<Typography
sx={{
fontWeight: "bold",
fontSize: "12px",
marginBottom: "10px",
}}
>
Условие 1, Условие 2
</Typography>
<Typography sx={{ color: "#7E2AEA", fontSize: "12px" }}>
Все условия обязательны
</Typography>
</Box>
}
>
<MiniButtonSetting
key={title}
onClick={() => {
SSHC(value);
myFunc();
}}
sx={{
backgroundColor:
switchState === value
? theme.palette.brightPurple.main
: "transparent",
color:
switchState === value
? "#ffffff"
: theme.palette.grey3.main,
}}
>
{icon}
{title}
</MiniButtonSetting>
</Tooltip>
) : (
<MiniButtonSetting
key={title}
onClick={() => {
SSHC(value);
myFunc();
}}
sx={{
backgroundColor:
switchState === value
? theme.palette.brightPurple.main
: "transparent",
color:
switchState === value
? "#ffffff"
: theme.palette.grey3.main,
}}
>
{icon}
{title}
</MiniButtonSetting>
)}
</>
))} ))}
</Box> </Box>
<Box <Box
@ -82,13 +177,19 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
}} }}
> >
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}> <IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
<HideIcon color={"#4D4D4D"}/> <HideIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}> <IconButton
<CopyIcon color={"#4D4D4D"}/> sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => copyQuestion(quizId, totalIndex)}
>
<CopyIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
<IconButton sx={{ borderRadius: "6px", padding: "2px" }} onClick={() => removeQuestion(quizId, totalIndex)}> <IconButton
<DeleteIcon color={"#4D4D4D"}/> sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => removeQuestion(quizId, totalIndex)}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
</Box> </Box>
</Box> </Box>

@ -9,7 +9,12 @@ import CopyIcon from "../../assets/icons/questionsPage/CopyIcon";
import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon"; import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon";
import ImgIcon from "../../assets/icons/questionsPage/imgIcon"; import ImgIcon from "../../assets/icons/questionsPage/imgIcon";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { questionStore, removeQuestion, resetSomeField } from "@root/questions"; import {
questionStore,
copyQuestion,
removeQuestion,
resetSomeField,
} from "@root/questions";
import "./ButtonsOptionsAndPict.css"; import "./ButtonsOptionsAndPict.css";
@ -176,7 +181,10 @@ export default function ButtonsOptionsAndPict({
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}> <IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
<HideIcon color={"#4D4D4D"} /> <HideIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}> <IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => copyQuestion(quizId, totalIndex)}
>
<CopyIcon color={"#4D4D4D"} /> <CopyIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
<IconButton <IconButton

@ -1,6 +1,7 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
@ -17,7 +18,7 @@ export default function SettingsData({ totalIndex }: SettingsDataProps) {
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography>Настройки календаря</Typography> <Typography>Настройки календаря</Typography>
<CustomCheckbox <CustomCheckbox
label={"Выбор диапозона дат"} label={"Выбор диапазона дат"}
checked={listQuestions[quizId][totalIndex].content.dateRange} checked={listQuestions[quizId][totalIndex].content.dateRange}
handleChange={({ target }) => { handleChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content; const clonContent = listQuestions[quizId][totalIndex].content;
@ -35,10 +36,45 @@ export default function SettingsData({ totalIndex }: SettingsDataProps) {
}} }}
/> />
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px", minWidth: "350px", marginRight: "30px" }}>
<Typography>Настройки вопросов</Typography> <Typography>Настройки вопросов</Typography>
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
</Box> </Box>
); );

@ -24,7 +24,18 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
<Typography sx={{ marginBottom: "15px" }}> <Typography sx={{ marginBottom: "15px" }}>
Настройки ответов Настройки ответов
</Typography> </Typography>
<CustomCheckbox label={"Можно несколько"} /> <CustomCheckbox
label={"Можно несколько"}
checked={listQuestions[quizId][totalIndex].content.multi}
handleChange={({ target }) =>
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
multi: target.checked,
},
})
}
/>
<Typography sx={{ marginBottom: "15px" }}> <Typography sx={{ marginBottom: "15px" }}>
Текст в выпадающем списке Текст в выпадающем списке
</Typography> </Typography>
@ -38,12 +49,51 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
}} }}
/> />
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px", width: "100%" }}>
<Typography sx={{ marginBottom: "15px" }}> <Typography sx={{ marginBottom: "15px" }}>
Настройки вопросов Настройки вопросов
</Typography> </Typography>
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}}
/>
)}
</Box> </Box>
</Box> </Box>
</> </>

@ -1,6 +1,7 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
@ -13,7 +14,7 @@ export default function SettingEmoji({ totalIndex }: SettingEmojiProps) {
const { listQuestions } = questionStore(); const { listQuestions } = questionStore();
return ( return (
<Box sx={{ display: "flex" }}> <Box sx={{ display: "flex", justifyContent: "space-between" }}>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography>Настройки ответов</Typography> <Typography>Настройки ответов</Typography>
<CustomCheckbox <CustomCheckbox
@ -35,10 +36,45 @@ export default function SettingEmoji({ totalIndex }: SettingEmojiProps) {
}} }}
/> />
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px", minWidth: "350px", marginRight: "30px" }}>
<Typography>Настройки вопросов</Typography> <Typography>Настройки вопросов</Typography>
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
</Box> </Box>
); );

@ -89,7 +89,13 @@ export default function SettingOpytionsPict({
return ( return (
<> <>
<Box sx={{ display: "flex" }}> <Box
sx={{
display: "flex",
justifyContent: "space-between",
marginRight: "30px",
}}
>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography sx={{ marginBottom: "15px" }}>Пропорции</Typography> <Typography sx={{ marginBottom: "15px" }}>Пропорции</Typography>
<Box <Box
@ -152,7 +158,7 @@ export default function SettingOpytionsPict({
} }
/> />
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px", minWidth: "350px" }}>
<Typography sx={{ marginBottom: "15px" }}>Форма</Typography> <Typography sx={{ marginBottom: "15px" }}>Форма</Typography>
<Box <Box
sx={{ sx={{
@ -205,7 +211,7 @@ export default function SettingOpytionsPict({
}) })
} }
/> />
<Box sx={{ display: "flex" }}> <Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox <CustomCheckbox
sx={{ width: "100%" }} sx={{ width: "100%" }}
label={"Внутреннее название вопроса"} label={"Внутреннее название вопроса"}

@ -9,9 +9,12 @@ import {
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
import CheckedIcon from "@ui_kit/RadioCheck";
import CheckIcon from "@ui_kit/RadioIcon";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
type SettingTextFieldProps = { type SettingTextFieldProps = {
@ -37,7 +40,13 @@ export default function SettingTextField({
const theme = useTheme(); const theme = useTheme();
return ( return (
<Box sx={{ display: "flex" }}> <Box
sx={{
display: "flex",
justifyContent: "space-between",
marginRight: "50px",
}}
>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography>Настройки ответов</Typography> <Typography>Настройки ответов</Typography>
<FormControl> <FormControl>
@ -62,20 +71,68 @@ export default function SettingTextField({
{ANSWER_TYPES.map(({ name }, index) => ( {ANSWER_TYPES.map(({ name }, index) => (
<FormControlLabel <FormControlLabel
key={index} key={index}
sx={{ color: theme.palette.grey2.main }} sx={{
color: theme.palette.grey2.main,
"& .MuiRadio-root": { padding: "8px 9px" },
}}
value={index} value={index}
control={<Radio />} control={
<Radio icon={<CheckIcon />} checkedIcon={<CheckedIcon />} />
}
label={name} label={name}
/> />
))} ))}
</RadioGroup> </RadioGroup>
</FormControl> </FormControl>
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px", display: "flex", flexDirection: "column" }}>
<Typography>Настройки вопросов</Typography> <Typography>Настройки вопросов</Typography>
<CustomCheckbox label={"Автозаполнение адреса"} /> <CustomCheckbox
<CustomCheckbox label={"Необязательный вопрос"} /> label={"Автозаполнение адреса"}
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> checked={listQuestions[quizId][totalIndex].content.autofill}
handleChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.autofill = target.checked;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
<CustomCheckbox
label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
</Box> </Box>
); );

@ -1,15 +1,54 @@
import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { questionStore, updateQuestionsList } from "@root/questions";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
export default function SettingPageOptions() { type SettingPageOptionsProps = {
totalIndex: number;
};
export default function SettingPageOptions({
totalIndex,
}: SettingPageOptionsProps) {
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
return ( return (
<Box sx={{ display: "flex", flexDirection: "column", padding: "20px" }}> <Box sx={{ display: "flex", flexDirection: "column", padding: "20px" }}>
<Typography>Настройки вопроса</Typography> <Typography>Настройки вопроса</Typography>
<Box sx={{ display: "flex", alignItems: "center" }}> <Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox label={"Внутреннее название вопроса"} /> <CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={({ target }) =>
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
innerNameCheck: target.checked,
innerName: "",
},
})
}
/>
<InfoIcon /> <InfoIcon />
</Box> </Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Внутреннее описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}}
/>
)}
</Box> </Box>
); );
} }

@ -13,13 +13,13 @@ export default function SwitchPageOptions({
}: Props) { }: Props) {
switch (switchState) { switch (switchState) {
case "setting": case "setting":
return <SettingPageOptions />; return <SettingPageOptions totalIndex={totalIndex} />;
break; break;
case "help": case "help":
return <HelpQuestions totalIndex={totalIndex} />; return <HelpQuestions totalIndex={totalIndex} />;
break; break;
case "branching": case "branching":
return <BranchingQuestions totalIndex={totalIndex}/>; return <BranchingQuestions totalIndex={totalIndex} />;
break; break;
default: default:
return <></>; return <></>;

@ -2,10 +2,10 @@ import { useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography, useTheme } from "@mui/material"; import { Box, Typography, useTheme } from "@mui/material";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsOptions";
import Rating from "@mui/material/Rating";
import RatingStar from "../../../assets/icons/questionsPage/ratingStar"; import RatingStar from "../../../assets/icons/questionsPage/ratingStar";
import SwitchRating from "./switchRating"; import SwitchRating from "./switchRating";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
import CustomTextField from "@ui_kit/CustomTextField";
interface Props { interface Props {
totalIndex: number; totalIndex: number;
@ -33,22 +33,45 @@ export default function RatingOptions({ totalIndex }: Props) {
gap: "20px", gap: "20px",
}} }}
> >
<Rating <Box sx={{ display: "flex", gap: "15px" }}>
name="customized-color" <RatingStar
defaultValue={listQuestions[quizId][totalIndex].content.starts} onClick={() => {
getLabelText={(value: number) => updateQuestionsList(quizId, totalIndex, {
`${value} Heart${value !== 1 ? "s" : ""}` content: {
} ...listQuestions[quizId][totalIndex].content,
precision={1} ratingExpanded: true,
icon={<RatingStar color={theme.palette.brightPurple.main} />} },
emptyIcon={<RatingStar color={"#9A9AAF"} />} });
sx={{ display: "flex", gap: "15px" }} }}
onChange={(_, value) => { sx={{
const clonContent = listQuestions[quizId][totalIndex].content; cursor: "pointer",
clonContent.starts = value || 0; ":hover": {
updateQuestionsList(quizId, totalIndex, { content: clonContent }); transform: "scale(1.1)",
}} transition: "0.2s",
/> },
}}
/>
<RatingStar />
<RatingStar />
<RatingStar />
<RatingStar
onClick={() => {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
ratingExpanded: true,
},
});
}}
sx={{
cursor: "pointer",
":hover": {
transform: "scale(1.1)",
transition: "0.2s",
},
}}
/>
</Box>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -75,6 +98,37 @@ export default function RatingOptions({ totalIndex }: Props) {
Позитивно Позитивно
</Typography> </Typography>
</Box> </Box>
{listQuestions[quizId][totalIndex].content.ratingExpanded &&
(listQuestions[quizId][totalIndex].content.ratingDescription ? (
<Typography>
{listQuestions[quizId][totalIndex].content.ratingDescription}
</Typography>
) : (
<CustomTextField
placeholder={"Описание"}
text={listQuestions[quizId][totalIndex].content.ratingDescription}
onKeyDown={({ target, key }) => {
if (key === "Enter") {
const currentTarget = target as HTMLInputElement;
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
ratingDescription: currentTarget.value.substring(0, 20),
},
});
}
}}
onBlur={({ target }) => {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
ratingDescription: target.value.substring(0, 20),
},
});
}}
/>
))}
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}

@ -2,6 +2,7 @@ import { useParams } from "react-router-dom";
import { Box, ButtonBase, Slider, Typography, useTheme } from "@mui/material"; import { Box, ButtonBase, Slider, Typography, useTheme } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
@ -109,8 +110,43 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography>Настройки вопросов</Typography> <Typography>Настройки вопросов</Typography>
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
</Box> </Box>
); );

@ -1,8 +1,8 @@
import { useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsOptions";
import React from "react"; import CustomNumberField from "@ui_kit/CustomNumberField";
import CustomTextField from "@ui_kit/CustomTextField";
import SwitchSlider from "./switchSlider"; import SwitchSlider from "./switchSlider";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
@ -11,7 +11,8 @@ interface Props {
} }
export default function SliderOptions({ totalIndex }: Props) { export default function SliderOptions({ totalIndex }: Props) {
const [switchState, setSwitchState] = React.useState("setting"); const [switchState, setSwitchState] = useState("setting");
const [stepError, setStepError] = useState("");
const quizId = Number(useParams().quizId); const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore(); const { listQuestions } = questionStore();
@ -34,9 +35,11 @@ export default function SliderOptions({ totalIndex }: Props) {
<Box sx={{ gap: "10px", display: "flex", flexDirection: "column" }}> <Box sx={{ gap: "10px", display: "flex", flexDirection: "column" }}>
<Typography>Выбор значения из диапазона</Typography> <Typography>Выбор значения из диапазона</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: "20px" }}> <Box sx={{ display: "flex", alignItems: "center", gap: "20px" }}>
<CustomTextField <CustomNumberField
placeholder={"0"} placeholder={"0"}
text={ min={0}
max={99}
value={
listQuestions[quizId][totalIndex].content.range.split("—")[0] listQuestions[quizId][totalIndex].content.range.split("—")[0]
} }
onChange={({ target }) => { onChange={({ target }) => {
@ -48,11 +51,31 @@ export default function SliderOptions({ totalIndex }: Props) {
content: clonContent, content: clonContent,
}); });
}} }}
onBlur={({ target }) => {
const min = Number(target.value);
const max = Number(
listQuestions[quizId][totalIndex].content.range.split("—")[1]
);
if (min >= max) {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.range = `${max - 1 >= 0 ? max - 1 : 0}${
listQuestions[quizId][totalIndex].content.range.split(
"—"
)[1]
}`;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}
}}
/> />
<Typography></Typography> <Typography></Typography>
<CustomTextField <CustomNumberField
placeholder={"100"} placeholder={"100"}
text={ min={0}
max={100}
value={
listQuestions[quizId][totalIndex].content.range.split("—")[1] listQuestions[quizId][totalIndex].content.range.split("—")[1]
} }
onChange={({ target }) => { onChange={({ target }) => {
@ -64,6 +87,24 @@ export default function SliderOptions({ totalIndex }: Props) {
content: clonContent, content: clonContent,
}); });
}} }}
onBlur={({ target }) => {
const min = Number(
listQuestions[quizId][totalIndex].content.range.split("—")[0]
);
const max = Number(target.value);
if (max <= min) {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.range = `${
listQuestions[quizId][totalIndex].content.range.split(
"—"
)[0]
}${min + 1 >= 100 ? 100 : min + 1}`;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}
}}
/> />
</Box> </Box>
</Box> </Box>
@ -72,13 +113,15 @@ export default function SliderOptions({ totalIndex }: Props) {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
gap: "50px",
}} }}
> >
<Box> <Box sx={{ width: "100%" }}>
<Typography>Начальное значение</Typography> <Typography>Начальное значение</Typography>
<CustomTextField <CustomNumberField
placeholder={"50"} placeholder={"50"}
text={String(listQuestions[quizId][totalIndex].content.start)} min={0}
value={String(listQuestions[quizId][totalIndex].content.start)}
onChange={({ target }) => { onChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content; const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.start = Number(target.value); clonContent.start = Number(target.value);
@ -86,13 +129,31 @@ export default function SliderOptions({ totalIndex }: Props) {
content: clonContent, content: clonContent,
}); });
}} }}
onBlur={({ target }) => {
const start = Number(target.value);
const min = Number(
listQuestions[quizId][totalIndex].content.range.split("—")[0]
);
if (start < min) {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
start: min,
},
});
}
}}
/> />
</Box> </Box>
<Box> <Box sx={{ width: "100%" }}>
<Typography>Шаг</Typography> <Typography>Шаг</Typography>
<CustomTextField <CustomNumberField
min={0}
max={100}
placeholder={"1"} placeholder={"1"}
text={String(listQuestions[quizId][totalIndex].content.step)} error={stepError}
value={String(listQuestions[quizId][totalIndex].content.step)}
onChange={({ target }) => { onChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content; const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.step = Number(target.value); clonContent.step = Number(target.value);
@ -100,6 +161,35 @@ export default function SliderOptions({ totalIndex }: Props) {
content: clonContent, content: clonContent,
}); });
}} }}
onBlur={({ target }) => {
const min = Number(
listQuestions[quizId][totalIndex].content.range.split("—")[0]
);
const max = Number(
listQuestions[quizId][totalIndex].content.range.split("—")[1]
);
const range = max - min;
const step = Number(target.value);
if (step > range) {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
step: range,
},
});
}
if (range % step) {
setStepError(
`Шаг должен делить без остатка диапазон ${max} - ${min} = ${
max - min
}`
);
} else {
setStepError("");
}
}}
/> />
</Box> </Box>
</Box> </Box>

@ -1,6 +1,7 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
@ -28,8 +29,43 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
</Box> </Box>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<Typography>Настройки вопросов</Typography> <Typography>Настройки вопросов</Typography>
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
</Box> </Box>
); );

@ -1,6 +1,7 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { questionStore, updateQuestionsList } from "@root/questions"; import { questionStore, updateQuestionsList } from "@root/questions";
@ -26,8 +27,43 @@ export default function SettingsUpload({ totalIndex }: SettingsUploadProps) {
updateQuestionsList(quizId, totalIndex, { content: clonContent }); updateQuestionsList(quizId, totalIndex, { content: clonContent });
}} }}
/> />
<CustomCheckbox label={"Необязательный вопрос"} /> <CustomCheckbox
<CustomCheckbox label={"Внутреннее название вопроса"} /> <InfoIcon /> label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
handleChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
required: !e.target.checked,
});
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
handleChange={(e) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerNameCheck = e.target.checked;
if (!e.target.checked) {
clonContent.innerName = "";
}
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>{" "}
<InfoIcon />
</Box>
{listQuestions[quizId][totalIndex].content.innerNameCheck && (
<CustomTextField
placeholder={"Развёрнутое описание вопроса"}
text={listQuestions[quizId][totalIndex].content.innerName}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
/>
)}
</Box> </Box>
); );
} }

@ -14,7 +14,13 @@ export default function ResponseSettings({ totalIndex }: Props) {
const { listQuestions } = questionStore(); const { listQuestions } = questionStore();
return ( return (
<Box sx={{ display: "flex" }}> <Box
sx={{
display: "flex",
justifyContent: "space-between",
marginRight: "30px",
}}
>
<Box sx={{ padding: "20px", display: "flex", flexDirection: "column" }}> <Box sx={{ padding: "20px", display: "flex", flexDirection: "column" }}>
<Typography>Настройки ответов</Typography> <Typography>Настройки ответов</Typography>
<CustomCheckbox <CustomCheckbox
@ -61,7 +67,7 @@ export default function ResponseSettings({ totalIndex }: Props) {
}); });
}} }}
/> />
<Box sx={{ display: "flex" }}> <Box sx={{ display: "flex", alignItems: "center" }}>
<CustomCheckbox <CustomCheckbox
label={"Внутреннее название вопроса"} label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck} checked={listQuestions[quizId][totalIndex].content.innerNameCheck}

@ -55,7 +55,6 @@ export interface Question {
video: string; video: string;
dateRange: boolean; dateRange: boolean;
time: boolean; time: boolean;
starts: number;
form: string; form: string;
steps: number; steps: number;
range: string; range: string;
@ -64,6 +63,8 @@ export interface Question {
chooseRange: boolean; chooseRange: boolean;
required: boolean; required: boolean;
replText: string; replText: string;
ratingExpanded: boolean;
ratingDescription: string;
}; };
version: number; version: number;
parent_ids: number[]; parent_ids: number[];
@ -161,7 +162,6 @@ export const createQuestion = (quizId: number) => {
video: "", video: "",
dateRange: false, dateRange: false,
time: false, time: false,
starts: 0,
form: "star", form: "star",
steps: 5, steps: 5,
range: "0—100", range: "0—100",
@ -170,6 +170,8 @@ export const createQuestion = (quizId: number) => {
chooseRange: false, chooseRange: false,
required: false, required: false,
replText: "", replText: "",
ratingExpanded: false,
ratingDescription: "",
variants: [ variants: [
{ {
answer: "", answer: "",
@ -204,9 +206,11 @@ export const createQuestion = (quizId: number) => {
export const copyQuestion = (quizId: number, copiedQuestionIndex: number) => { export const copyQuestion = (quizId: number, copiedQuestionIndex: number) => {
const listQuestions = { ...questionStore.getState()["listQuestions"] }; const listQuestions = { ...questionStore.getState()["listQuestions"] };
listQuestions[quizId].push({ listQuestions[quizId].splice(
...listQuestions[quizId][copiedQuestionIndex], copiedQuestionIndex,
}); 0,
listQuestions[quizId][copiedQuestionIndex]
);
questionStore.setState({ listQuestions }); questionStore.setState({ listQuestions });
}; };

@ -0,0 +1,54 @@
import CustomTextField from "./CustomTextField";
import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react";
import type { SxProps, Theme } from "@mui/material";
interface CustomNumberFieldProps {
placeholder: string;
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
error?: string;
value: string;
sx?: SxProps<Theme>;
min?: number;
max?: number;
}
export default function CustomNumberField({
placeholder,
value,
sx,
error,
onChange,
onKeyDown,
onBlur,
min = -999999999,
max = 999999999,
}: CustomNumberFieldProps) {
const onInputChange = (event: ChangeEvent<HTMLInputElement>) => {
const inputValue = event.target.value;
if (
Number(inputValue) >= min &&
Number(inputValue) <= max &&
(inputValue === "" ||
inputValue.match(/^\d*$/) ||
(inputValue[0] === "-" && inputValue.slice(1).match(/^\d*$/)))
) {
onChange?.({ ...event, target: { ...event.target, value: inputValue } });
}
};
return (
<CustomTextField
placeholder={placeholder}
sx={sx}
error={error}
onChange={onInputChange}
onKeyDown={onKeyDown}
onBlur={onBlur}
value={value}
/>
);
}

@ -1,46 +1,69 @@
import {FormControl, TextField, useTheme, SxProps, Theme} from "@mui/material"; import {
import {ChangeEvent} from "react"; FormControl,
TextField,
useTheme,
SxProps,
Theme,
} from "@mui/material";
import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react";
interface CustomTextFieldProps { interface CustomTextFieldProps {
placeholder: string; placeholder: string;
onChange?: (event: ChangeEvent<HTMLInputElement>) => void; value?: string;
text?: string; error?: string;
sx?: SxProps<Theme>; onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
text?: string;
sx?: SxProps<Theme>;
} }
export default function CustomTextField({ placeholder, text, sx, onChange}: CustomTextFieldProps) { export default function CustomTextField({
const theme = useTheme(); placeholder,
value,
text,
sx,
error,
onChange,
onKeyDown,
onBlur,
}: CustomTextFieldProps) {
const theme = useTheme();
return ( return (
<FormControl <FormControl fullWidth variant="standard" sx={{ p: 0 }}>
fullWidth <TextField
variant="standard" defaultValue={text}
sx={{ p: 0 }} fullWidth
> value={value}
<TextField placeholder={placeholder}
defaultValue={text} error={!!error}
fullWidth label={error}
placeholder={placeholder} onChange={onChange}
onChange={onChange} onKeyDown={onKeyDown}
sx={{ onBlur={onBlur}
"& .MuiInputBase-root": { sx={{
backgroundColor: theme.palette.background.default, "& .MuiInputBase-root": {
height: "48px", backgroundColor: theme.palette.background.default,
borderRadius: "10px", height: "48px",
borderRadius: "10px",
}, },
...sx "& .MuiInputLabel-root": {
}} fontSize: "13.5px",
inputProps={{ marginTop: "3px",
sx: { },
borderRadius: "10px", ...sx,
fontSize: "18px", }}
lineHeight: "21px", inputProps={{
py: 0, sx: {
borderRadius: "10px",
} fontSize: "18px",
}} lineHeight: "21px",
/> py: 0,
</FormControl> },
); }}
} />
</FormControl>
);
}