fix: little fixes

This commit is contained in:
IlyaDoronin 2023-10-30 19:46:02 +03:00
parent 9dfa464afd
commit 128a33ef80
15 changed files with 284 additions and 210 deletions

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

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

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

@ -1,6 +1,7 @@
import { Box, Typography } from "@mui/material";
import LabeledDatePicker from "@ui_kit/LabeledDatePicker";
import { QuizQuestionDate } from "model/questionTypes/date";
import type { QuizQuestionDate } from "model/questionTypes/date";
interface Props {
question: QuizQuestionDate;

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon";
import { useState, ChangeEvent } from "react";
import {
Box,
FormControl,
@ -9,8 +9,10 @@ import {
Tooltip,
Typography,
} 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 {
question: QuizQuestionEmoji;

@ -1,44 +1,63 @@
import { ChangeEvent, useEffect, useRef, useState } from "react";
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 {
question: QuizQuestionFile;
question: QuizQuestionFile;
}
export default function File({ question }: Props) {
const fileInputRef = useRef<HTMLInputElement>(null);
const [file, setFile] = useState<File | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const [file, setFile] = useState<File | null>(null);
const [acceptedType, setAcceptedType] = useState<any>(
UPLOAD_FILE_TYPES_MAP.all
);
function handleFileChange(event: ChangeEvent<HTMLInputElement>) {
if (!event.target.files?.[0]) return setFile(null);
setFile(event.target.files[0]);
}
useEffect(() => {
setAcceptedType(UPLOAD_FILE_TYPES_MAP[question.content.type]);
}, [question.content.type]);
return (
<Box sx={{
display: "flex",
flexDirection: "column",
alignItems: "start",
gap: 1,
}}>
<Typography variant="h6">{question.title}</Typography>
<Button
variant="contained"
onClick={() => fileInputRef.current?.click()}
>
Загрузить файл
<input
ref={fileInputRef}
onChange={handleFileChange}
type="file"
style={{
display: "none",
}}
/>
</Button>
{file && <Typography>Выбран файл: {file.name}</Typography>}
</Box>
);
function handleFileChange(event: ChangeEvent<HTMLInputElement>) {
if (!event.target.files?.[0]) return setFile(null);
setFile(event.target.files[0]);
}
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "start",
gap: 1,
}}
>
<Typography variant="h6">{question.title}</Typography>
<Button variant="contained" onClick={() => fileInputRef.current?.click()}>
Загрузить файл
<input
ref={fileInputRef}
onChange={handleFileChange}
type="file"
accept={acceptedType}
style={{
display: "none",
}}
/>
</Button>
{file && <Typography>Выбран файл: {file.name}</Typography>}
</Box>
);
}

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon";
import { useEffect, useState } from "react";
import {
Box,
ButtonBase,
@ -7,8 +7,10 @@ import {
Typography,
useTheme,
} 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 {
question: QuizQuestionImages;

@ -1,47 +1,52 @@
import { Box, Typography } from "@mui/material";
import { CustomSlider } from "@ui_kit/CustomSlider";
import { QuizQuestionNumber } from "model/questionTypes/number";
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 {
question: QuizQuestionNumber;
question: QuizQuestionNumber;
}
export default function Number({ question }: Props) {
const [sliderValues, setSliderValues] = useState<number | number[]>(0);
const [sliderValues, setSliderValues] = useState<number | number[]>(0);
const start = question.content.start;
const min = parseInt(question.content.range.split("—")[0]);
const max = parseInt(question.content.range.split("—")[1]);
const start = question.content.start;
const min = parseInt(question.content.range.split("—")[0]);
const max = parseInt(question.content.range.split("—")[1]);
useLayoutEffect(() => {
if (question.content.chooseRange) {
setSliderValues([start, start + (max - start) / 2]);
} else {
setSliderValues(start);
}
}, [max, question.content.chooseRange, start]);
useLayoutEffect(() => {
if (question.content.chooseRange) {
setSliderValues([start, start + (max - start) / 2]);
} else {
setSliderValues(start);
}
}, [max, question.content.chooseRange, start]);
return (
<Box sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}>
<Typography variant="h6">{question.title}</Typography>
<Box sx={{
px: 2,
}}>
<CustomSlider
value={sliderValues}
onChange={value => setSliderValues(value)}
min={min}
max={max}
defaultValue={start}
step={question.content.step}
/>
</Box>
</Box>
);
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}
>
<Typography variant="h6">{question.title}</Typography>
<Box
sx={{
px: 2,
}}
>
<CustomSlider
value={sliderValues}
onChange={(value) => setSliderValues(value)}
min={min}
max={max}
defaultValue={start}
step={question.content.step}
/>
</Box>
</Box>
);
}

