frontPanel/src/pages/Questions/BranchingModal/Settings.tsx
2023-12-05 16:46:31 +03:00

776 lines
29 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Box, MenuItem, FormControl, Checkbox, FormControlLabel, Radio, RadioGroup, Typography, useTheme, Select, useMediaQuery, IconButton, TextField } from "@mui/material"
import RadioCheck from "@ui_kit/RadioCheck"
import RadioIcon from "@ui_kit/RadioIcon"
import { QuizQuestionBase } from "model/questionTypes/shared"
import { useState, useRef, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useQuestionsStore } from "@root/questions/store";
import { updateQuestion, getQuestionById } from "@root/questions/actions";
import { AnyTypedQuizQuestion } from "../../../model/questionTypes/shared"
import { SelectChangeEvent } from '@mui/material/Select';
import CalendarIcon from "@icons/CalendarIcon";
import { DatePicker } from "@mui/x-date-pickers";
import * as dayjs from 'dayjs'
import { TimePicker } from '@mui/x-date-pickers/TimePicker';
import InfoIcon from "@icons/Info";
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
const CONDITIONS = [
"Все условия обязательны",
"Обязательно хотя бы одно условие",
];
interface Props {
parentQuestion: AnyTypedQuizQuestion;
targetQuestion: AnyTypedQuizQuestion;
ruleIndex: number;
setParentQuestion: (q:AnyTypedQuizQuestion) => void;
}
//Этот компонент вызывается 1 раз на каждое условие родителя для перехода к этому вопросу. Поэтому для изменения стора мы знаем индекс
export const TypeSwitch = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
switch (parentQuestion.type) {
// case 'nonselected':
// return <BlockRule text={"Не выбран тип родительского вопроса"} />
// break;
case "variant":
case "images":
case "varimg":
case "emoji":
case "select":
return (parentQuestion.content.variants === undefined ? <BlockRule text={"У родителя нет вариантов"} /> :
<SelectorType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
//Реализован
)
break;
case "date":
return <DateInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
break;
case "number":
return <NumberInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
//Реализован
break;
case "page":
return <BlockRule text={"У такого родителя может быть только один потомок"} />
break;
case "text":
return <TextInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
//Реализован
break;
case "file":
return <FileInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
//Реализован
break;
case "rating":
return <RatingInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
//Реализован
break;
default:
return <BlockRule text={"Не распознан тип родительского вопроса"} />
break;
}
}
export const BlockRule = ({ text }: { text: string }) => {
return (
<Typography
sx={{
margin: "100px 0",
textAlign: "center"
}}
>{text}</Typography>
)
}
const SelectorType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const quizId = Number(useParams().quizId);
return (
<Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Дан ответ
</Typography>
<Typography sx={{ color: "#7E2AEA", pl: "10px" }}>
(Укажите один или несколько вариантов)
</Typography>
</Box>
<Select
multiple
value={parentQuestion.content?.rule?.main[ruleIndex]?.rules[0]?.answers || []}
onChange={(event: SelectChangeEvent) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = (event.target as HTMLSelectElement).value
setParentQuestion(newParentQuestion)
}}
sx={{
width: "100%",
height: "48px",
borderRadius: "8px",
"& .MuiOutlinedInput-notchedOutline": {
border: `1px solid ${theme.palette.brightPurple.main} !important`,
height: "48px",
borderRadius: "10px",
},
}}
>
{parentQuestion.content.variants.map((e: any) => {
return <MenuItem value={e.id}>
{e.answer}
</MenuItem>
})}
</Select>
<FormControl>
<RadioGroup
aria-labelledby="demo-controlled-radio-buttons-group"
value={parentQuestion.content.rule.main[ruleIndex].or}
onChange={(_, value) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].or = value
setParentQuestion(newParentQuestion)
}}
>
{CONDITIONS.map((condition, totalIndex) => (
<FormControlLabel
key={totalIndex}
sx={{ color: theme.palette.grey2.main }}
value={Boolean(Number(totalIndex))}
control={
<Radio
checkedIcon={<RadioCheck />}
icon={<RadioIcon />}
/>
}
label={condition}
/>
))}
</RadioGroup>
</FormControl>
</Box >
)
}
const DateInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const upLg = useMediaQuery(theme.breakpoints.up("md"));
const time = dayjs(new Date)
const [firstDate, setFirstDate] = useState(time)
const [secondDate, setSecondDate] = useState(time)
const [firstTime, setFirstTime] = useState(time)
const [secondTime, setSecondTime] = useState(time)
useEffect(() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = time
if (newParentQuestion.content.dateRange) parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = time
setParentQuestion(newParentQuestion)
}, [firstDate, secondDate, firstTime, secondTime])
// {/* //dateRange выбор диапазона дат */}
// {/* time выбор времени */}
return <Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Дан ответ
</Typography>
<Typography sx={{ color: "#7E2AEA", pl: "10px" }}>
(Укажите один или несколько вариантов)
</Typography>
</Box>
<Box
sx={{
backgroundColor: "#E8EAEE",
margin: "10px"
}}
>
{
parentQuestion.content.dateRange &&
<Typography sx={{ color: "#4D4D4D", p: "10px" }}>
(Начало периода)
</Typography>
}
<DatePicker
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(dateString) => {
const date = dateString?.$d?.toLocaleDateString("ru-RU", { year: "numeric", month: "2-digit", day: "2-digit" });
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [date]
// setParentQuestion(newParentQuestion)
}}
slots={{
openPickerIcon: () => <CalendarIcon />,
}}
slotProps={{
openPickerButton: {
sx: {
p: 0,
},
"data-cy": "open-datepicker",
},
}}
sx={{
p: "10px",
"& .MuiInputBase-root": {
minWidth: "325px",
backgroundColor: "#F2F3F7",
borderRadius: "10px",
pr: "31px",
"& input": {
py: "11px",
pl: upLg ? "20px" : "13px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
{parentQuestion.content.time &&
<TimePicker
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
sx={{
p: "10px",
"& .MuiInputBase-root": {
minWidth: "325px",
backgroundColor: "#F2F3F7",
borderRadius: "10px",
pr: "22px",
"& input": {
py: "11px",
pl: upLg ? "20px" : "13px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
}
</Box>
{parentQuestion.content.dateRange &&
<Box
sx={{
backgroundColor: "#E8EAEE",
margin: "10px"
}}
>
{
parentQuestion.content.dateRange &&
<Typography sx={{ color: "#4D4D4D", p: "10px" }}>
(Конец периода)
</Typography>
}
<DatePicker
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
onChange={() => { }}
slots={{
openPickerIcon: () => <CalendarIcon />,
}}
slotProps={{
openPickerButton: {
sx: {
p: 0,
},
"data-cy": "open-datepicker",
},
}}
sx={{
p: "10px",
"& .MuiInputBase-root": {
minWidth: "325px",
backgroundColor: "#F2F3F7",
borderRadius: "10px",
pr: "31px",
"& input": {
py: "11px",
pl: upLg ? "20px" : "13px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
{parentQuestion.content.time &&
<TimePicker
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
sx={{
p: "10px",
"& .MuiInputBase-root": {
minWidth: "325px",
backgroundColor: "#F2F3F7",
borderRadius: "10px",
pr: "22px",
"& input": {
py: "11px",
pl: upLg ? "20px" : "13px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
}
</Box>
}
{/* <TextField
sx={{
marginTop: "20px",
width: "100%"
}}
placeholder="от"
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = 0
setParentQuestion(newParentQuestion)
}}
/>
{parentQuestion.content.chooseRange &&
<TextField
placeholder="до"
sx={{
marginTop: "20px",
width: "100%"
}}
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = 0
setParentQuestion(newParentQuestion)
}}
/>
} */}
</Box >
}
const NumberInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const quizId = Number(useParams().quizId);
return (
<Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Дан ответ
</Typography>
<Typography sx={{ color: "#7E2AEA", pl: "10px" }}>
(Укажите один или несколько вариантов)
</Typography>
</Box>
<TextField
sx={{
marginTop: "20px",
width: "100%"
}}
placeholder="от"
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = 0
setParentQuestion(newParentQuestion)
}}
/>
{parentQuestion.content.chooseRange &&
<TextField
placeholder="до"
sx={{
marginTop: "20px",
width: "100%"
}}
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = 0
setParentQuestion(newParentQuestion)
}}
/>
}
</Box >
)
}
const TextInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const quizId = Number(useParams().quizId);
return (
<Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "inline",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Дан ответ
</Typography>
<Typography sx={{ color: "#7E2AEA", pl: "10px", fontSize: "12px" }}>
(Укажите текст, при совпадении с которым пользователь попадёт на этот вопрос)
</Typography>
</Box>
<TextField
sx={{
marginTop: "20px",
width: "100%"
}}
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [(event.target as HTMLInputElement).value]
setParentQuestion(newParentQuestion)
}}
/>
</Box >
)
}
const FileInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const quizId = Number(useParams().quizId);
return (
<Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "inline",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Перевести на этот вопрос если пользователь загрузил файл
</Typography>
</Box>
<FormControlLabel control={<Checkbox
sx={{
margin: 0
}}
checked={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [(event.target as HTMLInputElement).checked]
setParentQuestion(newParentQuestion)
}}
/>} label="да" />
</Box >
)
}
const RatingInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
const theme = useTheme();
const quizId = Number(useParams().quizId);
return (
<Box
sx={{
padding: "20px",
margin: "20px",
borderRadius: "8px",
bgcolor: "#F2F3F7",
height: "280px",
overflow: "auto"
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
pb: "5px",
}}
>
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
Новое условие
</Typography>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
setParentQuestion(newParentQuestion)
}}
>
<DeleteIcon color={"#4D4D4D"} />
</IconButton>
</Box>
<Box
sx={{
display: "inline",
alignItems: "center",
pb: "10px",
}}
>
<Typography sx={{ color: "#7E2AEA", pl: "10px", fontSize: "12px" }}>
Ожидаемое количество ячеек(не более доступного количества)
</Typography>
</Box>
<TextField
sx={{
marginTop: "20px",
width: "100%"
}}
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
onChange={(event: React.FormEvent<HTMLInputElement>) => {
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
let valueNumber = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
valueNumber = valueNumber > parentQuestion.content.steps ? parentQuestion.content.steps : valueNumber
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [valueNumber]
setParentQuestion(newParentQuestion)
}}
/>
</Box >
)
}