feat: CustomVariant (WIP)
This commit is contained in:
parent
cd04457501
commit
b6cd3a6c7f
@ -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);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user