feat: CustomVariant (WIP)

This commit is contained in:
IlyaDoronin 2023-12-13 14:00:59 +03:00
parent cd04457501
commit b6cd3a6c7f
3 changed files with 157 additions and 62 deletions

@ -41,18 +41,10 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
sx={{ height: "50px", gap: "15px" }} sx={{ height: "50px", gap: "15px" }}
max={currentQuestion.content.steps} max={currentQuestion.content.steps}
icon={ icon={
<StarIconMini <StarIconMini color={theme.palette.brightPurple.main} width={50} />
color={theme.palette.brightPurple.main}
width={50}
sx={{ transform: "scale(1.4)" }}
/>
} }
emptyIcon={ emptyIcon={
<StarIconMini <StarIconMini color={theme.palette.grey2.main} width={50} />
color={theme.palette.grey2.main}
width={50}
sx={{ transform: "scale(1.4)" }}
/>
} }
/> />
<Box <Box

@ -1,3 +1,4 @@
import { useEffect } from "react";
import { import {
Box, Box,
Typography, Typography,
@ -6,32 +7,56 @@ import {
FormControlLabel, FormControlLabel,
Radio, Radio,
Checkbox, Checkbox,
TextField,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { useQuizViewStore, updateAnswer, deleteAnswer } from "@root/quizView"; import {
useQuizViewStore,
updateAnswer,
deleteAnswer,
updateOwnVariant,
deleteOwnVariant,
} from "@root/quizView";
import RadioCheck from "@ui_kit/RadioCheck"; import RadioCheck from "@ui_kit/RadioCheck";
import RadioIcon from "@ui_kit/RadioIcon"; import RadioIcon from "@ui_kit/RadioIcon";
import { CheckboxIcon } from "@icons/Checkbox"; import { CheckboxIcon } from "@icons/Checkbox";
import type { QuizQuestionVariant } from "../../../model/questionTypes/variant"; import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
import type { QuestionVariant } from "../../../model/questionTypes/shared";
type VariantProps = { type VariantProps = {
stepNumber: number; stepNumber: number;
currentQuestion: QuizQuestionVariant; currentQuestion: QuizQuestionVariant;
}; };
type VariantItemProps = {
currentQuestion: QuizQuestionVariant;
variant: QuestionVariant;
answer: string | string[] | undefined;
index: number;
own?: boolean;
};
export const Variant = ({ currentQuestion }: VariantProps) => { export const Variant = ({ currentQuestion }: VariantProps) => {
const { answers } = useQuizViewStore(); const { answers, ownVariants } = useQuizViewStore();
const theme = useTheme();
const { answer } = const { answer } =
answers.find( answers.find(
({ questionId }) => questionId === currentQuestion.content.id ({ questionId }) => questionId === currentQuestion.content.id
) ?? {}; ) ?? {};
const ownVariant = ownVariants.find(
(variant) => variant.contentId === currentQuestion.content.id
);
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup; const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
useEffect(() => {
if (!ownVariant) {
updateOwnVariant(currentQuestion.content.id, "");
}
}, []);
return ( return (
<Box> <Box>
<Typography variant="h5">{currentQuestion.title}</Typography> <Typography variant="h5">{currentQuestion.title}</Typography>
@ -60,58 +85,23 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
}} }}
> >
{currentQuestion.content.variants.map((variant, index) => ( {currentQuestion.content.variants.map((variant, index) => (
<FormControlLabel <VariantItem
key={variant.id} key={variant.id}
sx={{ currentQuestion={currentQuestion}
margin: "0", variant={variant}
borderRadius: "12px", answer={answer}
padding: "15px", index={index}
border: `1px solid ${theme.palette.grey2.main}`,
display: "flex",
maxWidth: "685px",
justifyContent: "space-between",
width: "100%",
}}
value={index}
labelPlacement="start"
control={
currentQuestion.content.multi ? (
<Checkbox
checked={!!answer?.includes(variant.id)}
checkedIcon={<CheckboxIcon checked />}
icon={<CheckboxIcon />}
/>
) : (
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
)
}
label={variant.answer}
onClick={(event) => {
event.preventDefault();
const variantId = currentQuestion.content.variants[index].id;
if (currentQuestion.content.multi) {
const currentAnswer =
typeof answer !== "string" ? answer || [] : [];
updateAnswer(
currentQuestion.content.id,
currentAnswer?.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId]
);
return;
}
updateAnswer(currentQuestion.content.id, variantId);
if (answer === variantId) {
deleteAnswer(currentQuestion.content.id);
}
}}
/> />
))} ))}
{currentQuestion.content.own && ownVariant && (
<VariantItem
own
currentQuestion={currentQuestion}
variant={ownVariant.variant}
answer={answer}
index={currentQuestion.content.variants.length + 2}
/>
)}
</Box> </Box>
</Group> </Group>
{currentQuestion.content.back && ( {currentQuestion.content.back && (
@ -127,3 +117,66 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
</Box> </Box>
); );
}; };
const VariantItem = ({
currentQuestion,
variant,
answer,
index,
own = false,
}: VariantItemProps) => {
const theme = useTheme();
return (
<FormControlLabel
key={variant.id}
sx={{
margin: "0",
borderRadius: "12px",
padding: "15px",
border: `1px solid ${theme.palette.grey2.main}`,
display: "flex",
maxWidth: "685px",
justifyContent: "space-between",
width: "100%",
}}
value={index}
labelPlacement="start"
control={
currentQuestion.content.multi ? (
<Checkbox
checked={!!answer?.includes(variant.id)}
checkedIcon={<CheckboxIcon checked />}
icon={<CheckboxIcon />}
/>
) : (
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
)
}
label={own ? <TextField label="Другое..." /> : variant.answer}
onClick={(event) => {
event.preventDefault();
const variantId = currentQuestion.content.variants[index].id;
if (currentQuestion.content.multi) {
const currentAnswer = typeof answer !== "string" ? answer || [] : [];
updateAnswer(
currentQuestion.content.id,
currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId]
);
return;
}
updateAnswer(currentQuestion.content.id, variantId);
if (answer === variantId) {
deleteAnswer(currentQuestion.content.id);
}
}}
/>
);
};

@ -1,6 +1,8 @@
import { create } from "zustand"; import { create } from "zustand";
import { devtools } from "zustand/middleware"; import { devtools } from "zustand/middleware";
import type { QuestionVariant } from "../model/questionTypes/shared";
type Answer = { type Answer = {
questionId: string; questionId: string;
answer: string | string[]; answer: string | string[];
@ -8,14 +10,21 @@ type Answer = {
changed: boolean; changed: boolean;
}; };
type OwnVariant = {
contentId: string;
variant: QuestionVariant;
};
interface QuizViewStore { interface QuizViewStore {
answers: Answer[]; answers: Answer[];
ownVariants: OwnVariant[];
} }
export const useQuizViewStore = create<QuizViewStore>()( export const useQuizViewStore = create<QuizViewStore>()(
devtools( devtools(
(set, get) => ({ (set, get) => ({
answers: [], answers: [],
ownVariants: [],
}), }),
{ {
name: "quizView", name: "quizView",
@ -50,3 +59,44 @@ export const deleteAnswer = (questionId: string) => {
useQuizViewStore.setState({ answers: filteredItems }); useQuizViewStore.setState({ answers: filteredItems });
}; };
export const updateOwnVariant = (contentId: string, answer: string) => {
const ownVariants = [...useQuizViewStore.getState().ownVariants];
const ownVariantIndex = ownVariants.findIndex(
(variant) => variant.contentId === contentId
);
if (ownVariantIndex < 0) {
ownVariants.push({
contentId,
variant: {
id: getRandom(),
answer,
extendedText: "",
hints: "",
originalImageUrl: "",
},
});
} else {
ownVariants[ownVariantIndex].variant.answer = answer;
}
useQuizViewStore.setState({ ownVariants });
};
export const deleteOwnVariant = (contentId: string) => {
const ownVariants = [...useQuizViewStore.getState().ownVariants];
const filteredOwnVariants = ownVariants.filter(
(variant) => variant.contentId !== contentId
);
useQuizViewStore.setState({ ownVariants: filteredOwnVariants });
};
function getRandom() {
const min = Math.ceil(1000000);
const max = Math.floor(10000000);
return String(Math.floor(Math.random() * (max - min)) + min);
}