Merge branch 'dev' into staging

This commit is contained in:
Nastya 2024-09-12 19:24:46 +03:00
commit 3e10a41504
68 changed files with 515 additions and 328 deletions

1
CHANGELOG.md Normal file

@ -0,0 +1 @@
1.0.0 Добавлены фичи "мультиответ", "перенос строки в своём ответе", "свой ответ", "плейсхолдер своего ответа"

@ -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: "",
}; };
} }

@ -7,10 +7,10 @@ import SupplementIcon from "../../assets/icons/ContactFormIcon/supplementIcon";
interface Props { interface Props {
switchState: string; switchState: string;
SSHC: (data: string) => void; setSwitchState: (data: string) => void;
} }
export default function ButtonSettingForms({ SSHC, switchState }: Props) { export default function ButtonSettingForms({ setSwitchState, switchState }: Props) {
const theme = useTheme(); const theme = useTheme();
const buttonSetting: { icon: JSX.Element; title: string; value: string }[] = [ const buttonSetting: { icon: JSX.Element; title: string; value: string }[] = [
{ {
@ -68,7 +68,7 @@ export default function ButtonSettingForms({ SSHC, switchState }: Props) {
<MiniButtonSetting <MiniButtonSetting
key={i} key={i}
onClick={() => { onClick={() => {
SSHC(e.value); setSwitchState(e.value);
}} }}
sx={{ sx={{
backgroundColor: backgroundColor:

@ -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;

@ -59,7 +59,7 @@ export const Tariffs = () => {
type: "duration", type: "duration",
description: "30 дней безлимитного пользования сервисом", description: "30 дней безлимитного пользования сервисом",
actualPrice: "969", actualPrice: "969",
oldPrice: "1024", oldPrice: "1020",
discount: "5", discount: "5",
}, },
{ {
@ -99,7 +99,7 @@ export const Tariffs = () => {
type: "requests", type: "requests",
description: "Полное прохождение 1000 опросов респондентом", description: "Полное прохождение 1000 опросов респондентом",
actualPrice: "12 740", actualPrice: "12 740",
oldPrice: "2 000", oldPrice: "20 000",
discount: "36", discount: "36",
}, },
{ {

@ -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,13 +26,22 @@ type AnswerItemProps = {
disableKeyDown?: boolean; disableKeyDown?: boolean;
additionalContent?: ReactNode; additionalContent?: ReactNode;
additionalMobile?: ReactNode; additionalMobile?: ReactNode;
isOwn: boolean;
ownPlaceholder: string;
}; };
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, ownPlaceholder }) => {
const theme = useTheme(); const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(790)); const isTablet = useMediaQuery(theme.breakpoints.down(790));
const setOwnPlaceholder = (replText: string) => {
updateQuestion(questionId, (question) => {
question.content.ownPlaceholder = replText;
console.log(question)
});
};
return ( return (
<Draggable <Draggable
draggableId={String(index)} draggableId={String(index)}
@ -55,19 +64,22 @@ const AnswerItem = memo<AnswerItemProps>(
}} }}
> >
<TextField <TextField
value={variant.answer} value={ isOwn ? ownPlaceholder : 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) {
isOwn ?
setOwnPlaceholder(target.value || " ")
:
setQuestionVariantField(questionId, variant.id, "answer", target.value || " "); setQuestionVariantField(questionId, variant.id, "answer", target.value || " ");
} }
}} }}
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 +100,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 +122,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,8 @@ type Props = Omit<
originalImageUrl?: string | null | undefined, originalImageUrl?: string | null | undefined,
) => Promise<void>; ) => Promise<void>;
openImageUploadModal: () => void; openImageUploadModal: () => void;
isOwn: boolean;
ownPlaceholder: string;
}; };
export default function ImageEditAnswerItem({ export default function ImageEditAnswerItem({
@ -27,6 +29,8 @@ export default function ImageEditAnswerItem({
pictureUploding, pictureUploding,
openCropModal, openCropModal,
openImageUploadModal, openImageUploadModal,
isOwn,
ownPlaceholder,
}: Props) { }: Props) {
const addOrEditImageButton = useMemo(() => { const addOrEditImageButton = useMemo(() => {
return ( return (
@ -105,6 +109,8 @@ export default function ImageEditAnswerItem({
variant={variant} variant={variant}
additionalContent={addOrEditImageButton} additionalContent={addOrEditImageButton}
additionalMobile={addOrEditImageButtonMobile} additionalMobile={addOrEditImageButtonMobile}
isOwn={isOwn}
ownPlaceholder={ownPlaceholder}
/> />
); );
} }

@ -38,7 +38,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 6px; border-radius: 6px;
background-image: url("../../../../assets/icons/ArrowGear.svg"); background-image: url("../../../../../assets/icons/ArrowGear.svg");
font-size: 0px; font-size: 0px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;

@ -11,7 +11,7 @@ import {
useMediaQuery, useMediaQuery,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { createBranchingRuleMain } from "../../../model/questionTypes/shared"; import { createBranchingRuleMain } from "../../../../model/questionTypes/shared";
import InfoIcon from "@icons/Info"; import InfoIcon from "@icons/Info";
import { TypeSwitch } from "./Settings"; import { TypeSwitch } from "./Settings";

@ -1,7 +1,7 @@
import { Box, Skeleton, useMediaQuery, useTheme } from "@mui/material"; import { Box, Skeleton, useMediaQuery, useTheme } from "@mui/material";
import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions"; import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions";
import { lazy, Suspense, useCallback } from "react"; import { lazy, Suspense, useCallback } from "react";
import { DraggableList } from "./DraggableList"; import { DraggableList } from "../DraggableList";
import { SwitchBranchingPanel } from "./SwitchBranchingPanel"; import { SwitchBranchingPanel } from "./SwitchBranchingPanel";
const BranchingMap = lazy(() => const BranchingMap = lazy(() =>

@ -3,7 +3,7 @@ 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 { useAddAnswer } from "../../../utils/hooks/useAddAnswer";
import { AnswerDraggableList } from "../AnswerDraggableList"; import { AnswerDraggableList } from "../AnswerDraggableList";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
import SwitchDropDown from "./switchDropDown"; import SwitchDropDown from "./switchDropDown";
import type { QuizQuestionSelect } from "@frontend/squzanswerer"; import type { QuizQuestionSelect } from "@frontend/squzanswerer";
@ -100,7 +100,7 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -6,7 +6,7 @@ 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 { useAddAnswer } from "../../../utils/hooks/useAddAnswer";
import { AnswerDraggableList } from "../AnswerDraggableList"; import { AnswerDraggableList } from "../AnswerDraggableList";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
import EmojiAnswerItem from "./EmojiAnswerItem/EmojiAnswerItem"; import EmojiAnswerItem from "./EmojiAnswerItem/EmojiAnswerItem";
import SwitchEmoji from "./switchEmoji"; import SwitchEmoji from "./switchEmoji";
@ -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,12 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
setAnchorElement={setAnchorElement} setAnchorElement={setAnchorElement}
setOpen={setOpen} setOpen={setOpen}
setSelectedVariant={setSelectedVariant} setSelectedVariant={setSelectedVariant}
isOwn={Boolean(variant?.isOwn)}
ownPlaceholder={question.content.ownPlaceholder}
/> />
))} ))}
/> />
<Popover <Popover
open={open} open={open}
anchorEl={anchorElement} anchorEl={anchorElement}
@ -115,7 +121,7 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -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,8 @@ 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;
ownPlaceholder: string;
}; };
export default function EmojiAnswerItem({ export default function EmojiAnswerItem({
@ -23,7 +26,11 @@ export default function EmojiAnswerItem({
setAnchorElement, setAnchorElement,
setSelectedVariant, setSelectedVariant,
setOpen, setOpen,
isOwn,
ownPlaceholder,
}: Props) { }: Props) {
const addOrEditImageButton = useMemo(() => { const addOrEditImageButton = useMemo(() => {
return ( return (
!isTablet && ( !isTablet && (
@ -77,6 +84,8 @@ export default function EmojiAnswerItem({
variant={variant} variant={variant}
additionalContent={addOrEditImageButton} additionalContent={addOrEditImageButton}
additionalMobile={addOrEditImageButtonMobile} additionalMobile={addOrEditImageButtonMobile}
isOwn={isOwn}
ownPlaceholder={ownPlaceholder}
/> />
); );
} }

@ -1,23 +1,37 @@
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 { useAddAnswer } from "@/utils/hooks/useAddAnswer";
type SettingEmojiProps = { type SettingEmojiProps = {
question: QuizQuestionEmoji;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isMulti: boolean; isMulti: boolean;
isOwn: boolean; isOwn: boolean;
isLargeCheck?: boolean;
}; };
const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, isRequired, 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));
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const setOwnPlaceholder = (replText: string) => {
updateQuestion(questionId, (question) => {
if (question.type !== "varimg") return;
question.content.ownPlaceholder = replText;
});
};
return ( return (
<Box <Box
sx={{ sx={{
@ -29,7 +43,7 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, isRequired,
pt: isTablet ? "5px" : "0px", pt: isTablet ? "5px" : "0px",
}} }}
> >
{/* <Box <Box
sx={{ sx={{
boxSizing: "border-box", boxSizing: "border-box",
pt: "20px", pt: "20px",
@ -50,6 +64,17 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, isRequired,
> >
Настройки ответов Настройки ответов
</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 <CustomCheckbox
dataCy="checkbox-multiple-answers" dataCy="checkbox-multiple-answers"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
@ -67,12 +92,34 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, isRequired,
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> */} {/* <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
sx={{ sx={{
pt: "20px", pt: "20px",

@ -12,10 +12,13 @@ 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}
isMulti={question.content.multi} isMulti={question.content.multi}
isLargeCheck={question.content.isLargeCheck}
ownPlaceholder={question.content.ownPlaceholder}
/> />
); );
case "help": case "help":

@ -5,7 +5,7 @@ import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
import type { QuizQuestionText } from "@frontend/squzanswerer"; import type { QuizQuestionText } from "@frontend/squzanswerer";
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict"; import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
import SwitchTextField from "./switchTextField"; import SwitchTextField from "./switchTextField";
interface Props { interface Props {
@ -90,9 +90,9 @@ export default function OwnTextField({ question, openBranchingPage, setOpenBranc
)} )}
</Box> </Box>
</Box> </Box>
<ButtonsOptionsAndPict <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionHasParent={question.content.rule.parentId?.length !== 0} questionHasParent={question.content.rule.parentId?.length !== 0}

@ -1,3 +1,4 @@
import { QuestionType } from "@model/question/question"; import { QuestionType } from "@model/question/question";
import { import {
Box, Box,
@ -20,25 +21,28 @@ import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal"; import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
import { DeleteFunction } from "@utils/deleteFunc"; import { DeleteFunction } from "@utils/deleteFunc";
import { memo, useState } from "react"; import { memo, useState } from "react";
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon"; import { CopyIcon } from "@/assets/icons/questionsPage/CopyIcon";
import Branching from "../../assets/icons/questionsPage/branching"; import Branching from "@/assets/icons/questionsPage/branching";
import { DeleteIcon } from "../../assets/icons/questionsPage/deleteIcon"; import { DeleteIcon } from "@/assets/icons/questionsPage/deleteIcon";
import ImgIcon from "../../assets/icons/questionsPage/imgIcon"; import ImgIcon from "@/assets/icons/questionsPage/imgIcon";
import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import SettingIcon from "@/assets/icons/questionsPage/settingIcon";
import { DeleteBranchingQuestionModal } from "./DeleteBranchingQuestionModal";
interface Props { interface Props {
switchState: string; switchState: string;
SSHC: (data: string) => void; setSwitchState: (data: string) => void;
openBranchingPage: boolean; openBranchingPage: boolean;
setOpenBranchingPage: (a: boolean) => void; setOpenBranchingPage: (a: boolean) => void;
questionId: string; questionId: string;
questionType: QuestionType; questionType: QuestionType;
questionContentId: string; questionContentId: string;
questionHasParent: boolean; questionHasParent: boolean;
} };
const ButtonsOptionsAndPict = memo<Props>(function ({ const IgnoreImage = ["images", "emoji", "number", "date", "select", "text", "file", "rating"]
SSHC,
const ButtonsOptions = memo<Props>(function ({
setSwitchState,
switchState, switchState,
openBranchingPage, openBranchingPage,
setOpenBranchingPage, setOpenBranchingPage,
@ -47,17 +51,17 @@ const ButtonsOptionsAndPict = memo<Props>(function ({
questionContentId, questionContentId,
questionHasParent, questionHasParent,
}) { }) {
const [buttonHover, setButtonHover] = useState<string>("");
const [openedReallyChangingModal, setOpenedReallyChangingModal] =
useState<boolean>(false);
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const isQuestionFirst = useQuestionsStore((state) => state.questions[0]?.id === questionId,);
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isIgnoreImage = !IgnoreImage.includes(questionType)
const [buttonHover, setButtonHover] = useState<string>("");
const [openedReallyChangingModal, setOpenedReallyChangingModal] = useState<boolean>(false);
const [openDelete, setOpenDelete] = useState<boolean>(false); const [openDelete, setOpenDelete] = useState<boolean>(false);
const isQuestionFirst = useQuestionsStore(
(state) => state.questions[0]?.id === questionId,
);
if (!quiz) return null; if (!quiz) return null;
@ -85,7 +89,7 @@ const ButtonsOptionsAndPict = memo<Props>(function ({
onMouseEnter={() => setButtonHover("setting")} onMouseEnter={() => setButtonHover("setting")}
onMouseLeave={() => setButtonHover("")} onMouseLeave={() => setButtonHover("")}
onClick={() => { onClick={() => {
SSHC("setting"); switchState === "setting" ? setSwitchState("") : setSwitchState("setting");
}} }}
sx={{ sx={{
maxWidth: "104px", maxWidth: "104px",
@ -153,38 +157,40 @@ const ButtonsOptionsAndPict = memo<Props>(function ({
{isIconMobile ? null : "Ветвление"} {isIconMobile ? null : "Ветвление"}
</MiniButtonSetting> </MiniButtonSetting>
)} )}
<MiniButtonSetting {isIgnoreImage &&
onMouseEnter={() => setButtonHover("image")} <MiniButtonSetting
onMouseLeave={() => setButtonHover("")} onMouseEnter={() => setButtonHover("image")}
onClick={() => { onMouseLeave={() => setButtonHover("")}
SSHC("image"); onClick={() => {
}} switchState === "image" ? setSwitchState("") : setSwitchState("image");
sx={{ }}
height: "30px", sx={{
maxWidth: "123px", height: "30px",
minWidth: isIconMobile ? "30px" : "64px", maxWidth: "123px",
backgroundColor: minWidth: isIconMobile ? "30px" : "64px",
switchState === "image" backgroundColor:
? theme.palette.brightPurple.main switchState === "image"
: "transparent", ? theme.palette.brightPurple.main
color: : "transparent",
switchState === "image" ? "#ffffff" : theme.palette.grey3.main, color:
"&:hover": { switchState === "image" ? "#ffffff" : theme.palette.grey3.main,
color: switchState === "image" ? theme.palette.grey3.main : null, "&:hover": {
}, color: switchState === "image" ? theme.palette.grey3.main : null,
}} },
> }}
<ImgIcon >
color={ <ImgIcon
buttonHover === "image" color={
? theme.palette.grey3.main buttonHover === "image"
: switchState === "image" ? theme.palette.grey3.main
? "#ffffff" : switchState === "image"
: theme.palette.grey3.main ? "#ffffff"
} : theme.palette.grey3.main
/> }
{isIconMobile ? null : "Изображение"} />
</MiniButtonSetting> {isIconMobile ? null : "Изображение"}
</MiniButtonSetting>
}
</Box> </Box>
<Box <Box
sx={{ sx={{
@ -217,52 +223,12 @@ const ButtonsOptionsAndPict = memo<Props>(function ({
<DeleteIcon style={{ color: "#4D4D4D" }} /> <DeleteIcon style={{ color: "#4D4D4D" }} />
</IconButton> </IconButton>
)} )}
<Modal open={openDelete} onClose={() => setOpenDelete(false)}>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
padding: "30px",
borderRadius: "10px",
background: "#FFFFFF",
}}
>
<Typography variant="h6" sx={{ textAlign: "center" }}>
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки
потеряют данные ветвления. Вы уверены, что хотите удалить вопрос?
</Typography>
<Box
sx={{
marginTop: "30px",
display: "flex",
justifyContent: "center",
gap: "15px",
}}
>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={() => setOpenDelete(false)}
>
Отмена
</Button>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={() => {
deleteQuestionWithTimeout(questionId, () =>
DeleteFunction(questionId),
);
}}
>
Подтвердить
</Button>
</Box>
</Box>
</Modal>
</Box> </Box>
<DeleteBranchingQuestionModal
open={openDelete}
onclose={() => setOpenDelete(false)}
questionId={questionId}
/>
<ReallyChangingModal <ReallyChangingModal
opened={openedReallyChangingModal} opened={openedReallyChangingModal}
onClose={() => setOpenedReallyChangingModal(false)} onClose={() => setOpenedReallyChangingModal(false)}
@ -271,6 +237,4 @@ const ButtonsOptionsAndPict = memo<Props>(function ({
); );
}); });
ButtonsOptionsAndPict.displayName = "ButtonsOptionsAndPict"; export default ButtonsOptions;
export default ButtonsOptionsAndPict;

@ -0,0 +1,66 @@
import { deleteQuestionWithTimeout } from "@/stores/questions/actions";
import { DeleteFunction } from "@/utils/deleteFunc";
import { Box, Button, Modal, Typography } from "@mui/material";
interface Props {
open: boolean;
onclose: () => void;
questionId: string;
}
export const DeleteBranchingQuestionModal = ({
open,
onclose,
questionId,
}: Props) => {
return (
<Modal
open={open}
onClose={onclose}
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
padding: "30px",
borderRadius: "10px",
background: "#FFFFFF",
}}
>
<Typography
variant="h6"
sx={{ textAlign: "center" }}
>
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что хотите удалить вопрос?
</Typography>
<Box
sx={{
marginTop: "30px",
display: "flex",
justifyContent: "center",
gap: "15px",
}}
>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={onclose}
>
Отмена
</Button>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={() => {
deleteQuestionWithTimeout(questionId, () => DeleteFunction(questionId));
}}
>
Подтвердить
</Button>
</Box>
</Box>
</Modal>
)
}

@ -8,15 +8,16 @@ import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
import MiniButtonSetting from "@ui_kit/MiniButtonSetting"; import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import { DeleteFunction } from "@utils/deleteFunc"; import { DeleteFunction } from "@utils/deleteFunc";
import { memo, useState } from "react"; import { memo, useState } from "react";
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon"; import { CopyIcon } from "../../../../assets/icons/questionsPage/CopyIcon";
import Branching from "../../assets/icons/questionsPage/branching"; import Branching from "../../../../assets/icons/questionsPage/branching";
import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import SettingIcon from "../../../../assets/icons/questionsPage/settingIcon";
import { QuestionType } from "@model/question/question"; import { QuestionType } from "@model/question/question";
import type { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import type { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
import { DeleteBranchingQuestionModal } from "./DeleteBranchingQuestionModal";
interface Props { interface Props {
switchState: string; switchState: string;
SSHC: (data: string) => void; setSwitchState: (data: string) => void;
questionId: string; questionId: string;
questionContentId: string; questionContentId: string;
questionType: QuestionType; questionType: QuestionType;
@ -25,8 +26,8 @@ interface Props {
sx?: SxProps; sx?: SxProps;
} }
const ButtonsOptions = memo<Props>(function ({ const lalalalala = memo<Props>(function ({
SSHC, setSwitchState,
switchState, switchState,
questionId, questionId,
questionContentId, questionContentId,
@ -54,21 +55,21 @@ const ButtonsOptions = memo<Props>(function ({
value: string; value: string;
myFunc?: any; myFunc?: any;
}[] = [ }[] = [
{ {
icon: <SettingIcon color={switchState === "setting" ? "#ffffff" : theme.palette.grey3.main} />, icon: <SettingIcon color={switchState === "setting" ? "#ffffff" : theme.palette.grey3.main} />,
title: "Настройки", title: "Настройки",
value: "setting", value: "setting",
},
{
icon: <Branching color={switchState === "branching" ? "#ffffff" : theme.palette.grey3.main} />,
title: "Ветвление",
value: "branching",
myFunc: (question: AnyTypedQuizQuestion) => {
setOpenBranchingPage(true);
updateDesireToOpenABranchingModal(question.content.id);
}, },
}, {
]; icon: <Branching color={switchState === "branching" ? "#ffffff" : theme.palette.grey3.main} />,
title: "Ветвление",
value: "branching",
myFunc: (question: AnyTypedQuizQuestion) => {
setOpenBranchingPage(true);
updateDesireToOpenABranchingModal(question.content.id);
},
},
];
return ( return (
<Box <Box
@ -81,6 +82,7 @@ const ButtonsOptions = memo<Props>(function ({
height: isMobile ? "92px" : "70px", height: isMobile ? "92px" : "70px",
}} }}
> >
ButtonsOptions
<Box <Box
sx={{ sx={{
padding: isMobile ? " 3px 12px 11px" : "20px", padding: isMobile ? " 3px 12px 11px" : "20px",
@ -118,7 +120,7 @@ const ButtonsOptions = memo<Props>(function ({
<MiniButtonSetting <MiniButtonSetting
key={title} key={title}
onClick={() => { onClick={() => {
SSHC(value); setSwitchState(value);
myFunc(); myFunc();
}} }}
sx={{ sx={{
@ -170,55 +172,11 @@ const ButtonsOptions = memo<Props>(function ({
<DeleteIcon color={"#4D4D4D"} /> <DeleteIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
)} )}
<Modal <DeleteBranchingQuestionModal
open={openDelete} open={openDelete}
onClose={() => setOpenDelete(false)} onclose={() => setOpenDelete(false)}
> questionId={questionId}
<Box />
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
padding: "30px",
borderRadius: "10px",
background: "#FFFFFF",
}}
>
<Typography
variant="h6"
sx={{ textAlign: "center" }}
>
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что
хотите удалить вопрос?
</Typography>
<Box
sx={{
marginTop: "30px",
display: "flex",
justifyContent: "center",
gap: "15px",
}}
>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={() => setOpenDelete(false)}
>
Отмена
</Button>
<Button
variant="contained"
sx={{ minWidth: "150px" }}
onClick={() => {
deleteQuestionWithTimeout(questionId, () => DeleteFunction(questionId));
}}
>
Подтвердить
</Button>
</Box>
</Box>
</Modal>
</Box> </Box>
</Box> </Box>
); );

@ -1,8 +1,8 @@
import { Box, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material"; import { Box, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
import { useState } from "react"; import { useState } from "react";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "@/assets/icons/InfoIcon";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import SwitchData from "./switchData"; import SwitchDate from "./switchDate";
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo"; import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
import { QuizQuestionDate } from "@frontend/squzanswerer"; import { QuizQuestionDate } from "@frontend/squzanswerer";
@ -12,7 +12,7 @@ interface Props {
setOpenBranchingPage: (a: boolean) => void; setOpenBranchingPage: (a: boolean) => void;
} }
export default function DataOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) { export default function DateOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) {
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));
@ -64,14 +64,14 @@ export default function DataOptions({ question, openBranchingPage, setOpenBranch
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}
questionHasParent={question.content.rule.parentId?.length !== 0} questionHasParent={question.content.rule.parentId?.length !== 0}
setOpenBranchingPage={setOpenBranchingPage} setOpenBranchingPage={setOpenBranchingPage}
/> />
<SwitchData <SwitchDate
switchState={switchState} switchState={switchState}
question={question} question={question}
/> />

@ -1,6 +1,6 @@
import { QuizQuestionDate } from "@frontend/squzanswerer"; import { QuizQuestionDate } from "@frontend/squzanswerer";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import SettingData from "./settingData"; import SettingDate from "./settingDate";
interface Props { interface Props {
switchState: string; switchState: string;
@ -11,7 +11,7 @@ export default function SwitchData({ switchState = "setting", question }: Props)
switch (switchState) { switch (switchState) {
case "setting": case "setting":
return ( return (
<SettingData <SettingDate
questionId={question.id} questionId={question.id}
isRequired={question.content.required} isRequired={question.content.required}
isDateRange={question.content.dateRange} isDateRange={question.content.dateRange}

@ -3,13 +3,13 @@ import { addQuestionVariant, clearQuestionImages, uploadQuestionImage } from "@r
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal";
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 { QuizQuestionVarImg } from "@frontend/squzanswerer"; import type { QuizQuestionVarImg } from "@frontend/squzanswerer";
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";
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import { UploadImageModal } from "../UploadImage/UploadImageModal"; import { UploadImageModal } from "../../UploadImage/UploadImageModal";
import SwitchOptionsAndPict from "./switchOptionsAndPict"; import SwitchOptionsAndPict from "./switchOptionsAndPict";
interface Props { interface Props {
@ -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,8 @@ export default function OptionsAndPicture({ question, setOpenBranchingPage }: Pr
openImageUploadModal={openImageUploadModal} openImageUploadModal={openImageUploadModal}
pictureUploding={pictureUploding} pictureUploding={pictureUploding}
setSelectedVariantId={setSelectedVariantId} setSelectedVariantId={setSelectedVariantId}
isOwn={Boolean(variant?.isOwn)}
ownPlaceholder={question.content.ownPlaceholder}
/> />
))} ))}
/> />
@ -152,9 +156,9 @@ export default function OptionsAndPicture({ question, setOpenBranchingPage }: Pr
)} )}
</Box> </Box>
</Box> </Box>
<ButtonsOptionsAndPict <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionHasParent={question.content.rule.parentId?.length !== 0} questionHasParent={question.content.rule.parentId?.length !== 0}

@ -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";
@ -9,15 +10,22 @@ type SettingOptionsAndPictProps = {
questionId: string; questionId: string;
replText: string; replText: string;
isRequired: boolean; isRequired: boolean;
isLargeCheck: boolean;
isOwn: boolean; isOwn: boolean;
ownPlaceholder?: boolean;
isMulti?: boolean;
question: QuizQuestionVarImg;
}; };
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ questionId, 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) => {
@ -49,7 +57,7 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ quest
width: "100%", width: "100%",
}} }}
> >
{/* <Typography <Typography
sx={{ sx={{
height: isMobile ? "18px" : "auto", height: isMobile ? "18px" : "auto",
fontWeight: "500", fontWeight: "500",
@ -58,18 +66,16 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ quest
}} }}
> >
Настройки ответов Настройки ответов
</Typography> */} </Typography>
{/* <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; }}
}); />
}}
/> */}
{!isWrappColumn && ( {!isWrappColumn && (
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}> <Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
<Typography <Typography

@ -1,6 +1,6 @@
import { QuizQuestionVarImg } from "@frontend/squzanswerer"; import { QuizQuestionVarImg } from "@frontend/squzanswerer";
import UploadImage from "../UploadImage"; import UploadImage from "../../UploadImage";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import SettingOptionsAndPict from "./SettingOptionsAndPict"; import SettingOptionsAndPict from "./SettingOptionsAndPict";
interface Props { interface Props {
@ -13,10 +13,13 @@ export default function SwitchOptionsAndPict({ switchState = "setting", question
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}
isOwn={question.content.own} isOwn={question.content.own}
isLargeCheck={question.content.largeCheck}
isMulti={question.content.multi}
/> />
); );
case "help": case "help":

@ -3,14 +3,14 @@ import { clearQuestionImages, uploadQuestionImage } from "@root/questions/action
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal";
import { useState } from "react"; import { useState } from "react";
import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; import { EnterIcon } from "@/assets/icons/questionsPage/enterIcon";
import type { QuizQuestionImages } from "@frontend/squzanswerer"; import type { QuizQuestionImages } from "@frontend/squzanswerer";
import { useAddAnswer } from "../../../utils/hooks/useAddAnswer"; import { useAddAnswer } from "@/utils/hooks/useAddAnswer";
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";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import { UploadImageModal } from "../UploadImage/UploadImageModal"; import { UploadImageModal } from "../../UploadImage/UploadImageModal";
import SwitchAnswerOptionsPict from "./switchOptionsPict"; import SwitchAnswerOptionsPict from "./switchOptionsPict";
interface Props { interface Props {
@ -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,8 @@ export default function OptionsPicture({ question, openBranchingPage, setOpenBra
openImageUploadModal={openImageUploadModal} openImageUploadModal={openImageUploadModal}
pictureUploding={pictureUploding} pictureUploding={pictureUploding}
setSelectedVariantId={setSelectedVariantId} setSelectedVariantId={setSelectedVariantId}
isOwn={Boolean(variant?.isOwn)}
ownPlaceholder={question.content.ownPlaceholder}
/> />
))} ))}
/> />
@ -137,7 +140,7 @@ export default function OptionsPicture({ question, openBranchingPage, setOpenBra
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -3,11 +3,13 @@ import { Box, Button, 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 FormatIcon1 from "../../../assets/icons/questionsPage/FormatIcon1"; import FormatIcon1 from "@/assets/icons/questionsPage/FormatIcon1";
import FormatIcon2 from "../../../assets/icons/questionsPage/FormatIcon2"; import FormatIcon2 from "@/assets/icons/questionsPage/FormatIcon2";
import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11"; 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 { useAddAnswer } from "@/utils/hooks/useAddAnswer";
type Proportion = "1:1" | "1:2" | "2:1"; type Proportion = "1:1" | "1:2" | "2:1";
@ -34,19 +36,23 @@ const FORMATS: FormatItem[] = [
{ value: "masonry", icon: FormatIcon1 }, { value: "masonry", icon: FormatIcon1 },
]; ];
type SettingOpytionsPictProps = { type SettingOptionsPictProps = {
question: QuizQuestionVariant;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isMulti: boolean; isMulti: boolean;
isOwn: boolean; isOwn: boolean;
proportions: Proportion; proportions: Proportion;
format: Format; format: Format;
ownPlaceholder?: boolean;
isLargeCheck?: boolean;
}; };
const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({ const SettingOptionsPict = memo<SettingOptionsPictProps>(function ({
question,
questionId, questionId,
isRequired, isRequired,
isMulti, ownPlaceholder, isMulti, isLargeCheck,
isOwn, isOwn,
proportions, proportions,
format, format,
@ -55,6 +61,15 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
const isTablet = useMediaQuery(theme.breakpoints.down(985)); const isTablet = useMediaQuery(theme.breakpoints.down(985));
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990)); const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
const setOwnPlaceholder = (replText: string) => {
updateQuestion(questionId, (question) => {
if (question.type !== "varimg") return;
question.content.ownPlaceholder = replText;
});
};
const {switchOwn} = useAddAnswer();
return ( return (
<Box <Box
@ -68,8 +83,8 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
pt: isTablet ? "5px" : "0px", pt: isTablet ? "5px" : "0px",
}} }}
> >
{/* <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}> <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
<Box {/* <Box
sx={{ sx={{
boxSizing: "border-box", boxSizing: "border-box",
pt: "20px", pt: "20px",
@ -110,7 +125,7 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
/> />
))} ))}
</Box> </Box>
</Box> </Box> */}
<Box <Box
sx={{ sx={{
boxSizing: "border-box", boxSizing: "border-box",
@ -132,6 +147,17 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
> >
Настройки ответов Настройки ответов
</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 <CustomCheckbox
dataCy="checkbox-multiple-answers" dataCy="checkbox-multiple-answers"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
@ -149,13 +175,35 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(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%" }}>
<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>
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}> <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
{/* <Box {/* <Box
sx={{ sx={{

@ -1,6 +1,6 @@
import { QuizQuestionImages } from "@frontend/squzanswerer"; import { QuizQuestionImages } from "@frontend/squzanswerer";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import SettingOpytionsPict from "./settingOpytionsPict"; import SettingOptionsPict from "./settingOptionsPict";
interface Props { interface Props {
switchState: string; switchState: string;
@ -11,13 +11,17 @@ export default function SwitchAnswerOptionsPict({ switchState = "setting", quest
switch (switchState) { switch (switchState) {
case "setting": case "setting":
return ( return (
<SettingOpytionsPict <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}
isOwn={question.content.own} isOwn={question.content.own}
proportions={question.content.xy} proportions={question.content.xy}
format={question.content.format} format={question.content.format}
ownPlaceholder={question.content.ownPlaceholder}
isLargeCheck={question.content.isLargeCheck}
/> />
); );
case "help": case "help":

@ -1,15 +1,15 @@
import { Box, TextField as MuiTextField, TextFieldProps, Typography, useMediaQuery, useTheme } from "@mui/material"; import { Box, TextField as MuiTextField, TextFieldProps, Typography, useMediaQuery, useTheme } from "@mui/material";
import { updateQuestion } from "@root/questions/actions"; import { updateQuestion } from "@root/questions/actions";
import { FC, useLayoutEffect, useRef, useState } from "react"; import { FC, useLayoutEffect, useRef, useState } from "react";
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon"; import FlagIcon from "@/assets/icons/questionsPage/FlagIcon";
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini"; import StarIconMini from "@/assets/icons/questionsPage/StarIconMini";
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon"; import HashtagIcon from "@/assets/icons/questionsPage/hashtagIcon";
import HeartIcon from "../../../assets/icons/questionsPage/heartIcon"; import HeartIcon from "@/assets/icons/questionsPage/heartIcon";
import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon"; import LightbulbIcon from "@/assets/icons/questionsPage/lightbulbIcon";
import LikeIcon from "../../../assets/icons/questionsPage/likeIcon"; import LikeIcon from "@/assets/icons/questionsPage/likeIcon";
import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon"; import TropfyIcon from "@/assets/icons/questionsPage/tropfyIcon";
import type { QuizQuestionRating } from "@frontend/squzanswerer"; import type { QuizQuestionRating } from "@frontend/squzanswerer";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import SwitchRating from "./switchRating"; import SwitchRating from "./switchRating";
const TextField = MuiTextField as unknown as FC<TextFieldProps>; const TextField = MuiTextField as unknown as FC<TextFieldProps>;
@ -289,7 +289,7 @@ export default function RatingOptions({ question, openBranchingPage, setOpenBran
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -2,13 +2,13 @@ import { QuizQuestionRating } from "@frontend/squzanswerer";
import { Box, ButtonBase, Slider, Typography, useMediaQuery, useTheme } from "@mui/material"; import { Box, ButtonBase, Slider, 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 FlagIcon from "../../../assets/icons/questionsPage/FlagIcon"; import FlagIcon from "@/assets/icons/questionsPage/FlagIcon";
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini"; import StarIconMini from "@/assets/icons/questionsPage/StarIconMini";
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon"; import HashtagIcon from "@/assets/icons/questionsPage/hashtagIcon";
import HeartIcon from "../../../assets/icons/questionsPage/heartIcon"; import HeartIcon from "@/assets/icons/questionsPage/heartIcon";
import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon"; import LightbulbIcon from "@/assets/icons/questionsPage/lightbulbIcon";
import LikeIcon from "../../../assets/icons/questionsPage/likeIcon"; import LikeIcon from "@/assets/icons/questionsPage/likeIcon";
import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon"; import TropfyIcon from "@/assets/icons/questionsPage/tropfyIcon";
import type { ButtonRatingFrom } from "./RatingOptions"; import type { ButtonRatingFrom } from "./RatingOptions";
type SettingSliderProps = { type SettingSliderProps = {

@ -1,5 +1,5 @@
import { QuizQuestionRating } from "@frontend/squzanswerer"; import { QuizQuestionRating } from "@frontend/squzanswerer";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import SettingRating from "./settingRating"; import SettingRating from "./settingRating";
interface Props { interface Props {

@ -4,7 +4,7 @@ import { useDebouncedCallback } from "use-debounce";
import CustomNumberField from "@ui_kit/CustomNumberField"; import CustomNumberField from "@ui_kit/CustomNumberField";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import SwitchSlider from "./switchSlider"; import SwitchSlider from "./switchSlider";
import { updateQuestion } from "@root/questions/actions"; import { updateQuestion } from "@root/questions/actions";
@ -209,7 +209,7 @@ export default function SliderOptions({ question, openBranchingPage, setOpenBran
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -1,5 +1,5 @@
import { QuizQuestionNumber } from "@frontend/squzanswerer"; import { QuizQuestionNumber } from "@frontend/squzanswerer";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import SettingSlider from "./settingSlider"; import SettingSlider from "./settingSlider";
interface Props { interface Props {

@ -1,11 +1,11 @@
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material"; 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 { useAddAnswer } from "@/utils/hooks/useAddAnswer";
import { AnswerDraggableList } from "../AnswerDraggableList"; import { AnswerDraggableList } from "../../AnswerDraggableList";
import AnswerItem from "../AnswerDraggableList/AnswerItem"; import AnswerItem from "../../AnswerDraggableList/AnswerItem";
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict"; import ButtonsOptions from "../ButtonsLayout/ButtonsOptions";
import SwitchAnswerOptions from "./switchAnswerOptions"; import SwitchAnswerOptions from "./switchAnswerOptions";
interface Props { interface Props {
@ -44,13 +44,17 @@ 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)}
ownPlaceholder={question.content.ownPlaceholder}
/> />
))} ))}
/> />
@ -100,9 +104,9 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
)} )}
</Box> </Box>
</Box> </Box>
<ButtonsOptionsAndPict <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionHasParent={question.content.rule.parentId?.length !== 0} questionHasParent={question.content.rule.parentId?.length !== 0}

@ -3,20 +3,25 @@ import { updateQuestion } from "@root/questions/actions";
import CustomCheckbox from "@ui_kit/CustomCheckbox"; 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 { useAddAnswer } from "@/utils/hooks/useAddAnswer";
interface Props { interface Props {
question: QuizQuestionVariant;
questionId: string; questionId: string;
isRequired: boolean; isRequired: boolean;
isLargeCheck: boolean; isLargeCheck: boolean;
isMulti: boolean; isMulti: boolean;
isOwn: boolean; isOwn: boolean;
ownPlaceholder?: string;
} }
const ResponseSettings = memo<Props>(function ({ questionId, 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 {switchOwn} = useAddAnswer();
return ( return (
<Box <Box
@ -30,7 +35,7 @@ const ResponseSettings = memo<Props>(function ({ questionId, isRequired, isLarge
pt: isTablet ? "5px" : "0px", pt: isTablet ? "5px" : "0px",
}} }}
> >
{/* <Box <Box
sx={{ sx={{
boxSizing: "border-box", boxSizing: "border-box",
pt: "20px", pt: "20px",
@ -54,7 +59,7 @@ const ResponseSettings = memo<Props>(function ({ questionId, isRequired, isLarge
<CustomCheckbox <CustomCheckbox
dataCy="checkbox-long-text-answer" dataCy="checkbox-long-text-answer"
sx={{ mr: isMobile ? "0px" : "16px" }} sx={{ mr: isMobile ? "0px" : "16px" }}
label={"Длинный текстовый ответ"} label={"Многострочный ответ"}
checked={isLargeCheck} checked={isLargeCheck}
handleChange={({ target }) => { handleChange={({ target }) => {
updateQuestion<QuizQuestionVariant>(questionId, (question) => { updateQuestion<QuizQuestionVariant>(questionId, (question) => {
@ -79,12 +84,10 @@ const ResponseSettings = memo<Props>(function ({ questionId, isRequired, isLarge
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> */} </Box>
<Box <Box
sx={{ sx={{
boxSizing: "border-box", boxSizing: "border-box",

@ -1,6 +1,6 @@
import { QuizQuestionVariant } from "@frontend/squzanswerer"; import { QuizQuestionVariant } from "@frontend/squzanswerer";
import UploadImage from "../UploadImage"; import UploadImage from "../../UploadImage";
import HelpQuestions from "../helpQuestions"; import HelpQuestions from "../../helpQuestions";
import ResponseSettings from "./responseSettings"; import ResponseSettings from "./responseSettings";
interface Props { interface Props {
@ -13,11 +13,13 @@ 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}
isMulti={question.content.multi} isMulti={question.content.multi}
isOwn={question.content.own} isOwn={question.content.own}
isOwnPlaceholder={question.content.ownPlaceholder}
/> />
); );
case "help": case "help":

@ -22,8 +22,8 @@ import { useLayoutEffect } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import AddPlus from "../../assets/icons/questionsPage/addPlus"; import AddPlus from "../../assets/icons/questionsPage/addPlus";
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft"; import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal"; import BranchingQuestions from "./Branching/BranchingModal/BranchingQuestionsModal";
import { QuestionSwitchWindowTool } from "./QuestionSwitchWindowTool"; import { QuestionSwitchWindowTool } from "./Branching/QuestionSwitchWindowTool";
interface Props { interface Props {
openBranchingPage: boolean; openBranchingPage: boolean;

@ -1,14 +1,14 @@
import DataOptions from "./DataOptions/DataOptions"; import DateOptions from "./QuestionOptions/DateOptions/DateOptions";
import DropDown from "./DropDown/DropDown"; import DropDown from "./DropDown/DropDown";
import Emoji from "./Emoji/Emoji"; import Emoji from "./Emoji/Emoji";
import OptionsAndPicture from "./OptionsAndPicture/OptionsAndPicture"; import OptionsAndPicture from "./QuestionOptions/OptionsAndPicture/OptionsAndPicture";
import OptionsPicture from "./OptionsPicture/OptionsPicture"; import OptionsPicture from "./QuestionOptions/OptionsPicture/OptionsPicture";
import OwnTextField from "./OwnTextField/OwnTextField"; import OwnTextField from "./OwnTextField/OwnTextField";
import PageOptions from "./PageOptions/PageOptions"; import PageOptions from "./QuestionOptions/PageOptions/PageOptions";
import RatingOptions from "./RatingOptions/RatingOptions"; import RatingOptions from "./QuestionOptions/RatingOptions/RatingOptions";
import SliderOptions from "./SliderOptions/SliderOptions"; import SliderOptions from "./QuestionOptions/SliderOptions/SliderOptions";
import UploadFile from "./UploadFile/UploadFile"; import UploadFile from "./UploadFile/UploadFile";
import AnswerOptions from "./answerOptions/AnswerOptions"; import AnswerOptions from "./QuestionOptions/answerOptions/AnswerOptions";
import { notReachable } from "../../utils/notReachable"; import { notReachable } from "../../utils/notReachable";
import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
@ -76,7 +76,7 @@ export default function SwitchQuestionsPage({ question, openBranchingPage, setOp
case "date": case "date":
return ( return (
<DataOptions <DateOptions
question={question} question={question}
openBranchingPage={openBranchingPage} openBranchingPage={openBranchingPage}
setOpenBranchingPage={setOpenBranchingPage} setOpenBranchingPage={setOpenBranchingPage}

@ -13,7 +13,7 @@ import { updateQuestion } from "@root/questions/actions";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import ArrowDown from "../../../assets/icons/ArrowDownIcon"; import ArrowDown from "../../../assets/icons/ArrowDownIcon";
import InfoIcon from "../../../assets/icons/InfoIcon"; import InfoIcon from "../../../assets/icons/InfoIcon";
import ButtonsOptions from "../ButtonsOptions"; import ButtonsOptions from "../QuestionOptions/ButtonsLayout/ButtonsOptions";
import SwitchUpload from "./switchUpload"; import SwitchUpload from "./switchUpload";
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo"; import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
import { QuizQuestionFile, UploadFileType } from "@frontend/squzanswerer"; import { QuizQuestionFile, UploadFileType } from "@frontend/squzanswerer";
@ -187,7 +187,7 @@ export default function UploadFile({ question, openBranchingPage, setOpenBranchi
</Box> </Box>
<ButtonsOptions <ButtonsOptions
switchState={switchState} switchState={switchState}
SSHC={setSwitchState} setSwitchState={setSwitchState}
questionId={question.id} questionId={question.id}
questionContentId={question.content.id} questionContentId={question.content.id}
questionType={question.type} questionType={question.type}

@ -10,10 +10,10 @@ import StarIconPoints from "./StarIconsPoints";
interface Props { interface Props {
switchState: string; switchState: string;
SSHC: (data: string) => void; setSwitchState: (data: string) => void;
} }
export default function ButtonsOptionsForm({ SSHC, switchState }: Props) { export default function ButtonsOptionsForm({ setSwitchState, switchState }: Props) {
const theme = useTheme(); const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(800)); const isTablet = useMediaQuery(theme.breakpoints.down(800));
@ -74,7 +74,7 @@ export default function ButtonsOptionsForm({ SSHC, switchState }: Props) {
<MiniButtonSetting <MiniButtonSetting
key={index} key={index}
onClick={() => { onClick={() => {
SSHC(value); setSwitchState(value);
}} }}
sx={{ sx={{
backgroundColor: backgroundColor:

@ -24,7 +24,7 @@ export const DescriptionForm = () => {
setPriceButtonsType(type); setPriceButtonsType(type);
}; };
const SSHC = (data: string) => { const setSwitchState = (data: string) => {
setSwitchState(data); setSwitchState(data);
}; };
@ -188,7 +188,7 @@ export const DescriptionForm = () => {
</Button> </Button>
)} )}
</Box> </Box>
<ButtonsOptionsForm switchState={switchState} SSHC={SSHC} /> <ButtonsOptionsForm switchState={switchState} setSwitchState={setSwitchState} />
<SwitchResult switchState={switchState} totalIndex={0} /> <SwitchResult switchState={switchState} totalIndex={0} />
</Box> </Box>
); );

@ -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) {