@ -1,34 +1,35 @@
import { Box, Typography } from "@mui/material";
import { QuizQuestionPage } from "model/questionTypes/page";
import type { QuizQuestionPage } from "model/questionTypes/page";
interface Props {
question: QuizQuestionPage;
question: QuizQuestionPage;
}
export default function Page({ question }: Props) {
return (
<Box sx={{
display: "flex",
flexDirection: "column",
alignItems: "start",
gap: 1,
}}>
<Typography variant="h6">{question.title}</Typography>
<Typography>{question.content.text}</Typography>
{question.content.picture &&
<img
src={question.content.picture}
alt=""
style={{
width: "100%",
display: "block",
objectFit: "scale-down",
flexGrow: 1,
}}
/>
}
</Box>
);
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "start",
gap: 1,
}}
>
<Typography variant="h6">{question.title}</Typography>
<Typography>{question.content.text}</Typography>
{question.content.picture && (
<img
src={question.content.picture}
alt=""
style={{
width: "100%",
display: "block",
objectFit: "scale-down",
flexGrow: 1,
}}
/>
)}
</Box>
);
}

@ -1,91 +1,113 @@
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import { FC, useState } from "react";
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon";
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 { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
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; }>> = {
"star": StarIconMini,
"trophie": TropfyIcon,
"flag": FlagIcon,
"heart": HeartIcon,
"like": LikeIcon,
"bubble": LightbulbIcon,
"hashtag": HashtagIcon,
type RatingIconType =
| "star"
| "trophie"
| "flag"
| "heart"
| "like"
| "bubble"
| "hashtag";
const ratingIconComponentByType: Record<
RatingIconType,
FC<{ color: string }>
> = {
star: StarIconMini,
trophie: TropfyIcon,
flag: FlagIcon,
heart: HeartIcon,
like: LikeIcon,
bubble: LightbulbIcon,
hashtag: HashtagIcon,
};
interface Props {
question: QuizQuestionRating;
question: QuizQuestionRating;
}
export default function Rating({ question }: Props) {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const [selectedRating, setSelectedRating] = useState<number>(0);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const [selectedRating, setSelectedRating] = useState<number>(0);
console.log(question);
console.log(question);
const RatingIconComponent = ratingIconComponentByType[question.content.form as RatingIconType];
const RatingIconComponent =
ratingIconComponentByType[question.content.form as RatingIconType];
return (
<Box sx={{
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}
>
<Typography variant="h6">{question.title}</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
width: "fit-content",
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}>
<Typography variant="h6">{question.title}</Typography>
<Box sx={{
display: "flex",
flexDirection: "column",
gap: 1,
width: "fit-content",
}}>
<Box sx={{
display: "flex",
gap: isMobile ? "10px" : "15px",
flexWrap: "wrap",
}}>
{Array.from(
{ length: question.content.steps },
(_, index) => index
).map((itemNumber) => (
<Box
key={itemNumber}
onClick={() => setSelectedRating(itemNumber + 1)}
sx={{
cursor: "pointer",
transform: "scale(1.5)",
":hover": {
transform: "scale(1.7)",
transition: "0.2s",
},
}}
>
<RatingIconComponent color={
selectedRating > itemNumber
? theme.palette.brightPurple.main
: theme.palette.grey2.main
} />
</Box>
))}
</Box>
<Box sx={{
display: "flex",
justifyContent: "space-between",
gap: 2,
}}>
<Typography>{question.content.ratingNegativeDescription}</Typography>
<Typography>{question.content.ratingPositiveDescription}</Typography>
</Box>
gap: isMobile ? "10px" : "15px",
flexWrap: "wrap",
}}
>
{Array.from(
{ length: question.content.steps },
(_, index) => index
).map((itemNumber) => (
<Box
key={itemNumber}
onClick={() => setSelectedRating(itemNumber + 1)}
sx={{
cursor: "pointer",
transform: "scale(1.5)",
":hover": {
transform: "scale(1.7)",
transition: "0.2s",
},
}}
>
<RatingIconComponent
color={
selectedRating > itemNumber
? theme.palette.brightPurple.main
: theme.palette.grey2.main
}
/>
</Box>
))}
</Box>
);
<Box
sx={{
display: "flex",
justifyContent: "space-between",
gap: 2,
}}
>
<Typography>{question.content.ratingNegativeDescription}</Typography>
<Typography>{question.content.ratingPositiveDescription}</Typography>
</Box>
</Box>
</Box>
);
}

