Merge branch 'little-fixes' into 'fix-questions-store'
fix: little fixes See merge request frontend/squiz!10
This commit is contained in:
commit
23e3045085
@ -1,29 +1,63 @@
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
|
||||
interface Props {
|
||||
color: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export default function DeleteIcon({color}: Props) {
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "30px",
|
||||
width: "30px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.25 5.25H3.75" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M9.75 9.75V15.75" stroke="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M14.25 9.75V15.75" stroke="#4D4D4D" 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="#4D4D4D" 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="#4D4D4D" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
export default function DeleteIcon({ color = "#4D4D4D" }: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "30px",
|
||||
width: "30px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
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 type { SxProps } from "@mui/material";
|
||||
|
||||
interface Props {
|
||||
color: string;
|
||||
sx?: SxProps;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export default function RatingStar({color}: Props) {
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "38px",
|
||||
width: "45px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
export default function RatingStar({ sx, onClick }: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "38px",
|
||||
width: "45px",
|
||||
display: "flex",
|
||||
alignItems: "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="#9A9AAF"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@ -8,7 +8,12 @@ import { Box, Typography, Tooltip, IconButton, useTheme } from "@mui/material";
|
||||
import HideIcon from "../../assets/icons/questionsPage/hideIcon";
|
||||
import CopyIcon from "../../assets/icons/questionsPage/CopyIcon";
|
||||
import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon";
|
||||
import { questionStore, resetSomeField, removeQuestion } from "@root/questions";
|
||||
import {
|
||||
questionStore,
|
||||
resetSomeField,
|
||||
copyQuestion,
|
||||
removeQuestion,
|
||||
} from "@root/questions";
|
||||
|
||||
interface Props {
|
||||
switchState: string;
|
||||
@ -174,7 +179,10 @@ export default function ButtonsOptions({
|
||||
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
|
||||
<HideIcon color={"#4D4D4D"} />
|
||||
</IconButton>
|
||||
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
|
||||
<IconButton
|
||||
sx={{ borderRadius: "6px", padding: "2px" }}
|
||||
onClick={() => copyQuestion(quizId, totalIndex)}
|
||||
>
|
||||
<CopyIcon color={"#4D4D4D"} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
|
||||
@ -9,7 +9,12 @@ import CopyIcon from "../../assets/icons/questionsPage/CopyIcon";
|
||||
import DeleteIcon from "../../assets/icons/questionsPage/deleteIcon";
|
||||
import ImgIcon from "../../assets/icons/questionsPage/imgIcon";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { questionStore, removeQuestion, resetSomeField } from "@root/questions";
|
||||
import {
|
||||
questionStore,
|
||||
copyQuestion,
|
||||
removeQuestion,
|
||||
resetSomeField,
|
||||
} from "@root/questions";
|
||||
|
||||
import "./ButtonsOptionsAndPict.css";
|
||||
|
||||
@ -176,7 +181,10 @@ export default function ButtonsOptionsAndPict({
|
||||
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
|
||||
<HideIcon color={"#4D4D4D"} />
|
||||
</IconButton>
|
||||
<IconButton sx={{ borderRadius: "6px", padding: "2px" }}>
|
||||
<IconButton
|
||||
sx={{ borderRadius: "6px", padding: "2px" }}
|
||||
onClick={() => copyQuestion(quizId, totalIndex)}
|
||||
>
|
||||
<CopyIcon color={"#4D4D4D"} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
|
||||
@ -24,7 +24,18 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
|
||||
<Typography sx={{ marginBottom: "15px" }}>
|
||||
Настройки ответов
|
||||
</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>
|
||||
|
||||
@ -13,6 +13,8 @@ import CustomTextField from "@ui_kit/CustomTextField";
|
||||
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
|
||||
import CheckedIcon from "@ui_kit/RadioCheck";
|
||||
import CheckIcon from "@ui_kit/RadioIcon";
|
||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
||||
|
||||
type SettingTextFieldProps = {
|
||||
@ -69,9 +71,14 @@ export default function SettingTextField({
|
||||
{ANSWER_TYPES.map(({ name }, index) => (
|
||||
<FormControlLabel
|
||||
key={index}
|
||||
sx={{ color: theme.palette.grey2.main }}
|
||||
sx={{
|
||||
color: theme.palette.grey2.main,
|
||||
"& .MuiRadio-root": { padding: "8px 9px" },
|
||||
}}
|
||||
value={index}
|
||||
control={<Radio />}
|
||||
control={
|
||||
<Radio icon={<CheckIcon />} checkedIcon={<CheckedIcon />} />
|
||||
}
|
||||
label={name}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -2,10 +2,10 @@ import { useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Box, Typography, useTheme } from "@mui/material";
|
||||
import ButtonsOptions from "../ButtonsOptions";
|
||||
import Rating from "@mui/material/Rating";
|
||||
import RatingStar from "../../../assets/icons/questionsPage/ratingStar";
|
||||
import SwitchRating from "./switchRating";
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
import CustomTextField from "@ui_kit/CustomTextField";
|
||||
|
||||
interface Props {
|
||||
totalIndex: number;
|
||||
@ -33,22 +33,45 @@ export default function RatingOptions({ totalIndex }: Props) {
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<Rating
|
||||
name="customized-color"
|
||||
defaultValue={listQuestions[quizId][totalIndex].content.starts}
|
||||
getLabelText={(value: number) =>
|
||||
`${value} Heart${value !== 1 ? "s" : ""}`
|
||||
}
|
||||
precision={1}
|
||||
icon={<RatingStar color={theme.palette.brightPurple.main} />}
|
||||
emptyIcon={<RatingStar color={"#9A9AAF"} />}
|
||||
sx={{ display: "flex", gap: "15px" }}
|
||||
onChange={(_, value) => {
|
||||
const clonContent = listQuestions[quizId][totalIndex].content;
|
||||
clonContent.starts = value || 0;
|
||||
updateQuestionsList(quizId, totalIndex, { content: clonContent });
|
||||
}}
|
||||
/>
|
||||
<Box sx={{ display: "flex", gap: "15px" }}>
|
||||
<RatingStar
|
||||
onClick={() => {
|
||||
updateQuestionsList(quizId, totalIndex, {
|
||||
content: {
|
||||
...listQuestions[quizId][totalIndex].content,
|
||||
ratingExpanded: true,
|
||||
},
|
||||
});
|
||||
}}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
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
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -75,6 +98,37 @@ export default function RatingOptions({ totalIndex }: Props) {
|
||||
Позитивно
|
||||
</Typography>
|
||||
</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>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import ButtonsOptions from "../ButtonsOptions";
|
||||
import React from "react";
|
||||
import CustomTextField from "@ui_kit/CustomTextField";
|
||||
import CustomNumberField from "@ui_kit/CustomNumberField";
|
||||
import SwitchSlider from "./switchSlider";
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
|
||||
@ -11,7 +11,8 @@ interface 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 { listQuestions } = questionStore();
|
||||
|
||||
@ -34,9 +35,11 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
<Box sx={{ gap: "10px", display: "flex", flexDirection: "column" }}>
|
||||
<Typography>Выбор значения из диапазона</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "20px" }}>
|
||||
<CustomTextField
|
||||
<CustomNumberField
|
||||
placeholder={"0"}
|
||||
text={
|
||||
min={0}
|
||||
max={99}
|
||||
value={
|
||||
listQuestions[quizId][totalIndex].content.range.split("—")[0]
|
||||
}
|
||||
onChange={({ target }) => {
|
||||
@ -48,11 +51,31 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
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>
|
||||
<CustomTextField
|
||||
<CustomNumberField
|
||||
placeholder={"100"}
|
||||
text={
|
||||
min={0}
|
||||
max={100}
|
||||
value={
|
||||
listQuestions[quizId][totalIndex].content.range.split("—")[1]
|
||||
}
|
||||
onChange={({ target }) => {
|
||||
@ -64,6 +87,24 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
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>
|
||||
@ -72,13 +113,15 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: "50px",
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Typography>Начальное значение</Typography>
|
||||
<CustomTextField
|
||||
<CustomNumberField
|
||||
placeholder={"50"}
|
||||
text={String(listQuestions[quizId][totalIndex].content.start)}
|
||||
min={0}
|
||||
value={String(listQuestions[quizId][totalIndex].content.start)}
|
||||
onChange={({ target }) => {
|
||||
const clonContent = listQuestions[quizId][totalIndex].content;
|
||||
clonContent.start = Number(target.value);
|
||||
@ -86,13 +129,31 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
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 sx={{ width: "100%" }}>
|
||||
<Typography>Шаг</Typography>
|
||||
<CustomTextField
|
||||
<CustomNumberField
|
||||
min={0}
|
||||
max={100}
|
||||
placeholder={"1"}
|
||||
text={String(listQuestions[quizId][totalIndex].content.step)}
|
||||
error={stepError}
|
||||
value={String(listQuestions[quizId][totalIndex].content.step)}
|
||||
onChange={({ target }) => {
|
||||
const clonContent = listQuestions[quizId][totalIndex].content;
|
||||
clonContent.step = Number(target.value);
|
||||
@ -100,6 +161,35 @@ export default function SliderOptions({ totalIndex }: Props) {
|
||||
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>
|
||||
|
||||
@ -55,7 +55,6 @@ export interface Question {
|
||||
video: string;
|
||||
dateRange: boolean;
|
||||
time: boolean;
|
||||
starts: number;
|
||||
form: string;
|
||||
steps: number;
|
||||
range: string;
|
||||
@ -64,6 +63,8 @@ export interface Question {
|
||||
chooseRange: boolean;
|
||||
required: boolean;
|
||||
replText: string;
|
||||
ratingExpanded: boolean;
|
||||
ratingDescription: string;
|
||||
};
|
||||
version: number;
|
||||
parent_ids: number[];
|
||||
@ -161,7 +162,6 @@ export const createQuestion = (quizId: number) => {
|
||||
video: "",
|
||||
dateRange: false,
|
||||
time: false,
|
||||
starts: 0,
|
||||
form: "star",
|
||||
steps: 5,
|
||||
range: "0—100",
|
||||
@ -170,6 +170,8 @@ export const createQuestion = (quizId: number) => {
|
||||
chooseRange: false,
|
||||
required: false,
|
||||
replText: "",
|
||||
ratingExpanded: false,
|
||||
ratingDescription: "",
|
||||
variants: [
|
||||
{
|
||||
answer: "",
|
||||
|
||||
54
src/ui_kit/CustomNumberField.tsx
Normal file
54
src/ui_kit/CustomNumberField.tsx
Normal file
@ -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 {ChangeEvent} from "react";
|
||||
import {
|
||||
FormControl,
|
||||
TextField,
|
||||
useTheme,
|
||||
SxProps,
|
||||
Theme,
|
||||
} from "@mui/material";
|
||||
|
||||
import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react";
|
||||
|
||||
interface CustomTextFieldProps {
|
||||
placeholder: string;
|
||||
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
text?: string;
|
||||
sx?: SxProps<Theme>;
|
||||
placeholder: string;
|
||||
value?: string;
|
||||
error?: string;
|
||||
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) {
|
||||
const theme = useTheme();
|
||||
export default function CustomTextField({
|
||||
placeholder,
|
||||
value,
|
||||
text,
|
||||
sx,
|
||||
error,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onBlur,
|
||||
}: CustomTextFieldProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="standard"
|
||||
sx={{ p: 0 }}
|
||||
>
|
||||
<TextField
|
||||
defaultValue={text}
|
||||
fullWidth
|
||||
placeholder={placeholder}
|
||||
onChange={onChange}
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
height: "48px",
|
||||
borderRadius: "10px",
|
||||
|
||||
},
|
||||
...sx
|
||||
}}
|
||||
inputProps={{
|
||||
sx: {
|
||||
borderRadius: "10px",
|
||||
fontSize: "18px",
|
||||
lineHeight: "21px",
|
||||
py: 0,
|
||||
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<FormControl fullWidth variant="standard" sx={{ p: 0 }}>
|
||||
<TextField
|
||||
defaultValue={text}
|
||||
fullWidth
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
error={!!error}
|
||||
label={error}
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onBlur={onBlur}
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
height: "48px",
|
||||
borderRadius: "10px",
|
||||
},
|
||||
"& .MuiInputLabel-root": {
|
||||
fontSize: "13.5px",
|
||||
marginTop: "3px",
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
inputProps={{
|
||||
sx: {
|
||||
borderRadius: "10px",
|
||||
fontSize: "18px",
|
||||
lineHeight: "21px",
|
||||
py: 0,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user