fix: text inputs debounce

This commit is contained in:
IlyaDoronin 2023-09-20 12:07:33 +03:00
parent 879f206d8f
commit 10f9a5adb1
19 changed files with 342 additions and 166 deletions

@ -32,6 +32,7 @@
"react-router-dom": "^6.6.2",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"use-debounce": "^9.0.4",
"web-vitals": "^2.1.0",
"zustand": "^4.3.8"
},

@ -10,6 +10,7 @@ import {
useTheme,
useMediaQuery,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -42,6 +43,17 @@ export const AnswerItem = ({
const { listQuestions } = questionStore();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
const answerNew = variants.slice();
answerNew[index].answer = value;
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
variants: answerNew,
},
});
}, 1000);
const [isOpen, setIsOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
@ -55,18 +67,6 @@ export const AnswerItem = ({
setIsOpen(false);
};
const onChangeText = (event: ChangeEvent<HTMLInputElement>) => {
const answerNew = variants.slice();
answerNew[index].answer = event.target.value;
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
variants: answerNew,
},
});
};
const addNewAnswer = () => {
const answerNew = variants.slice();
answerNew.push({ answer: "", hints: "" });
@ -114,12 +114,12 @@ export const AnswerItem = ({
sx={{ padding: isMobile ? " 15px 0 20px 0" : "0 0 20px 0" }}
>
<TextField
value={variant.answer}
defaultValue={variant.answer}
fullWidth
focused={false}
placeholder={"Добавьте ответ"}
multiline={listQuestions[quizId][totalIndex].content.largeCheck}
onChange={onChangeText}
onChange={({ target }) => debounced(target.value)}
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
if (
event.code === "Enter" &&

@ -6,6 +6,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon";
@ -20,6 +21,11 @@ export default function SettingsData({ totalIndex }: SettingsDataProps) {
const { listQuestions } = questionStore();
const theme = useTheme();
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box
@ -98,11 +104,7 @@ export default function SettingsData({ totalIndex }: SettingsDataProps) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -12,10 +12,17 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import TypeQuestions from "../TypeQuestions";
import SwitchQuestionsPage from "../SwitchQuestionsPage";
import { questionStore, updateQuestionsList, createQuestion, copyQuestion, removeQuestion } from "@root/questions";
import {
questionStore,
updateQuestionsList,
createQuestion,
copyQuestion,
removeQuestion,
} from "@root/questions";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
@ -49,39 +56,102 @@ interface Props {
const IconAndrom = (isExpanded: boolean, switchState: string) => {
switch (switchState) {
case "variant":
return <Answer color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Answer
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "images":
return <OptionsPict color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<OptionsPict
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "varimg":
return <OptionsAndPict color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<OptionsAndPict
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "emoji":
return <Emoji color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Emoji
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "text":
return <Input color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Input
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "select":
return <DropDown color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<DropDown
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "date":
return <Date color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Date
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "number":
return <Slider color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Slider
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "file":
return <Download color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Download
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "page":
return <Page color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<Page
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
case "rating":
return <RatingIcon color={isExpanded ? "#9A9AAF" : "white"} sx={{ height: "22px", width: "20px" }} />;
return (
<RatingIcon
color={isExpanded ? "#9A9AAF" : "white"}
sx={{ height: "22px", width: "20px" }}
/>
);
default:
return <></>;
}
};
export default function QuestionsPageCard({ totalIndex, draggableProps, isDragging }: Props) {
export default function QuestionsPageCard({
totalIndex,
draggableProps,
isDragging,
}: Props) {
const [plusVisible, setPlusVisible] = useState<boolean>(false);
const quizId = Number(useParams().quizId);
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const { listQuestions } = questionStore();
const { type: switchState, expanded: isExpanded } = listQuestions[quizId][totalIndex];
const { type: switchState, expanded: isExpanded } =
listQuestions[quizId][totalIndex];
const debounced = useDebouncedCallback((title) => {
updateQuestionsList(quizId, totalIndex, { title });
}, 1000);
return (
<>
@ -106,24 +176,29 @@ export default function QuestionsPageCard({ totalIndex, draggableProps, isDraggi
>
<FormControl
variant="standard"
sx={{ p: 0, maxWidth: isTablet ? (isMobile ? "100%" : "640px") : "100%", width: "100%" }}
sx={{
p: 0,
maxWidth: isTablet ? (isMobile ? "100%" : "640px") : "100%",
width: "100%",
}}
>
<TextField
value={listQuestions[quizId][totalIndex].title}
defaultValue={listQuestions[quizId][totalIndex].title}
placeholder={"Заголовок вопроса"}
onChange={(e) => {
updateQuestionsList(quizId, totalIndex, {
title: e.target.value,
});
console.log(listQuestions[quizId][totalIndex].title);
}}
onChange={({ target }) => debounced(target.value)}
InputProps={{
startAdornment: <InputAdornment position="start">{IconAndrom(isExpanded, switchState)}</InputAdornment>,
startAdornment: (
<InputAdornment position="start">
{IconAndrom(isExpanded, switchState)}
</InputAdornment>
),
}}
sx={{
"& .MuiInputBase-root": {
color: isExpanded ? "#9A9AAF" : "white",
backgroundColor: isExpanded ? theme.palette.background.default : "transparent",
backgroundColor: isExpanded
? theme.palette.background.default
: "transparent",
height: "48px",
borderRadius: "10px",
".MuiOutlinedInput-notchedOutline": {
@ -141,17 +216,45 @@ export default function QuestionsPageCard({ totalIndex, draggableProps, isDraggi
}}
/>
</FormControl>
<Box sx={{ display: "flex", alignItems: "center", width: isMobile ? "100%" : "auto", position: "relative" }}>
<Box sx={{ display: "flex", alignItems: "center", marginLeft: isMobile ? "auto" : "0px" }}>
<IconButton onClick={() => updateQuestionsList(quizId, totalIndex, { expanded: !isExpanded })}>
{isExpanded ? <ExpandMoreIcon /> : <ExpandLessIcon fill="#7E2AEA" />}
<Box
sx={{
display: "flex",
alignItems: "center",
width: isMobile ? "100%" : "auto",
position: "relative",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
marginLeft: isMobile ? "auto" : "0px",
}}
>
<IconButton
onClick={() =>
updateQuestionsList(quizId, totalIndex, {
expanded: !isExpanded,
})
}
>
{isExpanded ? (
<ExpandMoreIcon />
) : (
<ExpandLessIcon fill="#7E2AEA" />
)}
</IconButton>
{isExpanded ? (
<></>
) : (
<Box sx={{ display: "flex", borderRight: "solid 1px white" }}>
<FormControlLabel
control={<Checkbox icon={<HideIcon color={"#7E2AEA"} />} checkedIcon={<CrossedEyeIcon />} />}
control={
<Checkbox
icon={<HideIcon color={"#7E2AEA"} />}
checkedIcon={<CrossedEyeIcon />}
/>
}
label={""}
sx={{
color: theme.palette.grey2.main,
@ -164,7 +267,11 @@ export default function QuestionsPageCard({ totalIndex, draggableProps, isDraggi
<CopyIcon color={"white"} />
</IconButton>
<IconButton
sx={{ cursor: "pointer", borderRadius: "6px", padding: "2px" }}
sx={{
cursor: "pointer",
borderRadius: "6px",
padding: "2px",
}}
onClick={() => removeQuestion(quizId, totalIndex)}
>
<DeleteIcon color={"white"} />
@ -231,7 +338,8 @@ export default function QuestionsPageCard({ totalIndex, draggableProps, isDraggi
backgroundPosition: "bottom",
backgroundRepeat: "repeat-x",
backgroundSize: "20px 1px",
backgroundImage: "radial-gradient(circle, #7E2AEA 6px, #F2F3F7 1px)",
backgroundImage:
"radial-gradient(circle, #7E2AEA 6px, #F2F3F7 1px)",
}}
/>
<PlusIcon />

@ -2,6 +2,7 @@ import { useParams } from "react-router-dom";
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { useDebouncedCallback } from "use-debounce";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -18,6 +19,16 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
const debounceAnswer = useDebouncedCallback((value) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.default = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<>
@ -30,8 +41,15 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
flexDirection: isMobile ? "column" : null,
}}
>
<Box sx={{ padding: isMobile ? "20px 20px 0px 20px" : "20px 20px 20px 20px", width: "100%" }}>
<Typography sx={{ marginBottom: "15px" }}>Настройки ответов</Typography>
<Box
sx={{
padding: isMobile ? "20px 20px 0px 20px" : "20px 20px 20px 20px",
width: "100%",
}}
>
<Typography sx={{ marginBottom: "15px" }}>
Настройки ответов
</Typography>
<CustomCheckbox
label={"Можно несколько"}
checked={listQuestions[quizId][totalIndex].content.multi}
@ -45,21 +63,21 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
}
/>
<Box sx={{ display: isMobile ? "none" : "block" }}>
<Typography sx={{ marginBottom: "15px" }}>Текст в выпадающем списке</Typography>
<Typography sx={{ marginBottom: "15px" }}>
Текст в выпадающем списке
</Typography>
<CustomTextField
sx={{ maxWidth: "360px" }}
placeholder={"Выберите вариант"}
text={listQuestions[quizId][totalIndex].content.default}
onChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.default = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
onChange={({ target }) => debounceAnswer(target.value)}
/>
</Box>
</Box>
<Box sx={{ padding: "20px", width: "100%" }}>
<Typography sx={{ marginBottom: "15px" }}>Настройки вопросов</Typography>
<Typography sx={{ marginBottom: "15px" }}>
Настройки вопросов
</Typography>
<CustomCheckbox
label={"Необязательный вопрос"}
checked={!listQuestions[quizId][totalIndex].required}
@ -69,7 +87,9 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
});
}}
/>
<Box sx={{ position: "relative", display: "flex", alignItems: "center" }}>
<Box
sx={{ position: "relative", display: "flex", alignItems: "center" }}
>
<CustomCheckbox
label={"Внутреннее название вопроса"}
checked={listQuestions[quizId][totalIndex].content.innerNameCheck}
@ -87,33 +107,34 @@ export default function SettingDropDown({ totalIndex }: SettingDropDownProps) {
}}
/>
<InfoIcon
sx={{ position: isMobile ? "absolute" : null, display: "block", right: isMobile ? "30px" : null }}
sx={{
position: isMobile ? "absolute" : null,
display: "block",
right: isMobile ? "30px" : null,
}}
/>
</Box>
<Box sx={{ width: "85%", pt: "20px", display: isMobile ? "block" : "none" }}>
<Typography sx={{ marginBottom: "15px" }}>Текст в выпадающем списке</Typography>
<Box
sx={{
width: "85%",
pt: "20px",
display: isMobile ? "block" : "none",
}}
>
<Typography sx={{ marginBottom: "15px" }}>
Текст в выпадающем списке
</Typography>
<CustomTextField
sx={{}}
placeholder={"Выберите вариант"}
text={listQuestions[quizId][totalIndex].content.default}
onChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.default = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
onChange={({ target }) => debounceAnswer(target.value)}
/>
</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,
});
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -6,6 +6,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon";
@ -21,6 +22,11 @@ export default function SettingEmoji({ totalIndex }: SettingEmojiProps) {
const theme = useTheme();
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box
@ -98,11 +104,7 @@ export default function SettingEmoji({ totalIndex }: SettingEmojiProps) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -6,6 +6,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon";
@ -24,6 +25,21 @@ export default function SettingOptionsAndPict({
const theme = useTheme();
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
const isMobile = useMediaQuery(theme.breakpoints.down(680));
const debounced = useDebouncedCallback((replText) => {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
replText,
},
});
}, 1000);
const debounceDescription = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}, 1000);
return (
<>
@ -60,14 +76,7 @@ export default function SettingOptionsAndPict({
sx={{ maxWidth: "330px", width: "100%" }}
placeholder={"Пример текста"}
text={listQuestions[quizId][totalIndex].content.replText}
onChange={({ target }) => {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
replText: target.value,
},
});
}}
onChange={({ target }) => debounced(target.value)}
/>
</>
)}
@ -123,13 +132,7 @@ export default function SettingOptionsAndPict({
<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,
});
}}
onChange={({ target }) => debounceDescription(target.value)}
/>
)}
{isWrappColumn && (
@ -141,14 +144,7 @@ export default function SettingOptionsAndPict({
sx={{ maxWidth: "330px", width: "100%" }}
placeholder={"Пример текста"}
text={listQuestions[quizId][totalIndex].content.replText}
onChange={({ target }) => {
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
replText: target.value,
},
});
}}
onChange={({ target }) => debounced(target.value)}
/>
</>
)}

@ -10,6 +10,7 @@ import {
} from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { useDebouncedCallback } from "use-debounce";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -85,6 +86,13 @@ export default function SettingOpytionsPict({
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}, 1000);
useEffect(() => {
if (!listQuestions[quizId][totalIndex].content.xy) {
@ -254,13 +262,7 @@ export default function SettingOpytionsPict({
<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,
});
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -1,6 +1,7 @@
import { useState } from "react";
import { useParams } from "react-router-dom";
import { Box, Typography, Tooltip, useTheme } from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomTextField from "@ui_kit/CustomTextField";
import ButtonsOptions from "../ButtonsOptions";
@ -10,8 +11,6 @@ import { questionStore, updateQuestionsList } from "@root/questions";
import InfoIcon from "../../../assets/icons/InfoIcon";
import type { ChangeEvent } from "react";
interface Props {
totalIndex: number;
}
@ -20,6 +19,11 @@ export default function OwnTextField({ totalIndex }: Props) {
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
const theme = useTheme();
const debounced = useDebouncedCallback((value) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.placeholder = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
const SSHC = (data: string) => {
setSwitchState(data);
@ -40,11 +44,7 @@ export default function OwnTextField({ totalIndex }: Props) {
<CustomTextField
placeholder={"Пример ответа"}
text={listQuestions[quizId][totalIndex].content.placeholder}
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.placeholder = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
onChange={({ target }) => debounced(target.value)}
/>
<Box sx={{ display: "flex", alignItems: "center", gap: "12px" }}>
<Typography

@ -10,6 +10,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
@ -42,6 +43,11 @@ export default function SettingTextField({
const theme = useTheme();
const isWrapperColumn = useMediaQuery(theme.breakpoints.down(980));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box
@ -138,11 +144,7 @@ export default function SettingTextField({
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -1,6 +1,7 @@
import { useState } from "react";
import { useParams } from "react-router-dom";
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import ButtonsOptions from "../ButtonsOptions";
import CustomTextField from "@ui_kit/CustomTextField";
import AddImage from "../../../assets/icons/questionsPage/addImage";
@ -26,6 +27,11 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(980));
const isMobile = useMediaQuery(theme.breakpoints.down(780));
const debounced = useDebouncedCallback((value) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.text = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
const SSHC = (data: string) => {
setSwitchState(data);
@ -47,15 +53,16 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
<CustomTextField
placeholder={"Можно добавить текст"}
text={listQuestions[quizId][totalIndex].content.text}
onChange={({ target }) => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.text = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
onChange={({ target }) => debounced(target.value)}
/>
</Box>
<Box
sx={{ display: "flex", alignItems: "center", gap: "12px", justifyContent: isMobile ? "space-between" : null }}
sx={{
display: "flex",
alignItems: "center",
gap: "12px",
justifyContent: isMobile ? "space-between" : null,
}}
>
<Box
onClick={() => setOpenImageModal(true)}
@ -129,7 +136,11 @@ export default function PageOptions({ disableInput, totalIndex }: Props) {
/>
</Box>
</Box>
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<ButtonsOptions
switchState={switchState}
SSHC={SSHC}
totalIndex={totalIndex}
/>
<SwitchPageOptions switchState={switchState} totalIndex={totalIndex} />
</>
);

@ -2,6 +2,7 @@ import { useParams } from "react-router-dom";
import { Box, Typography, Tooltip } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { useDebouncedCallback } from "use-debounce";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -16,6 +17,13 @@ export default function SettingPageOptions({
}: SettingPageOptionsProps) {
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, {
content: clonContent,
});
}, 1000);
return (
<Box sx={{ display: "flex", flexDirection: "column", padding: "20px" }}>
@ -47,13 +55,7 @@ export default function SettingPageOptions({
<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,
});
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -1,9 +1,20 @@
import { Box, Button, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material";
import {
Box,
Button,
IconButton,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import AddPlus from "../../assets/icons/questionsPage/addPlus";
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
import { quizStore } from "@root/quizes";
import { useParams } from "react-router-dom";
import { questionStore, createQuestion, updateQuestionsList } from "@root/questions";
import {
questionStore,
createQuestion,
updateQuestionsList,
} from "@root/questions";
import { DraggableList } from "./DraggableList";
export default function QuestionsPage() {
@ -72,7 +83,10 @@ export default function QuestionsPage() {
<AddPlus />
</IconButton>
<Box sx={{ display: "flex", gap: "8px" }}>
<Button variant="outlined" sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}>
<Button
variant="outlined"
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
>
<ArrowLeft />
</Button>
<Button

@ -8,6 +8,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
@ -34,6 +35,11 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
const { listQuestions } = questionStore();
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
const buttonRatingForm: ButtonRatingFrom[] = [
{ name: "star", icon: <StarIconMini color={theme.palette.grey3.main} /> },
@ -160,11 +166,7 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -6,6 +6,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import InfoIcon from "../../../assets/icons/InfoIcon";
@ -21,6 +22,11 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
const theme = useTheme();
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box
@ -81,11 +87,7 @@ export default function SettingSlider({ totalIndex }: SettingSliderProps) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -2,6 +2,7 @@ import { useParams } from "react-router-dom";
import { Box, Typography, Tooltip } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import CustomTextField from "@ui_kit/CustomTextField";
import { useDebouncedCallback } from "use-debounce";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -14,6 +15,11 @@ type SettingsUploadProps = {
export default function SettingsUpload({ totalIndex }: SettingsUploadProps) {
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box sx={{ display: "flex", flexDirection: "column", padding: "20px" }}>
@ -64,11 +70,7 @@ export default function SettingsUpload({ totalIndex }: SettingsUploadProps) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -6,6 +6,7 @@ import {
useMediaQuery,
useTheme,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import InfoIcon from "../../../assets/icons/InfoIcon";
import CustomTextField from "@ui_kit/CustomTextField";
@ -21,6 +22,11 @@ export default function ResponseSettings({ totalIndex }: Props) {
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(900));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.innerName = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
return (
<Box
@ -107,11 +113,7 @@ export default function ResponseSettings({ totalIndex }: Props) {
<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 });
}}
onChange={({ target }) => debounced(target.value)}
/>
)}
</Box>

@ -1,8 +1,9 @@
import { useState } from "react";
import { Box, ButtonBase, Typography } from "@mui/material";
import { useParams } from "react-router-dom";
import SelectableButton from "@ui_kit/SelectableButton";
import CustomTextField from "@ui_kit/CustomTextField";
import { useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import UploadIcon from "../../assets/icons/UploadIcon";
import UploadBox from "@ui_kit/UploadBox";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -19,6 +20,11 @@ export default function HelpQuestions({ totalIndex }: HelpQuestionsProps) {
const [backgroundType, setBackgroundType] = useState<BackgroundType>("text");
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
const debounced = useDebouncedCallback((value) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.hint.text = value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}, 1000);
const videoHC = (url: string) => {
const clonContent = listQuestions[quizId][totalIndex].content;
@ -62,11 +68,7 @@ export default function HelpQuestions({ totalIndex }: HelpQuestionsProps) {
<CustomTextField
placeholder={"Текст консультанта"}
text={listQuestions[quizId][totalIndex].content.hint.text}
onChange={({ target }) => {
let clonContent = listQuestions[quizId][totalIndex].content;
clonContent.hint.text = target.value;
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}
onChange={({ target }) => debounced(target.value)}
/>
</>
) : (

@ -9186,6 +9186,11 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
use-debounce@^9.0.4:
version "9.0.4"
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-9.0.4.tgz#51d25d856fbdfeb537553972ce3943b897f1ac85"
integrity sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==
use-memo-one@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"