diff --git a/package.json b/package.json index f44d8ef6..cd513276 100755 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx b/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx index ac4f954c..ef5bc917 100644 --- a/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx +++ b/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx @@ -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(null); @@ -55,18 +67,6 @@ export const AnswerItem = ({ setIsOpen(false); }; - const onChangeText = (event: ChangeEvent) => { - 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" }} > debounced(target.value)} onKeyDown={(event: KeyboardEvent) => { if ( event.code === "Enter" && diff --git a/src/pages/Questions/DataOptions/settingData.tsx b/src/pages/Questions/DataOptions/settingData.tsx index 84dde286..91b966ac 100644 --- a/src/pages/Questions/DataOptions/settingData.tsx +++ b/src/pages/Questions/DataOptions/settingData.tsx @@ -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 ( { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/DraggableList/QuestionPageCard.tsx b/src/pages/Questions/DraggableList/QuestionPageCard.tsx index ecbd5e10..b052b6e3 100644 --- a/src/pages/Questions/DraggableList/QuestionPageCard.tsx +++ b/src/pages/Questions/DraggableList/QuestionPageCard.tsx @@ -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 ; + return ( + + ); case "images": - return ; + return ( + + ); case "varimg": - return ; + return ( + + ); case "emoji": - return ; + return ( + + ); case "text": - return ; + return ( + + ); case "select": - return ; + return ( + + ); case "date": - return ; + return ( + + ); case "number": - return ; + return ( + + ); case "file": - return ; + return ( + + ); case "page": - return ; + return ( + + ); case "rating": - return ; + return ( + + ); default: return <>; } }; -export default function QuestionsPageCard({ totalIndex, draggableProps, isDragging }: Props) { +export default function QuestionsPageCard({ + totalIndex, + draggableProps, + isDragging, +}: Props) { const [plusVisible, setPlusVisible] = useState(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 > { - updateQuestionsList(quizId, totalIndex, { - title: e.target.value, - }); - console.log(listQuestions[quizId][totalIndex].title); - }} + onChange={({ target }) => debounced(target.value)} InputProps={{ - startAdornment: {IconAndrom(isExpanded, switchState)}, + startAdornment: ( + + {IconAndrom(isExpanded, switchState)} + + ), }} 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 }} /> - - - updateQuestionsList(quizId, totalIndex, { expanded: !isExpanded })}> - {isExpanded ? : } + + + + updateQuestionsList(quizId, totalIndex, { + expanded: !isExpanded, + }) + } + > + {isExpanded ? ( + + ) : ( + + )} {isExpanded ? ( <> ) : ( } checkedIcon={} />} + control={ + } + checkedIcon={} + /> + } label={""} sx={{ color: theme.palette.grey2.main, @@ -164,7 +267,11 @@ export default function QuestionsPageCard({ totalIndex, draggableProps, isDraggi removeQuestion(quizId, totalIndex)} > @@ -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)", }} /> diff --git a/src/pages/Questions/DropDown/settingDropDown.tsx b/src/pages/Questions/DropDown/settingDropDown.tsx index d6dc8636..7c64908a 100644 --- a/src/pages/Questions/DropDown/settingDropDown.tsx +++ b/src/pages/Questions/DropDown/settingDropDown.tsx @@ -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, }} > - - Настройки ответов + + + Настройки ответов + - Текст в выпадающем списке + + Текст в выпадающем списке + { - const clonContent = listQuestions[quizId][totalIndex].content; - clonContent.default = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounceAnswer(target.value)} /> - Настройки вопросов + + Настройки вопросов + - + - - Текст в выпадающем списке + + + Текст в выпадающем списке + { - const clonContent = listQuestions[quizId][totalIndex].content; - clonContent.default = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounceAnswer(target.value)} /> {listQuestions[quizId][totalIndex].content.innerNameCheck && ( { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { - content: clonContent, - }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/Emoji/settingEmoji.tsx b/src/pages/Questions/Emoji/settingEmoji.tsx index 73de5e06..03d05790 100644 --- a/src/pages/Questions/Emoji/settingEmoji.tsx +++ b/src/pages/Questions/Emoji/settingEmoji.tsx @@ -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 ( { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx b/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx index 739f0b80..9a070ebb 100644 --- a/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx +++ b/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx @@ -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({ { - 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)} /> )} diff --git a/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx b/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx index 160fb621..ff9d611b 100644 --- a/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx +++ b/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx @@ -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({ { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { - content: clonContent, - }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/OwnTextField/OwnTextField.tsx b/src/pages/Questions/OwnTextField/OwnTextField.tsx index 80dd0391..3bf2cc64 100644 --- a/src/pages/Questions/OwnTextField/OwnTextField.tsx +++ b/src/pages/Questions/OwnTextField/OwnTextField.tsx @@ -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) { ) => { - const clonContent = listQuestions[quizId][totalIndex].content; - clonContent.placeholder = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounced(target.value)} /> { + let clonContent = listQuestions[quizId][totalIndex].content; + clonContent.innerName = value; + updateQuestionsList(quizId, totalIndex, { content: clonContent }); + }, 1000); return ( { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/PageOptions/PageOptions.tsx b/src/pages/Questions/PageOptions/PageOptions.tsx index b3bb106a..90426bf5 100644 --- a/src/pages/Questions/PageOptions/PageOptions.tsx +++ b/src/pages/Questions/PageOptions/PageOptions.tsx @@ -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) { { - const clonContent = listQuestions[quizId][totalIndex].content; - clonContent.text = target.value; - updateQuestionsList(quizId, totalIndex, { content: clonContent }); - }} + onChange={({ target }) => debounced(target.value)} /> setOpenImageModal(true)} @@ -129,7 +136,11 @@ export default function PageOptions({ disableInput, totalIndex }: Props) { /> - + ); diff --git a/src/pages/Questions/PageOptions/SettingPageOptions.tsx b/src/pages/Questions/PageOptions/SettingPageOptions.tsx index 3da6d2c8..8bde2b78 100644 --- a/src/pages/Questions/PageOptions/SettingPageOptions.tsx +++ b/src/pages/Questions/PageOptions/SettingPageOptions.tsx @@ -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 ( @@ -47,13 +55,7 @@ export default function SettingPageOptions({ { - let clonContent = listQuestions[quizId][totalIndex].content; - clonContent.innerName = target.value; - updateQuestionsList(quizId, totalIndex, { - content: clonContent, - }); - }} + onChange={({ target }) => debounced(target.value)} /> )} diff --git a/src/pages/Questions/QuestionsPage.tsx b/src/pages/Questions/QuestionsPage.tsx index 5fca60dd..1ecb607c 100755 --- a/src/pages/Questions/QuestionsPage.tsx +++ b/src/pages/Questions/QuestionsPage.tsx @@ -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() { -