Merge branch 'quiz-fixes' into 'dev'

feat: quiz fixes

See merge request frontend/squiz!43
This commit is contained in:
Nastya 2023-11-01 13:51:23 +00:00
commit cca074feb4
20 changed files with 598 additions and 1087 deletions

@ -12,5 +12,6 @@ export const QUIZ_QUESTION_TEXT: Omit<QuizQuestionText, "id"> = {
innerName: "", innerName: "",
required: false, required: false,
answerType: "single", answerType: "single",
onlyNumbers: false,
}, },
}; };

@ -4,7 +4,7 @@ import type {
QuestionBranchingRule, QuestionBranchingRule,
} from "./shared"; } from "./shared";
export const uploadFileTypesMap = { export const UPLOAD_FILE_TYPES_MAP = {
all: "Все типы файлов", all: "Все типы файлов",
picture: "Изображения", picture: "Изображения",
video: "Видео", video: "Видео",
@ -12,7 +12,7 @@ export const uploadFileTypesMap = {
document: "Документ", document: "Документ",
} as const; } as const;
export type UploadFileType = keyof typeof uploadFileTypesMap; export type UploadFileType = keyof typeof UPLOAD_FILE_TYPES_MAP;
export interface QuizQuestionFile extends QuizQuestionBase { export interface QuizQuestionFile extends QuizQuestionBase {
type: "file"; type: "file";

@ -16,10 +16,11 @@ export interface QuizQuestionText extends QuizQuestionBase {
required: boolean; required: boolean;
/** Чекбокс "Автозаполнение адреса" */ /** Чекбокс "Автозаполнение адреса" */
autofill: boolean; autofill: boolean;
answerType: "single" | "multi" | "number"; answerType: "single" | "multi";
hint: QuestionHint; hint: QuestionHint;
rule: QuestionBranchingRule; rule: QuestionBranchingRule;
back: string; back: string;
originalBack: string; originalBack: string;
onlyNumbers: boolean;
}; };
} }

@ -134,6 +134,7 @@ export const ChooseAnswerModal = ({
removeQuestionForce(quizId, question.id); removeQuestionForce(quizId, question.id);
createQuestion(quizId, selectedValue, totalIndex); createQuestion(quizId, selectedValue, totalIndex);
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, { updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
title: question.title,
expanded: question.expanded, expanded: question.expanded,
}); });
}} }}

