ваиранты получили работающие новые фичи

This commit is contained in:
Nastya 2024-09-11 09:11:48 +03:00
parent 19b80694cb
commit 22f8e80d16
22 changed files with 131 additions and 135 deletions

@ -30,6 +30,17 @@ export function createQuestionVariant(): QuestionVariant {
answer: "", answer: "",
extendedText: "", extendedText: "",
hints: "", hints: "",
isOwn: false,
originalImageUrl: "",
};
}
export function createQuestionOwnVariant(): QuestionVariant {
return {
id: nanoid(),
answer: "",
extendedText: "",
hints: "",
isOwn: true,
originalImageUrl: "", originalImageUrl: "",
}; };
} }

@ -9,8 +9,6 @@ type AnswerItemProps = {
}; };
export const AnswerItem: FC<AnswerItemProps> = ({ fieldName, fieldValue, deleteHC }) => { export const AnswerItem: FC<AnswerItemProps> = ({ fieldName, fieldValue, deleteHC }) => {
console.log("AnswerItem")
console.log(fieldName)
const theme = useTheme(); const theme = useTheme();
return ( return (
<Box <Box

@ -32,7 +32,6 @@ export const SettingItem: FC<SettingItemProps> = ({
selectedTags, selectedTags,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
console.log(step)
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
if (step === 0) { if (step === 0) {
return; return;

@ -10,11 +10,11 @@ import {
useMediaQuery, useMediaQuery,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { addQuestionVariant, deleteQuestionVariant, setQuestionVariantField } 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, 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 } from "@frontend/squzanswerer"; import type { QuestionVariant, QuizQuestionVariant } from "@frontend/squzanswerer";
const TextField = MuiTextField as unknown as FC<TextFieldProps>; const TextField = MuiTextField as unknown as FC<TextFieldProps>;
@ -26,10 +26,11 @@ type AnswerItemProps = {
disableKeyDown?: boolean; disableKeyDown?: boolean;
additionalContent?: ReactNode; additionalContent?: ReactNode;
additionalMobile?: ReactNode; additionalMobile?: ReactNode;
isOwn: boolean;
}; };
const AnswerItem = memo<AnswerItemProps>( const AnswerItem = memo<AnswerItemProps>(
({ index, variant, questionId, largeCheck = false, additionalContent, additionalMobile, disableKeyDown }) => { ({ index, variant, questionId, largeCheck = false, additionalContent, additionalMobile, disableKeyDown, isOwn }) => {
const theme = useTheme(); const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(790)); const isTablet = useMediaQuery(theme.breakpoints.down(790));
@ -58,7 +59,7 @@ const AnswerItem = memo<AnswerItemProps>(
value={variant.answer} value={variant.answer}
fullWidth fullWidth
focused={false} focused={false}
placeholder={"Добавьте ответ"} placeholder={isOwn ? "Добавьте текст-подсказку для ввода “своего ответа”" : "Добавьте ответ"}
multiline={largeCheck} multiline={largeCheck}
onChange={({ target }: ChangeEvent<HTMLInputElement>) => { onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
if (target.value.length <= 1000) { if (target.value.length <= 1000) {
@ -67,7 +68,7 @@ const AnswerItem = memo<AnswerItemProps>(
}} }}
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => { onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
if (disableKeyDown) { if (disableKeyDown) {
enqueueSnackbar("100 максимальное количество вопросов"); enqueueSnackbar("100 максимальное количество");
} else if (event.code === "Enter" && !largeCheck) { } else if (event.code === "Enter" && !largeCheck) {
addQuestionVariant(questionId); addQuestionVariant(questionId);
} }
@ -88,7 +89,13 @@ const AnswerItem = memo<AnswerItemProps>(
<InputAdornment position="end"> <InputAdornment position="end">
<IconButton <IconButton
sx={{ padding: "0" }} sx={{ padding: "0" }}
onClick={() => deleteQuestionVariant(questionId, variant.id)} onClick={() => {
isOwn ? updateQuestion<QuizQuestionVariant>(questionId, (question) => {
question.content.own = false;
})
:
deleteQuestionVariant(questionId, variant.id)
}}
> >
<DeleteIcon <DeleteIcon
style={{ style={{
@ -104,7 +111,7 @@ const AnswerItem = memo<AnswerItemProps>(
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
padding: additionalContent ? "5px 13px" : "13px", padding: additionalContent ? "5px 13px" : "13px",
borderRadius: "10px", borderRadius: "10px",
background: "#ffffff", background: isOwn ? "#F2F3F7" : "white",
"& input.MuiInputBase-input": { "& input.MuiInputBase-input": {
height: "22px", height: "22px",
}, },

@ -14,6 +14,7 @@ type Props = Omit<
originalImageUrl?: string | null | undefined, originalImageUrl?: string | null | undefined,
) => Promise<void>; ) => Promise<void>;
openImageUploadModal: () => void; openImageUploadModal: () => void;
isOwn: boolean;
}; };
export default function ImageEditAnswerItem({ export default function ImageEditAnswerItem({
@ -27,6 +28,7 @@ export default function ImageEditAnswerItem({
pictureUploding, pictureUploding,
openCropModal, openCropModal,
openImageUploadModal, openImageUploadModal,
isOwn,
}: Props) { }: Props) {
const addOrEditImageButton = useMemo(() => { const addOrEditImageButton = useMemo(() => {
return ( return (
@ -105,6 +107,7 @@ export default function ImageEditAnswerItem({
variant={variant} variant={variant}
additionalContent={addOrEditImageButton} additionalContent={addOrEditImageButton}
additionalMobile={addOrEditImageButtonMobile} additionalMobile={addOrEditImageButtonMobile}
isOwn={isOwn}
/> />
); );
} }

@ -18,7 +18,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 {onClickAddAnAnswer} = useAddAnswer();
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);
@ -29,9 +29,12 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
return ( return (
<> <>
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<AnswerDraggableList <AnswerDraggableList
questionId={question.id} questionId={question.id}
variants={question.content.variants.map((variant, index) => ( variants={question.content.variants
.filter(variant => !variant.isOwn ? true : question.content.own && variant.isOwn)
.map((variant, index) => (
<EmojiAnswerItem <EmojiAnswerItem
key={variant.id} key={variant.id}
index={index} index={index}
@ -42,9 +45,11 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
setAnchorElement={setAnchorElement} setAnchorElement={setAnchorElement}
setOpen={setOpen} setOpen={setOpen}
setSelectedVariant={setSelectedVariant} setSelectedVariant={setSelectedVariant}
isOwn={Boolean(variant?.isOwn)}
/> />
))} ))}
/> />
<Popover <Popover
open={open} open={open}
anchorEl={anchorElement} anchorEl={anchorElement}

@ -2,6 +2,7 @@ import { ComponentPropsWithoutRef, useMemo } from "react";
import AnswerItem from "../../AnswerDraggableList/AnswerItem"; import AnswerItem from "../../AnswerDraggableList/AnswerItem";
import VariantAdornment from "./VariantAdornment"; import VariantAdornment from "./VariantAdornment";
import VariantAdornmentMobile from "./VariantAdornmentMobile"; import VariantAdornmentMobile from "./VariantAdornmentMobile";
import { updateQuestion } from "@/stores/questions/actions";
type Props = Omit< type Props = Omit<
ComponentPropsWithoutRef<typeof AnswerItem>, ComponentPropsWithoutRef<typeof AnswerItem>,
@ -11,6 +12,7 @@ type Props = Omit<
setAnchorElement: React.Dispatch<React.SetStateAction<HTMLDivElement | null>>; setAnchorElement: React.Dispatch<React.SetStateAction<HTMLDivElement | null>>;
setSelectedVariant: React.Dispatch<React.SetStateAction<string | null>>; setSelectedVariant: React.Dispatch<React.SetStateAction<string | null>>;
setOpen: React.Dispatch<React.SetStateAction<boolean>>; setOpen: React.Dispatch<React.SetStateAction<boolean>>;
isOwn: boolean;
}; };
export default function EmojiAnswerItem({ export default function EmojiAnswerItem({
@ -23,7 +25,17 @@ export default function EmojiAnswerItem({
setAnchorElement, setAnchorElement,
setSelectedVariant, setSelectedVariant,
setOpen, setOpen,
isOwn
}: Props) { }: Props) {
const setOwnPlaceholder = (replText: string) => {
updateQuestion(questionId, (question) => {
if (question.type !== "varimg") return;
question.content.ownPlaceholder = replText;
});
};
const addOrEditImageButton = useMemo(() => { const addOrEditImageButton = useMemo(() => {
return ( return (
!isTablet && ( !isTablet && (
@ -77,6 +89,8 @@ export default function EmojiAnswerItem({
variant={variant} variant={variant}
additionalContent={addOrEditImageButton} additionalContent={addOrEditImageButton}
additionalMobile={addOrEditImageButtonMobile} additionalMobile={addOrEditImageButtonMobile}
isOwn={isOwn}
changeOwnText={setOwnPlaceholder}
/> />
); );
} }

@ -1,11 +1,13 @@
import type { QuizQuestionEmoji, QuizQuestionVariant } from "@frontend/squzanswerer"; import type { QuestionType, QuizQuestionEmoji, 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";
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";
type SettingEmojiProps = { type SettingEmojiProps = {
question: QuizQuestionEmoji;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isMulti: boolean; isMulti: boolean;
@ -13,8 +15,10 @@ type SettingEmojiProps = {
isLargeCheck?: boolean; isLargeCheck?: boolean;
}; };
const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, ownPlaceholder, 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 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));
const isTablet = useMediaQuery(theme.breakpoints.down(985)); const isTablet = useMediaQuery(theme.breakpoints.down(985));
@ -60,7 +64,7 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, ownPlacehol
> >
Настройки ответов Настройки ответов
</Typography> </Typography>
<CustomCheckbox {/* <CustomCheckbox
dataCy="checkbox-long-text-answer" dataCy="checkbox-long-text-answer"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Многострочный ответ"} label={"Многострочный ответ"}
@ -70,7 +74,7 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, ownPlacehol
question.content.largeCheck = target.checked; question.content.largeCheck = target.checked;
}); });
}} }}
/> /> */}
<CustomCheckbox <CustomCheckbox
dataCy="checkbox-multiple-answers" dataCy="checkbox-multiple-answers"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
@ -88,12 +92,10 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, ownPlacehol
label={'Вариант "свой ответ"'} label={'Вариант "свой ответ"'}
checked={isOwn} checked={isOwn}
handleChange={({ target }) => { handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => { switchOwn({question, checked:target.checked})
question.content.own = target.checked;
});
}} }}
/> />
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}> {/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography <Typography
sx={{ sx={{
height: isMobile ? "18px" : "auto", height: isMobile ? "18px" : "auto",
@ -116,7 +118,7 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, ownPlacehol
value={ownPlaceholder} value={ownPlaceholder}
onChange={({ target }) => setOwnPlaceholder(target.value)} onChange={({ target }) => setOwnPlaceholder(target.value)}
/> />
</Box> </Box> */}
</Box> </Box>
<Box <Box
sx={{ sx={{

@ -12,6 +12,7 @@ export default function SwitchEmoji({ switchState = "setting", question }: Props
case "setting": case "setting":
return ( return (
<SettingEmoji <SettingEmoji
question={question}
questionId={question.id} questionId={question.id}
isRequired={question.content.required} isRequired={question.content.required}
isOwn={question.content.own} isOwn={question.content.own}

@ -73,7 +73,9 @@ export default function OptionsAndPicture({ question, setOpenBranchingPage }: Pr
<Box sx={{ pl: "20px", pr: "20px" }}> <Box sx={{ pl: "20px", pr: "20px" }}>
<AnswerDraggableList <AnswerDraggableList
questionId={question.id} questionId={question.id}
variants={question.content.variants.map((variant, index) => ( variants={question.content.variants
.filter(variant => !variant.isOwn ? true : question.content.own && variant.isOwn)
.map((variant, index) => (
<ImageEditAnswerItem <ImageEditAnswerItem
key={variant.id} key={variant.id}
index={index} index={index}
@ -86,6 +88,7 @@ export default function OptionsAndPicture({ question, setOpenBranchingPage }: Pr
openImageUploadModal={openImageUploadModal} openImageUploadModal={openImageUploadModal}
pictureUploding={pictureUploding} pictureUploding={pictureUploding}
setSelectedVariantId={setSelectedVariantId} setSelectedVariantId={setSelectedVariantId}
isOwn={Boolean(variant?.isOwn)}
/> />
))} ))}
/> />

@ -1,3 +1,4 @@
import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
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";
@ -13,14 +14,18 @@ type SettingOptionsAndPictProps = {
isOwn: boolean; isOwn: boolean;
ownPlaceholder?: boolean; ownPlaceholder?: boolean;
isMulti?: boolean; isMulti?: boolean;
question: QuizQuestionVarImg;
}; };
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ 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 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));
const isTablet = useMediaQuery(theme.breakpoints.down(985)); const isTablet = useMediaQuery(theme.breakpoints.down(985));
const isMobile = useMediaQuery(theme.breakpoints.down(680)); const isMobile = useMediaQuery(theme.breakpoints.down(680));
const setReplText = (replText: string) => { const setReplText = (replText: string) => {
updateQuestion(questionId, (question) => { updateQuestion(questionId, (question) => {
@ -29,13 +34,6 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ quest
question.content.replText = replText; question.content.replText = replText;
}); });
}; };
const setOwnPlaceholder = (replText: string) => {
updateQuestion(questionId, (question) => {
if (question.type !== "varimg") return;
question.content.ownPlaceholder = replText;
});
};
return ( return (
<> <>
@ -69,63 +67,15 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ quest
> >
Настройки ответов Настройки ответов
</Typography> </Typography>
<CustomCheckbox
dataCy="checkbox-long-text-answer"
sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Многострочный ответ"}
checked={isLargeCheck}
handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
question.content.largeCheck = target.checked;
});
}}
/>
<CustomCheckbox
dataCy="checkbox-multiple-answers"
sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Можно несколько"}
checked={isMulti}
handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
question.content.multi = target.checked;
});
}}
/>
<CustomCheckbox <CustomCheckbox
dataCy="checkbox-own-answer" dataCy="checkbox-own-answer"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
label={'Вариант "свой ответ"'} label={'Вариант "свой ответ"'}
checked={isOwn} checked={isOwn}
handleChange={({ target }) => { handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => { switchOwn({question, checked:target.checked})
question.content.own = target.checked;
});
}} }}
/> />
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography
sx={{
height: isMobile ? "18px" : "auto",
fontWeight: "500",
fontSize: "18px",
color: " #4D4D4D",
mb: "14px",
}}
>
Подсказка "своего ответа"
</Typography>
<CustomTextField
sx={{
maxWidth: "330px",
width: "100%",
mr: isMobile ? "0px" : "16px",
}}
maxLength={60}
placeholder={"мой ответ: три"}
value={ownPlaceholder}
onChange={({ target }) => setOwnPlaceholder(target.value)}
/>
</Box>
{!isWrappColumn && ( {!isWrappColumn && (
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}> <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography <Typography

@ -9,11 +9,11 @@ interface Props {
} }
export default function SwitchOptionsAndPict({ switchState = "setting", question }: Props) { export default function SwitchOptionsAndPict({ switchState = "setting", question }: Props) {
console.log(question)
switch (switchState) { switch (switchState) {
case "setting": case "setting":
return ( return (
<SettingOptionsAndPict <SettingOptionsAndPict
question={question}
questionId={question.id} questionId={question.id}
replText={question.content.replText} replText={question.content.replText}
isRequired={question.content.required} isRequired={question.content.required}

@ -28,8 +28,7 @@ export default function OptionsPicture({ question, openBranchingPage, setOpenBra
const [switchState, setSwitchState] = useState("setting"); const [switchState, setSwitchState] = useState("setting");
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure(); const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure();
const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } = const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } = useCropModalState();
useCropModalState();
const handleImageUpload = async (file: File) => { const handleImageUpload = async (file: File) => {
if (!selectedVariantId) return; if (!selectedVariantId) return;
@ -70,7 +69,9 @@ export default function OptionsPicture({ question, openBranchingPage, setOpenBra
<Box sx={{ padding: "20px" }}> <Box sx={{ padding: "20px" }}>
<AnswerDraggableList <AnswerDraggableList
questionId={question.id} questionId={question.id}
variants={question.content.variants.map((variant, index) => ( variants={question.content.variants
.filter(variant => !variant.isOwn ? true : question.content.own && variant.isOwn)
.map((variant, index) => (
<ImageEditAnswerItem <ImageEditAnswerItem
key={variant.id} key={variant.id}
index={index} index={index}
@ -83,6 +84,7 @@ export default function OptionsPicture({ question, openBranchingPage, setOpenBra
openImageUploadModal={openImageUploadModal} openImageUploadModal={openImageUploadModal}
pictureUploding={pictureUploding} pictureUploding={pictureUploding}
setSelectedVariantId={setSelectedVariantId} setSelectedVariantId={setSelectedVariantId}
isOwn={Boolean(variant?.isOwn)}
/> />
))} ))}
/> />

@ -9,6 +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";
type Proportion = "1:1" | "1:2" | "2:1"; type Proportion = "1:1" | "1:2" | "2:1";
@ -36,6 +37,7 @@ const FORMATS: FormatItem[] = [
]; ];
type SettingOptionsPictProps = { type SettingOptionsPictProps = {
question: QuizQuestionVariant;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isMulti: boolean; isMulti: boolean;
@ -47,6 +49,7 @@ type SettingOptionsPictProps = {
}; };
const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
question,
questionId, questionId,
isRequired, isRequired,
ownPlaceholder, isMulti, isLargeCheck, ownPlaceholder, isMulti, isLargeCheck,
@ -66,6 +69,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
question.content.ownPlaceholder = replText; question.content.ownPlaceholder = replText;
}); });
}; };
const {switchOwn} = useAddAnswer();
return ( return (
<Box <Box
@ -143,7 +147,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
> >
Настройки ответов Настройки ответов
</Typography> </Typography>
<CustomCheckbox {/* <CustomCheckbox
dataCy="checkbox-long-text-answer" dataCy="checkbox-long-text-answer"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Многострочный ответ"} label={"Многострочный ответ"}
@ -153,7 +157,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
question.content.largeCheck = target.checked; question.content.largeCheck = target.checked;
}); });
}} }}
/> /> */}
<CustomCheckbox <CustomCheckbox
dataCy="checkbox-multiple-answers" dataCy="checkbox-multiple-answers"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
@ -171,12 +175,10 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
label={'Вариант "свой ответ"'} label={'Вариант "свой ответ"'}
checked={isOwn} checked={isOwn}
handleChange={({ target }) => { handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => { switchOwn({question, checked:target.checked})
question.content.own = target.checked;
});
}} }}
/> />
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}> {/* <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography <Typography
sx={{ sx={{
height: isMobile ? "18px" : "auto", height: isMobile ? "18px" : "auto",
@ -199,7 +201,7 @@ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
value={ownPlaceholder} value={ownPlaceholder}
onChange={({ target }) => setOwnPlaceholder(target.value)} onChange={({ target }) => setOwnPlaceholder(target.value)}
/> />
</Box> </Box> */}
</Box> </Box>
</Box> </Box>
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}> <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>

@ -12,6 +12,7 @@ export default function SwitchAnswerOptionsPict({ switchState = "setting", quest
case "setting": case "setting":
return ( return (
<SettingOptionsPict <SettingOptionsPict
question={question}
questionId={question.id} questionId={question.id}
isRequired={question.content.required} isRequired={question.content.required}
isMulti={question.content.multi} isMulti={question.content.multi}

@ -44,13 +44,16 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
) : ( ) : (
<AnswerDraggableList <AnswerDraggableList
questionId={question.id} questionId={question.id}
variants={question.content.variants.map((variant, index) => ( variants={question.content.variants
.filter(variant => !variant.isOwn ? true : question.content.own && variant.isOwn)
.map((variant, index) => (
<AnswerItem <AnswerItem
key={variant.id} key={variant.id}
index={index} index={index}
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)}
/> />
))} ))}
/> />

@ -4,8 +4,10 @@ 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";
interface Props { interface Props {
question: QuizQuestionVariant;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isLargeCheck: boolean; isLargeCheck: boolean;
@ -14,18 +16,12 @@ interface Props {
ownPlaceholder?: string; ownPlaceholder?: string;
} }
const ResponseSettings = memo<Props>(function ({ questionId, ownPlaceholder, isRequired, isLargeCheck, isMulti, isOwn }) { const ResponseSettings = memo<Props>(function ({question, questionId, ownPlaceholder, isRequired, isLargeCheck, isMulti, isOwn }) {
const theme = useTheme(); const theme = useTheme();
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 setOwnPlaceholder = (replText: string) => { const {switchOwn} = useAddAnswer();
updateQuestion(questionId, (question) => {
if (question.type !== "varimg") return;
question.content.ownPlaceholder = replText;
});
};
return ( return (
<Box <Box
@ -88,35 +84,9 @@ const ResponseSettings = memo<Props>(function ({ questionId, ownPlaceholder, isR
label={'Вариант "свой ответ"'} label={'Вариант "свой ответ"'}
checked={isOwn} checked={isOwn}
handleChange={({ target }) => { handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => { switchOwn({question, checked:target.checked})
question.content.own = target.checked;
});
}} }}
/> />
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography
sx={{
height: isMobile ? "18px" : "auto",
fontWeight: "500",
fontSize: "18px",
color: " #4D4D4D",
mb: "14px",
}}
>
Подсказка "своего ответа"
</Typography>
<CustomTextField
sx={{
maxWidth: "330px",
width: "100%",
mr: isMobile ? "0px" : "16px",
}}
maxLength={60}
placeholder={"мой ответ: три"}
value={ownPlaceholder}
onChange={({ target }) => setOwnPlaceholder(target.value)}
/>
</Box>
</Box> </Box>
<Box <Box
sx={{ sx={{

@ -13,6 +13,7 @@ export default function SwitchAnswerOptions({ switchState = "setting", question
case "setting": case "setting":
return ( return (
<ResponseSettings <ResponseSettings
question={question}
questionId={question.id} questionId={question.id}
isRequired={question.content.required} isRequired={question.content.required}
isLargeCheck={question.content.largeCheck} isLargeCheck={question.content.largeCheck}

@ -219,7 +219,6 @@ export const ModalRequestCreate = ({
time: moment(values.time).format("hh:mm") time: moment(values.time).format("hh:mm")
}) })
}) })
console.log(resp)
if (resp[0]?.status === 200) { if (resp[0]?.status === 200) {
enqueueSnackbar("Запрос успешно отправлен") enqueueSnackbar("Запрос успешно отправлен")
setIsSending(true) setIsSending(true)

@ -4,7 +4,7 @@ import { devlog } from "@frontend/kitui";
import { AnyTypedQuizQuestion, QuestionVariant } from "@frontend/squzanswerer"; import { AnyTypedQuizQuestion, QuestionVariant } from "@frontend/squzanswerer";
import { questionToEditQuestionRequest } from "@model/question/edit"; import { questionToEditQuestionRequest } from "@model/question/edit";
import { QuestionType, RawQuestion, rawQuestionToQuestion } from "@model/question/question"; import { QuestionType, RawQuestion, rawQuestionToQuestion } from "@model/question/question";
import { UntypedQuizQuestion, createQuestionVariant } from "@model/questionTypes/shared"; import { UntypedQuizQuestion, createQuestionOwnVariant, createQuestionVariant } from "@model/questionTypes/shared";
import { produce } from "immer"; import { produce } from "immer";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
@ -29,7 +29,6 @@ export const setQuestions = (questions: RawQuestion[] | null | undefined) =>
export const createUntypedQuestion = (quizId: number, insertAfterQuestionId?: string) => { export const createUntypedQuestion = (quizId: number, insertAfterQuestionId?: string) => {
const { questions } = useQuestionsStore.getState(); const { questions } = useQuestionsStore.getState();
console.log("insertAfterQuestionId ", insertAfterQuestionId)
const questionsAmount = questions.filter(({ type }) => type !== "result").length; const questionsAmount = questions.filter(({ type }) => type !== "result").length;
@ -68,7 +67,6 @@ export const createUntypedQuestion = (quizId: number, insertAfterQuestionId?: st
export const createUntypedQuestionForm = (quizId: number, insertAfterQuestionId?: string) => { export const createUntypedQuestionForm = (quizId: number, insertAfterQuestionId?: string) => {
const { questions } = useQuestionsStore.getState(); const { questions } = useQuestionsStore.getState();
console.log("insertAfterQuestionId ", insertAfterQuestionId)
const questionsAmount = questions.filter(({ type }) => type !== "result").length; const questionsAmount = questions.filter(({ type }) => type !== "result").length;
@ -338,6 +336,20 @@ export const addQuestionVariant = (questionId: string) => {
} }
}); });
}; };
export const addQuestionOwnVariant = (questionId: string) => {
updateQuestion(questionId, (question) => {
switch (question.type) {
case "variant":
case "emoji":
case "images":
case "varimg":
question.content.variants.push(createQuestionOwnVariant());
break;
default:
throw new Error(`Cannot add variant to question of type "${question.type}"`);
}
});
};
export const deleteQuestionVariant = (questionId: string, variantId: string) => { export const deleteQuestionVariant = (questionId: string, variantId: string) => {
updateQuestion(questionId, (question) => { updateQuestion(questionId, (question) => {

@ -1,10 +1,26 @@
import { QuizQuestionsWithVariants } from "@frontend/squzanswerer"; import { QuizQuestionsWithVariants } from "@frontend/squzanswerer";
import { addQuestionVariant } from "@root/questions/actions"; import { addQuestionOwnVariant, addQuestionVariant, updateQuestion } from "@root/questions/actions";
export const useAddAnswer = () => { export const useAddAnswer = () => {
const onClickAddAnAnswer = (question: QuizQuestionsWithVariants) => { const onClickAddAnAnswer = (question: QuizQuestionsWithVariants) => {
addQuestionVariant(question.id); 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)
}
return onClickAddAnAnswer; updateQuestion<QuizQuestionVariant>(question.id, (question) => {
question.content.own = checked;
});
}
return {
onClickAddAnAnswer,
switchOwn
};
}; };

@ -32,11 +32,9 @@ export const useAfterPay = () => {
const [, payCartError] = await cartApi.pay(); const [, payCartError] = await cartApi.pay();
if (payCartError) { if (payCartError) {
console.log("попытка оплаты не удалась")
//Не получилось купить корзину. Ставим флаг, что сайт в состоянии ожидания пополнения счёта для оплаты //Не получилось купить корзину. Ставим флаг, что сайт в состоянии ожидания пополнения счёта для оплаты
startPayCartProcess(paymentUserId) startPayCartProcess(paymentUserId)
} else { } else {
enqueueSnackbar("Товары успешно приобретены")
if (currentCC) navigate("/tariffs") if (currentCC) navigate("/tariffs")
cancelPayCartProcess() cancelPayCartProcess()
} }
@ -52,7 +50,6 @@ export const useAfterPay = () => {
//Время ещё не вышло. У нас стоит флаг покупать корзину если время не вышло. //Время ещё не вышло. У нас стоит флаг покупать корзину если время не вышло.
(async () => { (async () => {
console.log("Время ещё не вышло. У нас стоит флаг покупать корзину если время не вышло.")
const [, payCartError] = await cartApi.pay(); const [, payCartError] = await cartApi.pay();
if (!payCartError) { if (!payCartError) {