@ -1,4 +1,4 @@
import ArrowDownIcon from "@icons/ArrowDownIcon";
import { useState } from "react";
import {
Box,
FormControl,
@ -8,9 +8,10 @@ import {
Typography,
useTheme,
} from "@mui/material";
import { QuizQuestionSelect } from "model/questionTypes/select";
import { useState } from "react";
import ArrowDownIcon from "@icons/ArrowDownIcon";
import type { QuizQuestionSelect } from "model/questionTypes/select";
interface Props {
question: QuizQuestionSelect;
}
@ -45,6 +46,7 @@ export default function Text({ question }: Props) {
id="category-select"
variant="outlined"
value={selectValue}
placeholder={question.content.default}
displayEmpty
onChange={handleChange}
sx={{
@ -84,6 +86,15 @@ export default function Text({ question }: Props) {
alignItems: "center",
px: "9px",
gap: "20px",
"& + input": !selectValue && {
border: "none",
transform: "translateY(-50%)",
top: "50%",
left: "10px",
opacity: 1,
color: "#333",
fontSize: "16px",
},
},
}}
IconComponent={(props) => <ArrowDownIcon {...props} />}

@ -1,24 +1,24 @@
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 {
question: QuizQuestionText;
question: QuizQuestionText;
}
export default function Text({ question }: Props) {
return (
<Box sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}>
<Typography variant="h6">{question.title}</Typography>
<CustomTextField
placeholder={question.content.placeholder}
/>
</Box>
);
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
}}
>
<Typography variant="h6">{question.title}</Typography>
<CustomTextField placeholder={question.content.placeholder} />
</Box>
);
}

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon";
import { ChangeEvent, useState } from "react";
import {
Box,
FormControl,
@ -9,8 +9,10 @@ import {
Tooltip,
Typography,
} 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 {
question: QuizQuestionVariant;

@ -1,4 +1,4 @@
import InfoIcon from "@icons/InfoIcon";
import { useState, ChangeEvent } from "react";
import {
Box,
FormControl,
@ -9,9 +9,11 @@ import {
Tooltip,
Typography,
} from "@mui/material";
import { QuestionVariant } from "model/questionTypes/shared";
import { QuizQuestionVarImg } from "model/questionTypes/varimg";
import { useState, ChangeEvent } from "react";
import InfoIcon from "@icons/InfoIcon";
import type { QuestionVariant } from "model/questionTypes/shared";
import type { QuizQuestionVarImg } from "model/questionTypes/varimg";
interface Props {
question: QuizQuestionVarImg;

@ -7,7 +7,11 @@ interface Props {
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 isTablet = useMediaQuery(theme.breakpoints.down(1000));
@ -18,7 +22,7 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
display: "flex",
justifyContent: "center",
flexDirection: "column",
height: "51px",
height: "73px",
borderRadius: "13px",
border: "solid #7E2AEA 1px",
padding: "0 0 20px 0",
@ -33,7 +37,7 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
sx={{
width: "100%",
flexGrow: 1,
paddingLeft: 0,
padding: "8px 0",
"& .css-1ej0n1q-MuiLinearProgress-root-MuiMobileStepper-progress": {
height: "10px",
background: "#ffffff",
@ -47,7 +51,9 @@ export default function ProgressMobileStepper({ desc, activeStep = 1, steps = 8
backButton={<></>}
/>
<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}
</Typography>