@ -226,7 +226,7 @@ export default function QuestionsPageCard({
sx={{ sx={{
margin: isMobile ? "10px 0" : 0, margin: isMobile ? "10px 0" : 0,
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
color: question.expanded ? "#000000" : "#4D4D4D", color: "#000000",
backgroundColor: question.expanded backgroundColor: question.expanded
? theme.palette.background.default ? theme.palette.background.default
: "transparent", : "transparent",

@ -28,16 +28,17 @@ type SettingTextFieldProps = {
type Answer = { type Answer = {
name: string; name: string;
value: "single" | "multi" | "number"; value: "single" | "multi";
}; };
const ANSWER_TYPES: Answer[] = [ const ANSWER_TYPES: Answer[] = [
{ name: "Однострочное", value: "single" }, { name: "Однострочное", value: "single" },
{ name: "Многострочное", value: "multi" }, { name: "Многострочное", value: "multi" },
{ name: "Только числа", value: "number" },
]; ];
export default function SettingTextField({ totalIndex }: SettingTextFieldProps) { export default function SettingTextField({
totalIndex,
}: SettingTextFieldProps) {
const { listQuestions } = questionStore(); const { listQuestions } = questionStore();
const quizId = Number(useParams().quizId); const quizId = Number(useParams().quizId);
const theme = useTheme(); const theme = useTheme();
@ -68,12 +69,24 @@ export default function SettingTextField({ totalIndex }: SettingTextFieldProps)
pl: "20px", pl: "20px",
}} }}
> >
<Typography sx={{ fontWeight: "500", fontSize: "18px", color: " #4D4D4D", marginBottom: "14px" }}> <Typography
sx={{
fontWeight: "500",
fontSize: "18px",
color: " #4D4D4D",
marginBottom: "14px",
}}
>
Настройки ответов Настройки ответов
</Typography> </Typography>
<FormControl> <FormControl>
<RadioGroup <RadioGroup
sx={{ display: "flex", flexDirection: "column", gap: "14px", width: "100%" }} sx={{
display: "flex",
flexDirection: "column",
gap: "14px",
width: "100%",
}}
aria-labelledby="demo-controlled-radio-buttons-group" aria-labelledby="demo-controlled-radio-buttons-group"
name="controlled-radio-buttons-group" name="controlled-radio-buttons-group"
value={ANSWER_TYPES.findIndex( value={ANSWER_TYPES.findIndex(
@ -97,12 +110,29 @@ export default function SettingTextField({ totalIndex }: SettingTextFieldProps)
"& .MuiRadio-root": { padding: "8px 9px" }, "& .MuiRadio-root": { padding: "8px 9px" },
}} }}
value={index} value={index}
control={<Radio icon={<CheckIcon />} checkedIcon={<CheckedIcon />} />} control={
<Radio icon={<CheckIcon />} checkedIcon={<CheckedIcon />} />
}
label={name} label={name}
/> />
))} ))}
</RadioGroup> </RadioGroup>
</FormControl> </FormControl>
<CustomCheckbox
sx={{
display: isMobile ? "flex" : "block",
mr: isMobile ? "0px" : "16px",
marginTop: "15px",
alignItems: isMobile ? "flex-end" : "center",
}}
label={"Только числа"}
checked={question.content.onlyNumbers}
handleChange={({ target }) => {
updateQuestionsList<QuizQuestionText>(quizId, totalIndex, {
content: { ...question.content, onlyNumbers: target.checked },
});
}}
/>
</Box> </Box>
<Box <Box
sx={{ sx={{
@ -115,7 +145,14 @@ export default function SettingTextField({ totalIndex }: SettingTextFieldProps)
gap: "14px", gap: "14px",
}} }}
> >
<Typography sx={{ height: isMobile ? "18px" : "auto", fontWeight: "500", fontSize: "18px", color: " #4D4D4D" }}> <Typography
sx={{
height: isMobile ? "18px" : "auto",
fontWeight: "500",
fontSize: "18px",
color: " #4D4D4D",
}}
>
Настройки вопросов Настройки вопросов
</Typography> </Typography>
<CustomCheckbox <CustomCheckbox
@ -172,7 +209,10 @@ export default function SettingTextField({ totalIndex }: SettingTextFieldProps)
}); });
}} }}
/> />
<Tooltip title="Будет отображаться как заголовок вопроса в приходящих заявках." placement="top"> <Tooltip
title="Будет отображаться как заголовок вопроса в приходящих заявках."
placement="top"
>
<Box> <Box>
<InfoIcon /> <InfoIcon />
</Box> </Box>

@ -160,5 +160,4 @@ export default function QuizPreviewLayout() {
</Box> </Box>
</Paper> </Paper>
); );
} }

