новый ответ на вопрос получает фокус
This commit is contained in:
parent
751d9eb4f3
commit
862ed4f395
@ -12,7 +12,7 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { addQuestionVariant, deleteQuestionVariant, setQuestionVariantField, updateQuestion } from "@root/questions/actions";
|
import { addQuestionVariant, deleteQuestionVariant, setQuestionVariantField, updateQuestion } from "@root/questions/actions";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { memo, type ChangeEvent, type FC, type KeyboardEvent, type ReactNode } from "react";
|
import { memo, useCallback, type ChangeEvent, type FC, type KeyboardEvent, type ReactNode } from "react";
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
import type { QuestionVariant, QuizQuestionVariant } from "@frontend/squzanswerer";
|
import type { QuestionVariant, QuizQuestionVariant } from "@frontend/squzanswerer";
|
||||||
|
|
||||||
@ -28,10 +28,13 @@ type AnswerItemProps = {
|
|||||||
additionalMobile?: ReactNode;
|
additionalMobile?: ReactNode;
|
||||||
isOwn: boolean;
|
isOwn: boolean;
|
||||||
ownPlaceholder: string;
|
ownPlaceholder: string;
|
||||||
|
shouldAutoFocus?: boolean;
|
||||||
|
onFocusHandled?: () => void;
|
||||||
|
onEnterKeyPress?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AnswerItem = memo<AnswerItemProps>(
|
const AnswerItem = memo<AnswerItemProps>(
|
||||||
({ index, variant, questionId, largeCheck = false, additionalContent, additionalMobile, disableKeyDown, isOwn, ownPlaceholder }) => {
|
({ index, variant, questionId, largeCheck = false, additionalContent, additionalMobile, disableKeyDown, isOwn, ownPlaceholder, shouldAutoFocus, onFocusHandled, onEnterKeyPress }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
@ -41,6 +44,26 @@ const AnswerItem = memo<AnswerItemProps>(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inputRefCallback = useCallback((element: HTMLInputElement | null) => {
|
||||||
|
if (element && shouldAutoFocus) {
|
||||||
|
element.focus();
|
||||||
|
onFocusHandled?.();
|
||||||
|
}
|
||||||
|
}, [shouldAutoFocus, onFocusHandled]);
|
||||||
|
|
||||||
|
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (disableKeyDown) {
|
||||||
|
enqueueSnackbar("100 максимальное количество");
|
||||||
|
} else if (event.code === "Enter" && !largeCheck) {
|
||||||
|
if (onEnterKeyPress) {
|
||||||
|
onEnterKeyPress();
|
||||||
|
} else {
|
||||||
|
// Fallback если onEnterKeyPress не передан
|
||||||
|
addQuestionVariant(questionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable
|
<Draggable
|
||||||
@ -64,10 +87,11 @@ const AnswerItem = memo<AnswerItemProps>(
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
|
inputRef={inputRefCallback}
|
||||||
value={isOwn ? ownPlaceholder : variant.answer}
|
value={isOwn ? ownPlaceholder : variant.answer}
|
||||||
fullWidth
|
fullWidth
|
||||||
focused={false}
|
focused={false}
|
||||||
placeholder={isOwn ? "Добавьте текст-подсказку для ввода “своего ответа”" : "Добавьте ответ"}
|
placeholder={isOwn ? "Добавьте текст-подсказку для ввода \"своего ответа\"" : "Добавьте ответ"}
|
||||||
multiline={largeCheck}
|
multiline={largeCheck}
|
||||||
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
|
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (target.value.length <= 1000) {
|
if (target.value.length <= 1000) {
|
||||||
@ -79,13 +103,7 @@ const AnswerItem = memo<AnswerItemProps>(
|
|||||||
enqueueSnackbar("Превышена длина вводимого текста")
|
enqueueSnackbar("Превышена длина вводимого текста")
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
onKeyDown={handleKeyDown}
|
||||||
if (disableKeyDown) {
|
|
||||||
enqueueSnackbar("100 максимальное количество");
|
|
||||||
} else if (event.code === "Enter" && !largeCheck) {
|
|
||||||
addQuestionVariant(questionId);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: (
|
startAdornment: (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -16,6 +16,9 @@ type Props = Omit<
|
|||||||
openImageUploadModal: () => void;
|
openImageUploadModal: () => void;
|
||||||
isOwn: boolean;
|
isOwn: boolean;
|
||||||
ownPlaceholder: string;
|
ownPlaceholder: string;
|
||||||
|
shouldAutoFocus?: boolean;
|
||||||
|
onFocusHandled?: () => void;
|
||||||
|
onEnterKeyPress?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ImageEditAnswerItem({
|
export default function ImageEditAnswerItem({
|
||||||
@ -31,6 +34,9 @@ export default function ImageEditAnswerItem({
|
|||||||
openImageUploadModal,
|
openImageUploadModal,
|
||||||
isOwn,
|
isOwn,
|
||||||
ownPlaceholder,
|
ownPlaceholder,
|
||||||
|
shouldAutoFocus,
|
||||||
|
onFocusHandled,
|
||||||
|
onEnterKeyPress,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const addOrEditImageButton = useMemo(() => {
|
const addOrEditImageButton = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -111,6 +117,9 @@ export default function ImageEditAnswerItem({
|
|||||||
additionalMobile={addOrEditImageButtonMobile}
|
additionalMobile={addOrEditImageButtonMobile}
|
||||||
isOwn={isOwn}
|
isOwn={isOwn}
|
||||||
ownPlaceholder={ownPlaceholder}
|
ownPlaceholder={ownPlaceholder}
|
||||||
|
shouldAutoFocus={shouldAutoFocus}
|
||||||
|
onFocusHandled={onFocusHandled}
|
||||||
|
onEnterKeyPress={onEnterKeyPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
||||||
import { useAddAnswer } from "../../../utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "../../../utils/questionVariants";
|
||||||
import { AnswerDraggableList } from "../AnswerDraggableList";
|
import { AnswerDraggableList } from "../AnswerDraggableList";
|
||||||
import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
|
import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
|
||||||
import SwitchDropDown from "./switchDropDown";
|
import SwitchDropDown from "./switchDropDown";
|
||||||
@ -16,7 +16,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function DropDown({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
export default function DropDown({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
||||||
const {onClickAddAnAnswer} = useAddAnswer();
|
const {addVariantWithFocus, addVariantOnEnter, focusedVariantId, clearFocusedVariant} = useQuestionVariantsWithFocus();
|
||||||
const [switchState, setSwitchState] = useState("setting");
|
const [switchState, setSwitchState] = useState("setting");
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
@ -50,6 +50,11 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
|||||||
disableKeyDown={question.content.variants.length >= 100}
|
disableKeyDown={question.content.variants.length >= 100}
|
||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
|
isOwn={Boolean(variant?.isOwn)}
|
||||||
|
ownPlaceholder={question.content.ownPlaceholder || ""}
|
||||||
|
shouldAutoFocus={focusedVariantId === variant.id}
|
||||||
|
onFocusHandled={clearFocusedVariant}
|
||||||
|
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
/>
|
/>
|
||||||
@ -71,7 +76,7 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
|||||||
mr: "4px",
|
mr: "4px",
|
||||||
height: "19px",
|
height: "19px",
|
||||||
}}
|
}}
|
||||||
onClick={() => onClickAddAnAnswer(question)}
|
onClick={() => addVariantWithFocus(question)}
|
||||||
>
|
>
|
||||||
Добавьте ответ
|
Добавьте ответ
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { EmojiPicker } from "@ui_kit/EmojiPicker";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
||||||
import type { QuizQuestionEmoji } from "@frontend/squzanswerer";
|
import type { QuizQuestionEmoji } from "@frontend/squzanswerer";
|
||||||
import { useAddAnswer } from "../../../utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "../../../utils/questionVariants";
|
||||||
import { AnswerDraggableList } from "../AnswerDraggableList";
|
import { AnswerDraggableList } from "../AnswerDraggableList";
|
||||||
import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
|
import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
|
||||||
import EmojiAnswerItem from "./EmojiAnswerItem/EmojiAnswerItem";
|
import EmojiAnswerItem from "./EmojiAnswerItem/EmojiAnswerItem";
|
||||||
@ -19,7 +19,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function Emoji({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
export default function Emoji({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
||||||
const [switchState, setSwitchState] = useState<string>("setting");
|
const [switchState, setSwitchState] = useState<string>("setting");
|
||||||
const {onClickAddAnAnswer} = useAddAnswer();
|
const {addVariantWithFocus, addVariantOnEnter, focusedVariantId, clearFocusedVariant} = useQuestionVariantsWithFocus();
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const [anchorElement, setAnchorElement] = useState<HTMLDivElement | null>(null);
|
const [anchorElement, setAnchorElement] = useState<HTMLDivElement | null>(null);
|
||||||
const [selectedVariant, setSelectedVariant] = useState<string | null>(null);
|
const [selectedVariant, setSelectedVariant] = useState<string | null>(null);
|
||||||
@ -48,6 +48,9 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
|||||||
setSelectedVariant={setSelectedVariant}
|
setSelectedVariant={setSelectedVariant}
|
||||||
isOwn={Boolean(variant?.isOwn)}
|
isOwn={Boolean(variant?.isOwn)}
|
||||||
ownPlaceholder={question.content.ownPlaceholder}
|
ownPlaceholder={question.content.ownPlaceholder}
|
||||||
|
shouldAutoFocus={focusedVariantId === variant.id}
|
||||||
|
onFocusHandled={clearFocusedVariant}
|
||||||
|
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
/>
|
/>
|
||||||
@ -93,7 +96,7 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
|||||||
component="button"
|
component="button"
|
||||||
variant="body2"
|
variant="body2"
|
||||||
sx={{ color: theme.palette.brightPurple.main }}
|
sx={{ color: theme.palette.brightPurple.main }}
|
||||||
onClick={() => onClickAddAnAnswer(question)}
|
onClick={() => addVariantWithFocus(question)}
|
||||||
>
|
>
|
||||||
Добавьте ответ
|
Добавьте ответ
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -14,6 +14,9 @@ type Props = Omit<
|
|||||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
isOwn: boolean;
|
isOwn: boolean;
|
||||||
ownPlaceholder: string;
|
ownPlaceholder: string;
|
||||||
|
shouldAutoFocus?: boolean;
|
||||||
|
onFocusHandled?: () => void;
|
||||||
|
onEnterKeyPress?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function EmojiAnswerItem({
|
export default function EmojiAnswerItem({
|
||||||
@ -28,6 +31,9 @@ export default function EmojiAnswerItem({
|
|||||||
setOpen,
|
setOpen,
|
||||||
isOwn,
|
isOwn,
|
||||||
ownPlaceholder,
|
ownPlaceholder,
|
||||||
|
shouldAutoFocus,
|
||||||
|
onFocusHandled,
|
||||||
|
onEnterKeyPress,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
|
||||||
|
|
||||||
@ -99,6 +105,9 @@ export default function EmojiAnswerItem({
|
|||||||
additionalMobile={addOrEditImageButtonMobile}
|
additionalMobile={addOrEditImageButtonMobile}
|
||||||
isOwn={isOwn}
|
isOwn={isOwn}
|
||||||
ownPlaceholder={ownPlaceholder}
|
ownPlaceholder={ownPlaceholder}
|
||||||
|
shouldAutoFocus={shouldAutoFocus}
|
||||||
|
onFocusHandled={onFocusHandled}
|
||||||
|
onEnterKeyPress={onEnterKeyPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { updateQuestion } from "@root/questions/actions";
|
|||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
|
|
||||||
type SettingEmojiProps = {
|
type SettingEmojiProps = {
|
||||||
question: QuizQuestionEmoji;
|
question: QuizQuestionEmoji;
|
||||||
@ -17,7 +17,7 @@ type SettingEmojiProps = {
|
|||||||
|
|
||||||
const SettingEmoji = memo<SettingEmojiProps>(function ({ question, questionId, isRequired, isLargeCheck, isMulti, isOwn }) {
|
const SettingEmoji = memo<SettingEmojiProps>(function ({ question, questionId, isRequired, isLargeCheck, isMulti, isOwn }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const {switchOwn} = useAddAnswer();
|
const {switchOwnVariant} = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
@ -92,7 +92,7 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ question, questionId, i
|
|||||||
label={'Вариант "свой ответ"'}
|
label={'Вариант "свой ответ"'}
|
||||||
checked={isOwn}
|
checked={isOwn}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
switchOwn({question, checked:target.checked})
|
switchOwnVariant({question, checked:target.checked})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
addQuestionVariant,
|
|
||||||
clearQuestionImages,
|
clearQuestionImages,
|
||||||
uploadQuestionImage,
|
uploadQuestionImage,
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
||||||
@ -31,6 +31,7 @@ export default function OptionsAndPicture({
|
|||||||
const [switchState, setSwitchState] = useState("setting");
|
const [switchState, setSwitchState] = useState("setting");
|
||||||
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
||||||
const [openCropModal, setOpenCropModal] = useState(false);
|
const [openCropModal, setOpenCropModal] = useState(false);
|
||||||
|
const {addVariantWithFocus, addVariantOnEnter, focusedVariantId, clearFocusedVariant} = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
const [selectedVariantId, setSelectedVariantId] = useState<string | null>(
|
const [selectedVariantId, setSelectedVariantId] = useState<string | null>(
|
||||||
null,
|
null,
|
||||||
@ -111,6 +112,9 @@ export default function OptionsAndPicture({
|
|||||||
setSelectedVariantId={setSelectedVariantId}
|
setSelectedVariantId={setSelectedVariantId}
|
||||||
isOwn={Boolean(variant?.isOwn)}
|
isOwn={Boolean(variant?.isOwn)}
|
||||||
ownPlaceholder={question.content.ownPlaceholder}
|
ownPlaceholder={question.content.ownPlaceholder}
|
||||||
|
shouldAutoFocus={focusedVariantId === variant.id}
|
||||||
|
onFocusHandled={clearFocusedVariant}
|
||||||
|
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
/>
|
/>
|
||||||
@ -148,7 +152,7 @@ export default function OptionsAndPicture({
|
|||||||
height: "19px",
|
height: "19px",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addQuestionVariant(question.id);
|
addVariantWithFocus(question);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Добавьте ответ
|
Добавьте ответ
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
import type { QuizQuestionVarImg, QuizQuestionVariant } from "@frontend/squzanswerer";
|
import type { QuizQuestionVarImg, QuizQuestionVariant } from "@frontend/squzanswerer";
|
||||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import { updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
@ -19,7 +19,7 @@ type SettingOptionsAndPictProps = {
|
|||||||
|
|
||||||
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ question, questionId, ownPlaceholder, isMulti, isLargeCheck, replText, isRequired, isOwn }) {
|
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ question, questionId, ownPlaceholder, isMulti, isLargeCheck, replText, isRequired, isOwn }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { switchOwn } = useAddAnswer();
|
const { switchOwnVariant } = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
@ -73,7 +73,7 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ quest
|
|||||||
label={'Вариант "свой ответ"'}
|
label={'Вариант "свой ответ"'}
|
||||||
checked={isOwn}
|
checked={isOwn}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
switchOwn({ question, checked: target.checked })
|
switchOwnVariant({ question, checked: target.checked })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CustomCheckbox
|
<CustomCheckbox
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
|||||||
import type { QuizQuestionVarImg } from "@frontend/squzanswerer/dist-package/model/questionTypes/varimg";
|
import type { QuizQuestionVarImg } from "@frontend/squzanswerer/dist-package/model/questionTypes/varimg";
|
||||||
|
|
||||||
//@/model/questionTypes/images";
|
//@/model/questionTypes/images";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
import { useDisclosure } from "@/utils/useDisclosure";
|
import { useDisclosure } from "@/utils/useDisclosure";
|
||||||
import { AnswerDraggableList } from "../../AnswerDraggableList";
|
import { AnswerDraggableList } from "../../AnswerDraggableList";
|
||||||
import ImageEditAnswerItem from "../../AnswerDraggableList/ImageEditAnswerItem";
|
import ImageEditAnswerItem from "../../AnswerDraggableList/ImageEditAnswerItem";
|
||||||
@ -31,7 +31,7 @@ export default function OptionsPicture({
|
|||||||
setOpenBranchingPage,
|
setOpenBranchingPage,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const {onClickAddAnAnswer} = useAddAnswer();
|
const {addVariantWithFocus, addVariantOnEnter, focusedVariantId, clearFocusedVariant} = useQuestionVariantsWithFocus();
|
||||||
const quizQid = useCurrentQuiz()?.qid;
|
const quizQid = useCurrentQuiz()?.qid;
|
||||||
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
const [pictureUploding, setPictureUploading] = useState<boolean>(false);
|
||||||
const [openCropModal, setOpenCropModal] = useState(false);
|
const [openCropModal, setOpenCropModal] = useState(false);
|
||||||
@ -93,6 +93,9 @@ export default function OptionsPicture({
|
|||||||
setSelectedVariantId={setSelectedVariantId}
|
setSelectedVariantId={setSelectedVariantId}
|
||||||
isOwn={Boolean(variant?.isOwn)}
|
isOwn={Boolean(variant?.isOwn)}
|
||||||
ownPlaceholder={question.content.ownPlaceholder}
|
ownPlaceholder={question.content.ownPlaceholder}
|
||||||
|
shouldAutoFocus={focusedVariantId === variant.id}
|
||||||
|
onFocusHandled={clearFocusedVariant}
|
||||||
|
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
/>
|
/>
|
||||||
@ -117,7 +120,7 @@ export default function OptionsPicture({
|
|||||||
component="button"
|
component="button"
|
||||||
variant="body2"
|
variant="body2"
|
||||||
sx={{ color: theme.palette.brightPurple.main }}
|
sx={{ color: theme.palette.brightPurple.main }}
|
||||||
onClick={() => onClickAddAnAnswer(question)}
|
onClick={() => addVariantWithFocus(question)}
|
||||||
>
|
>
|
||||||
Добавьте ответ
|
Добавьте ответ
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import ProportionsIcon11 from "@/assets/icons/questionsPage/ProportionsIcon11";
|
|||||||
import ProportionsIcon12 from "@/assets/icons/questionsPage/ProportionsIcon12";
|
import ProportionsIcon12 from "@/assets/icons/questionsPage/ProportionsIcon12";
|
||||||
import ProportionsIcon21 from "@/assets/icons/questionsPage/ProportionsIcon21";
|
import ProportionsIcon21 from "@/assets/icons/questionsPage/ProportionsIcon21";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
|
|
||||||
type Proportion = "1:1" | "1:2" | "2:1";
|
type Proportion = "1:1" | "1:2" | "2:1";
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
|
|||||||
question.content.ownPlaceholder = replText;
|
question.content.ownPlaceholder = replText;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const {switchOwn} = useAddAnswer();
|
const {switchOwnVariant} = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -175,7 +175,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
|
|||||||
label={'Вариант "свой ответ"'}
|
label={'Вариант "свой ответ"'}
|
||||||
checked={isOwn}
|
checked={isOwn}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
switchOwn({question, checked:target.checked})
|
switchOwnVariant({question, checked:target.checked})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import ProportionsIcon11 from "@/assets/icons/questionsPage/ProportionsIcon11";
|
|||||||
import ProportionsIcon12 from "@/assets/icons/questionsPage/ProportionsIcon12";
|
import ProportionsIcon12 from "@/assets/icons/questionsPage/ProportionsIcon12";
|
||||||
import ProportionsIcon21 from "@/assets/icons/questionsPage/ProportionsIcon21";
|
import ProportionsIcon21 from "@/assets/icons/questionsPage/ProportionsIcon21";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
|
|
||||||
type Proportion = "1:1" | "1:2" | "2:1";
|
type Proportion = "1:1" | "1:2" | "2:1";
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
|
|||||||
question.content.ownPlaceholder = replText;
|
question.content.ownPlaceholder = replText;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const {switchOwn} = useAddAnswer();
|
const {switchOwnVariant} = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -175,7 +175,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
|
|||||||
label={'Вариант "свой ответ"'}
|
label={'Вариант "свой ответ"'}
|
||||||
checked={isOwn}
|
checked={isOwn}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
switchOwn({question, checked:target.checked})
|
switchOwnVariant({question, checked:target.checked})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
{/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
|
||||||
import type { QuizQuestionVariant } from "@frontend/squzanswerer";
|
import type { QuizQuestionVariant } from "@frontend/squzanswerer";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
import { AnswerDraggableList } from "../../AnswerDraggableList";
|
import { AnswerDraggableList } from "../../AnswerDraggableList";
|
||||||
import AnswerItem from "../../AnswerDraggableList/AnswerItem";
|
import AnswerItem from "../../AnswerDraggableList/AnswerItem";
|
||||||
import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
|
import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
|
||||||
@ -15,7 +15,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AnswerOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
export default function AnswerOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) {
|
||||||
const {onClickAddAnAnswer} = useAddAnswer();
|
const {addVariantWithFocus, addVariantOnEnter, focusedVariantId, clearFocusedVariant} = useQuestionVariantsWithFocus();
|
||||||
const [switchState, setSwitchState] = useState("setting");
|
const [switchState, setSwitchState] = useState("setting");
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
@ -55,6 +55,9 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
|
|||||||
variant={variant}
|
variant={variant}
|
||||||
isOwn={Boolean(variant.isOwn)}
|
isOwn={Boolean(variant.isOwn)}
|
||||||
ownPlaceholder={question.content.ownPlaceholder}
|
ownPlaceholder={question.content.ownPlaceholder}
|
||||||
|
shouldAutoFocus={focusedVariantId === variant.id}
|
||||||
|
onFocusHandled={clearFocusedVariant}
|
||||||
|
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
/>
|
/>
|
||||||
@ -77,7 +80,7 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
|
|||||||
mr: "4px",
|
mr: "4px",
|
||||||
height: "19px",
|
height: "19px",
|
||||||
}}
|
}}
|
||||||
onClick={() => onClickAddAnAnswer(question)}
|
onClick={() => addVariantWithFocus(question)}
|
||||||
>
|
>
|
||||||
Добавьте ответ
|
Добавьте ответ
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
|||||||
import type { QuizQuestionVariant } from "@frontend/squzanswerer";
|
import type { QuizQuestionVariant } from "@frontend/squzanswerer";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
|
import { useQuestionVariantsWithFocus } from "@/utils/questionVariants";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: QuizQuestionVariant;
|
question: QuizQuestionVariant;
|
||||||
@ -21,7 +21,7 @@ const ResponseSettings = memo<Props>(function ({question, questionId, ownPlaceho
|
|||||||
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const {switchOwn} = useAddAnswer();
|
const {switchOwnVariant} = useQuestionVariantsWithFocus();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -84,7 +84,7 @@ const ResponseSettings = memo<Props>(function ({question, questionId, ownPlaceho
|
|||||||
label={'Вариант "свой ответ"'}
|
label={'Вариант "свой ответ"'}
|
||||||
checked={isOwn}
|
checked={isOwn}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
switchOwn({question, checked:target.checked})
|
switchOwnVariant({question, checked:target.checked})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -327,7 +327,8 @@ export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
|||||||
requestQueue.enqueue(`updateQuestion-${questionId}`, request);
|
requestQueue.enqueue(`updateQuestion-${questionId}`, request);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addQuestionVariant = (questionId: string) => {
|
export const addQuestionVariant = (questionId: string): string => {
|
||||||
|
const newVariant = createQuestionVariant();
|
||||||
updateQuestion(questionId, (question) => {
|
updateQuestion(questionId, (question) => {
|
||||||
switch (question.type) {
|
switch (question.type) {
|
||||||
case "variant":
|
case "variant":
|
||||||
@ -335,12 +336,13 @@ export const addQuestionVariant = (questionId: string) => {
|
|||||||
case "select":
|
case "select":
|
||||||
case "images":
|
case "images":
|
||||||
case "varimg":
|
case "varimg":
|
||||||
question.content.variants.push(createQuestionVariant());
|
question.content.variants.push(newVariant);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Cannot add variant to question of type "${question.type}"`);
|
throw new Error(`Cannot add variant to question of type "${question.type}"`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return newVariant.id;
|
||||||
};
|
};
|
||||||
export const addQuestionOwnVariant = (questionId: string) => {
|
export const addQuestionOwnVariant = (questionId: string) => {
|
||||||
updateQuestion(questionId, (question) => {
|
updateQuestion(questionId, (question) => {
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
import { QuizQuestionsWithVariants } from "@frontend/squzanswerer";
|
|
||||||
import { addQuestionOwnVariant, addQuestionVariant, updateQuestion } from "@root/questions/actions";
|
|
||||||
|
|
||||||
export const useAddAnswer = () => {
|
|
||||||
const onClickAddAnAnswer = (question: QuizQuestionsWithVariants) => {
|
|
||||||
addQuestionVariant(question.id);
|
|
||||||
};
|
|
||||||
interface SwitchOwnProps {
|
|
||||||
question: QuizQuestionsWithVariants;
|
|
||||||
checked: boolean
|
|
||||||
}
|
|
||||||
const switchOwn = ({ question, checked }: SwitchOwnProps) => {
|
|
||||||
if (!question.content.variants.some(v => v.isOwn) && checked) {
|
|
||||||
addQuestionOwnVariant(question.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateQuestion<QuizQuestionVariant>(question.id, (question) => {
|
|
||||||
question.content.own = checked;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
onClickAddAnAnswer,
|
|
||||||
switchOwn
|
|
||||||
};
|
|
||||||
};
|
|
||||||
47
src/utils/questionVariants.ts
Normal file
47
src/utils/questionVariants.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { QuizQuestionsWithVariants, QuizQuestionVariant } from "@frontend/squzanswerer";
|
||||||
|
import { addQuestionOwnVariant, addQuestionVariant, updateQuestion } from "@root/questions/actions";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Утилита для управления вариантами ответов с автофокусом
|
||||||
|
*/
|
||||||
|
export const useQuestionVariantsWithFocus = () => {
|
||||||
|
const [focusedVariantId, setFocusedVariantId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const addVariantWithFocus = (question: QuizQuestionsWithVariants) => {
|
||||||
|
const newVariantId = addQuestionVariant(question.id);
|
||||||
|
setFocusedVariantId(newVariantId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addVariantOnEnter = (questionId: string) => {
|
||||||
|
const newVariantId = addQuestionVariant(questionId);
|
||||||
|
setFocusedVariantId(newVariantId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFocusedVariant = () => {
|
||||||
|
setFocusedVariantId(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SwitchOwnProps {
|
||||||
|
question: QuizQuestionsWithVariants;
|
||||||
|
checked: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchOwnVariant = ({ question, checked }: SwitchOwnProps) => {
|
||||||
|
if (!question.content.variants.some(v => v.isOwn) && checked) {
|
||||||
|
addQuestionOwnVariant(question.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateQuestion<QuizQuestionVariant>(question.id, (question) => {
|
||||||
|
question.content.own = checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
addVariantWithFocus,
|
||||||
|
addVariantOnEnter,
|
||||||
|
switchOwnVariant,
|
||||||
|
focusedVariantId,
|
||||||
|
clearFocusedVariant
|
||||||
|
};
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user