@ -1,20 +1,21 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import LabeledDatePicker from "@ui_kit/LabeledDatePicker";
import { QuizQuestionDate } from "model/questionTypes/date";
import LabeledDatePicker from "@ui_kit/LabeledDatePicker";
import type { QuizQuestionDate } from "model/questionTypes/date";
interface Props { interface Props {
question: QuizQuestionDate; question: QuizQuestionDate;
} }
export default function Date({ question }: Props) { export default function Date({ question }: Props) {
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<LabeledDatePicker /> <LabeledDatePicker />
</Box> </Box>

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon"; import { useState, ChangeEvent } from "react";
import { import {
Box, Box,
FormControl, FormControl,
@ -9,8 +9,10 @@ import {
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { QuizQuestionEmoji } from "model/questionTypes/emoji";
import { useState, ChangeEvent } from "react"; import InfoIcon from "@icons/InfoIcon";
import type { QuizQuestionEmoji } from "model/questionTypes/emoji";
interface Props { interface Props {
question: QuizQuestionEmoji; question: QuizQuestionEmoji;
@ -31,7 +33,9 @@ export default function Emoji({ question }: Props) {
value={value} value={value}
onChange={handleChange} onChange={handleChange}
> >
{question.content.variants.map((variant, index) => ( {question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<FormControlLabel <FormControlLabel
key={index} key={index}
value={variant.answer} value={variant.answer}
@ -39,11 +43,13 @@ export default function Emoji({ question }: Props) {
label={ label={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}> <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<Typography>{`${variant.extendedText} ${variant.answer}`}</Typography> <Typography>{`${variant.extendedText} ${variant.answer}`}</Typography>
{variant.hints && (
<Tooltip title="Подсказка" placement="right"> <Tooltip title="Подсказка" placement="right">
<Box> <Box>
<InfoIcon /> <InfoIcon />
</Box> </Box>
</Tooltip> </Tooltip>
)}
</Box> </Box>
} }
/> />

@ -1,7 +1,19 @@
import { ChangeEvent, useEffect, useRef, useState } from "react";
import { Box, Button, Typography } from "@mui/material"; import { Box, Button, Typography } from "@mui/material";
import { QuizQuestionFile } from "model/questionTypes/file";
import { ChangeEvent, useRef, useState } from "react";
import type {
QuizQuestionFile,
UploadFileType,
} from "model/questionTypes/file";
export const UPLOAD_FILE_TYPES_MAP: Record<UploadFileType, string> = {
all: "file",
picture: "image/*",
video: "video/*",
audio: "audio/*",
document:
".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf",
} as const;
interface Props { interface Props {
question: QuizQuestionFile; question: QuizQuestionFile;
@ -10,6 +22,13 @@ interface Props {
export default function File({ question }: Props) { export default function File({ question }: Props) {
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [acceptedType, setAcceptedType] = useState<any>(
UPLOAD_FILE_TYPES_MAP.all
);
useEffect(() => {
setAcceptedType(UPLOAD_FILE_TYPES_MAP[question.content.type]);
}, [question.content.type]);
function handleFileChange(event: ChangeEvent<HTMLInputElement>) { function handleFileChange(event: ChangeEvent<HTMLInputElement>) {
if (!event.target.files?.[0]) return setFile(null); if (!event.target.files?.[0]) return setFile(null);
@ -17,22 +36,22 @@ export default function File({ question }: Props) {
} }
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "start", alignItems: "start",
gap: 1, gap: 1,
}}> }}
<Typography variant="h6">{question.title}</Typography>
<Button
variant="contained"
onClick={() => fileInputRef.current?.click()}
> >
<Typography variant="h6">{question.title}</Typography>
<Button variant="contained" onClick={() => fileInputRef.current?.click()}>
Загрузить файл Загрузить файл
<input <input
ref={fileInputRef} ref={fileInputRef}
onChange={handleFileChange} onChange={handleFileChange}
type="file" type="file"
accept={acceptedType}
style={{ style={{
display: "none", display: "none",
}} }}

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon"; import { useEffect, useState } from "react";
import { import {
Box, Box,
ButtonBase, ButtonBase,
@ -7,8 +7,10 @@ import {
Typography, Typography,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { QuizQuestionImages } from "model/questionTypes/images";
import { useEffect, useState } from "react"; import InfoIcon from "@icons/InfoIcon";
import type { QuizQuestionImages } from "model/questionTypes/images";
interface Props { interface Props {
question: QuizQuestionImages; question: QuizQuestionImages;
@ -53,7 +55,9 @@ export default function Images({ question }: Props) {
gap: 1, gap: 1,
}} }}
> >
{question.content.variants.map((variant, index) => ( {question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<ButtonBase <ButtonBase
key={index} key={index}
onClick={() => handleVariantClick(index)} onClick={() => handleVariantClick(index)}
@ -93,11 +97,13 @@ export default function Images({ question }: Props) {
}} }}
> >
<Typography>{variant.answer}</Typography> <Typography>{variant.answer}</Typography>
<Tooltip title="Подсказка" placement="right"> {variant.hints && (
<Tooltip title={variant.hints} placement="right">
<Box> <Box>
<InfoIcon /> <InfoIcon />
</Box> </Box>
</Tooltip> </Tooltip>
)}
</Box> </Box>
</ButtonBase> </ButtonBase>
))} ))}

@ -1,8 +1,9 @@
import { Box, Typography } from "@mui/material";
import { CustomSlider } from "@ui_kit/CustomSlider";
import { QuizQuestionNumber } from "model/questionTypes/number";
import { useLayoutEffect, useState } from "react"; import { useLayoutEffect, useState } from "react";
import { Box, Typography } from "@mui/material";
import { CustomSlider } from "@ui_kit/CustomSlider";
import type { QuizQuestionNumber } from "model/questionTypes/number";
interface Props { interface Props {
question: QuizQuestionNumber; question: QuizQuestionNumber;
@ -24,18 +25,22 @@ export default function Number({ question }: Props) {
}, [max, question.content.chooseRange, start]); }, [max, question.content.chooseRange, start]);
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<Box sx={{ <Box
sx={{
px: 2, px: 2,
}}> }}
>
<CustomSlider <CustomSlider
value={sliderValues} value={sliderValues}
onChange={value => setSliderValues(value)} onChange={(value) => setSliderValues(value)}
min={min} min={min}
max={max} max={max}
defaultValue={start} defaultValue={start}

@ -1,23 +1,24 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { QuizQuestionPage } from "model/questionTypes/page";
import type { QuizQuestionPage } from "model/questionTypes/page";
interface Props { interface Props {
question: QuizQuestionPage; question: QuizQuestionPage;
} }
export default function Page({ question }: Props) { export default function Page({ question }: Props) {
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "start", alignItems: "start",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<Typography>{question.content.text}</Typography> <Typography>{question.content.text}</Typography>
{question.content.picture && {question.content.picture && (
<img <img
src={question.content.picture} src={question.content.picture}
alt="" alt=""
@ -28,7 +29,7 @@ export default function Page({ question }: Props) {
flexGrow: 1, flexGrow: 1,
}} }}
/> />
} )}
</Box> </Box>
); );
} }

@ -1,25 +1,36 @@
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import { FC, useState } from "react"; import { FC, useState } from "react";
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon"; import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini";
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon";
import HeartIcon from "../../../assets/icons/questionsPage/heartIcon";
import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon";
import LikeIcon from "../../../assets/icons/questionsPage/likeIcon";
import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon";
import { QuizQuestionRating } from "model/questionTypes/rating";
import FlagIcon from "@icons/questionsPage/FlagIcon";
import StarIconMini from "@icons/questionsPage/StarIconMini";
import HashtagIcon from "@icons/questionsPage/hashtagIcon";
import HeartIcon from "@icons/questionsPage/heartIcon";
import LightbulbIcon from "@icons/questionsPage/lightbulbIcon";
import LikeIcon from "@icons/questionsPage/likeIcon";
import TropfyIcon from "@icons/questionsPage/tropfyIcon";
type RatingIconType = "star" | "trophie" | "flag" | "heart" | "like" | "bubble" | "hashtag"; import type { QuizQuestionRating } from "model/questionTypes/rating";
const ratingIconComponentByType: Record<RatingIconType, FC<{ color: string; }>> = { type RatingIconType =
"star": StarIconMini, | "star"
"trophie": TropfyIcon, | "trophie"
"flag": FlagIcon, | "flag"
"heart": HeartIcon, | "heart"
"like": LikeIcon, | "like"
"bubble": LightbulbIcon, | "bubble"
"hashtag": HashtagIcon, | "hashtag";
const ratingIconComponentByType: Record<
RatingIconType,
FC<{ color: string }>
> = {
star: StarIconMini,
trophie: TropfyIcon,
flag: FlagIcon,
heart: HeartIcon,
like: LikeIcon,
bubble: LightbulbIcon,
hashtag: HashtagIcon,
}; };
interface Props { interface Props {
@ -33,26 +44,33 @@ export default function Rating({ question }: Props) {
console.log(question); console.log(question);
const RatingIconComponent = ratingIconComponentByType[question.content.form as RatingIconType]; const RatingIconComponent =
ratingIconComponentByType[question.content.form as RatingIconType];
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
width: "fit-content", width: "fit-content",
}}> }}
<Box sx={{ >
<Box
sx={{
display: "flex", display: "flex",
gap: isMobile ? "10px" : "15px", gap: isMobile ? "10px" : "15px",
flexWrap: "wrap", flexWrap: "wrap",
}}> }}
>
{Array.from( {Array.from(
{ length: question.content.steps }, { length: question.content.steps },
(_, index) => index (_, index) => index
@ -69,19 +87,23 @@ export default function Rating({ question }: Props) {
}, },
}} }}
> >
<RatingIconComponent color={ <RatingIconComponent
color={
selectedRating > itemNumber selectedRating > itemNumber
? theme.palette.brightPurple.main ? theme.palette.brightPurple.main
: theme.palette.grey2.main : theme.palette.grey2.main
} /> }
/>
</Box> </Box>
))} ))}
</Box> </Box>
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
gap: 2, gap: 2,
}}> }}
>
<Typography>{question.content.ratingNegativeDescription}</Typography> <Typography>{question.content.ratingNegativeDescription}</Typography>
<Typography>{question.content.ratingPositiveDescription}</Typography> <Typography>{question.content.ratingPositiveDescription}</Typography>
</Box> </Box>

@ -1,9 +1,17 @@
import ArrowDownIcon from "@icons/ArrowDownIcon";
import { Box, FormControl, MenuItem, Select, SelectChangeEvent, Typography, useTheme } from "@mui/material";
import { QuizQuestionSelect } from "model/questionTypes/select";
import { useState } from "react"; import { useState } from "react";
import {
Box,
FormControl,
MenuItem,
Select,
SelectChangeEvent,
Typography,
useTheme,
} from "@mui/material";
import ArrowDownIcon from "@icons/ArrowDownIcon";
import type { QuizQuestionSelect } from "model/questionTypes/select";
interface Props { interface Props {
question: QuizQuestionSelect; question: QuizQuestionSelect;
} }
@ -17,11 +25,13 @@ export default function Text({ question }: Props) {
} }
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<FormControl <FormControl
fullWidth fullWidth
@ -36,6 +46,7 @@ export default function Text({ question }: Props) {
id="category-select" id="category-select"
variant="outlined" variant="outlined"
value={selectValue} value={selectValue}
placeholder={question.content.default}
displayEmpty displayEmpty
onChange={handleChange} onChange={handleChange}
sx={{ sx={{
@ -75,11 +86,22 @@ export default function Text({ question }: Props) {
alignItems: "center", alignItems: "center",
px: "9px", px: "9px",
gap: "20px", gap: "20px",
"& + input": !selectValue && {
border: "none",
transform: "translateY(-50%)",
top: "50%",
left: "10px",
opacity: 1,
color: "#333",
fontSize: "16px",
},
}, },
}} }}
IconComponent={(props) => <ArrowDownIcon {...props} />} IconComponent={(props) => <ArrowDownIcon {...props} />}
> >
{question.content.variants.map(variant => ( {question.content.variants
.filter(({ answer }) => answer)
.map((variant) => (
<MenuItem <MenuItem
key={variant.answer} key={variant.answer}
value={variant.answer} value={variant.answer}

@ -1,24 +1,24 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField";
import { QuizQuestionText } from "model/questionTypes/text";
import CustomTextField from "@ui_kit/CustomTextField";
import type { QuizQuestionText } from "model/questionTypes/text";
interface Props { interface Props {
question: QuizQuestionText; question: QuizQuestionText;
} }
export default function Text({ question }: Props) { export default function Text({ question }: Props) {
return ( return (
<Box sx={{ <Box
sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 1, gap: 1,
}}> }}
>
<Typography variant="h6">{question.title}</Typography> <Typography variant="h6">{question.title}</Typography>
<CustomTextField <CustomTextField placeholder={question.content.placeholder} />
placeholder={question.content.placeholder}
/>
</Box> </Box>
); );
} }

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon"; import { ChangeEvent, useState } from "react";
import { import {
Box, Box,
FormControl, FormControl,
@ -9,8 +9,10 @@ import {
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { QuizQuestionVariant } from "model/questionTypes/variant";
import { ChangeEvent, useState } from "react"; import InfoIcon from "@icons/InfoIcon";
import type { QuizQuestionVariant } from "model/questionTypes/variant";
interface Props { interface Props {
question: QuizQuestionVariant; question: QuizQuestionVariant;
@ -25,34 +27,39 @@ export default function Variant({ question }: Props) {
return ( return (
<FormControl fullWidth> <FormControl fullWidth>
<FormLabel <FormLabel id="quiz-question-radio-group" data-cy="variant-title">
id="quiz-question-radio-group" {question.title}
data-cy="variant-title" </FormLabel>
>{question.title}</FormLabel>
<RadioGroup <RadioGroup
aria-labelledby="quiz-question-radio-group" aria-labelledby="quiz-question-radio-group"
value={value} value={value}
onChange={handleChange} onChange={handleChange}
> >
{question.content.variants.map((variant, index) => ( {question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<FormControlLabel <FormControlLabel
key={index} key={index}
value={variant.answer} value={variant.answer}
control={<Radio control={
<Radio
inputProps={{ inputProps={{
"data-cy": "variant-radio", "data-cy": "variant-radio",
}} }}
/>} />
}
label={ label={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}> <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<Typography <Typography data-cy="variant-answer">
data-cy="variant-answer" {variant.answer}
>{variant.answer}</Typography> </Typography>
{variant.hints && (
<Tooltip title={variant.hints} placement="right"> <Tooltip title={variant.hints} placement="right">
<Box> <Box>
<InfoIcon /> <InfoIcon />
</Box> </Box>
</Tooltip> </Tooltip>
)}
</Box> </Box>
} }
/> />

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon"; import { useState, ChangeEvent } from "react";
import { import {
Box, Box,
FormControl, FormControl,
@ -9,9 +9,11 @@ import {
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { QuestionVariant } from "model/questionTypes/shared";
import { QuizQuestionVarImg } from "model/questionTypes/varimg"; import InfoIcon from "@icons/InfoIcon";
import { useState, ChangeEvent } from "react";
import type { QuestionVariant } from "model/questionTypes/shared";
import type { QuizQuestionVarImg } from "model/questionTypes/varimg";
interface Props { interface Props {
question: QuizQuestionVarImg; question: QuizQuestionVarImg;
@ -46,7 +48,9 @@ export default function Varimg({ question }: Props) {
value={currentVariant?.answer ?? ""} value={currentVariant?.answer ?? ""}
onChange={handleChange} onChange={handleChange}
> >
{question.content.variants.map((variant, index) => ( {question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<FormControlLabel <FormControlLabel
key={index} key={index}
value={variant.answer} value={variant.answer}
@ -54,11 +58,13 @@ export default function Varimg({ question }: Props) {
label={ label={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}> <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<Typography>{variant.answer}</Typography> <Typography>{variant.answer}</Typography>
<Tooltip title="Подсказка" placement="right"> {variant.hints && (
<Tooltip title={variant.hints} placement="right">
<Box> <Box>
<InfoIcon /> <InfoIcon />
</Box> </Box>
</Tooltip> </Tooltip>
)}
</Box> </Box>
} }
/> />

@ -7,7 +7,11 @@ interface Props {
steps?: number; steps?: number;
} }
export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8 }: Props) { export default function ProgressMobileStepper({
desc,
activeStep = 1,
steps = 8,
}: Props) {
const theme = useTheme(); const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const isTablet = useMediaQuery(theme.breakpoints.down(1000));
@ -18,7 +22,7 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
display: "flex", display: "flex",
justifyContent: "center", justifyContent: "center",
flexDirection: "column", flexDirection: "column",
height: "51px", height: "73px",
borderRadius: "13px", borderRadius: "13px",
border: "solid #7E2AEA 1px", border: "solid #7E2AEA 1px",
padding: "0 0 20px 0", padding: "0 0 20px 0",
@ -33,7 +37,7 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
sx={{ sx={{
width: "100%", width: "100%",
flexGrow: 1, flexGrow: 1,
paddingLeft: 0, padding: "8px 0",
"& .css-1ej0n1q-MuiLinearProgress-root-MuiMobileStepper-progress": { "& .css-1ej0n1q-MuiLinearProgress-root-MuiMobileStepper-progress": {
height: "10px", height: "10px",
background: "#ffffff", background: "#ffffff",
@ -47,7 +51,9 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
backButton={<></>} backButton={<></>}
/> />
<Box sx={{ padding: "3px 3px 3px 20px" }}> <Box sx={{ padding: "3px 3px 3px 20px" }}>
<Typography sx={{ fontWeight: 400, fontSize: "12px", lineHeight: "14.22px" }}> <Typography
sx={{ fontWeight: 400, fontSize: "12px", lineHeight: "14.22px" }}
>
{" "} {" "}
Шаг {activeStep} из {steps - 1} Шаг {activeStep} из {steps - 1}
</Typography> </Typography>

672
yarn.lock

File diff suppressed because it is too large Load Diff