diff --git a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx index b32079b..76ff246 100644 --- a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx @@ -1,6 +1,16 @@ import type { QuestionVariant } from "@/model/questionTypes/shared"; import { useQuizSettings } from "@contexts/QuizDataContext"; -import { Box, FormControl, FormControlLabel, Radio, Typography, useTheme } from "@mui/material"; +import { + Box, + Checkbox, + FormControl, + FormControlLabel, + Input, + Radio, + TextareaAutosize, + Typography, + useTheme, +} from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import RadioCheck from "@ui_kit/RadioCheck"; import RadioIcon from "@ui_kit/RadioIcon"; @@ -14,18 +24,96 @@ type EmojiVariantProps = { questionId: string; variant: QuestionVariant; index: number; + isMulti: boolean; + own: boolean; + questionLargeCheck: boolean; + ownPlaceholder: string; + answer: string | string[] | undefined; }; -export const EmojiVariant = ({ variant, index, questionId }: EmojiVariantProps) => { +interface OwnInputProps { + questionId: string; + variant: QuestionVariant; + largeCheck: boolean; + ownPlaceholder: string; +} +const OwnInput = ({ questionId, variant, largeCheck, ownPlaceholder }: OwnInputProps) => { + const theme = useTheme(); + const ownVariants = useQuizViewStore((state) => state.ownVariants); + const { updateOwnVariant } = useQuizViewStore((state) => state); + + const ownAnswer = ownVariants[ownVariants.findIndex((v) => v.id === variant.id)]?.variant.answer || ""; + + return largeCheck ? ( + + ) => e.stopPropagation()} + onChange={(e: React.ChangeEvent) => { + updateOwnVariant(variant.id, e.target.value); + }} + /> + + ) : ( + ) => e.stopPropagation()} + onChange={(e: React.ChangeEvent) => { + updateOwnVariant(variant.id, e.target.value); + }} + /> + ); +}; + +export const EmojiVariant = ({ + answer, + variant, + index, + questionId, + isMulti, + own, + questionLargeCheck, + ownPlaceholder, +}: EmojiVariantProps) => { const { settings } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); - const { answer } = answers.find((answer) => answer.questionId === questionId) ?? {}; const onVariantClick = async (event: MouseEvent) => { event.preventDefault(); + const variantId = variant.id; + if (isMulti) { + const currentAnswer = typeof answer !== "string" ? answer || [] : []; + + return updateAnswer( + questionId, + currentAnswer.includes(variantId) + ? currentAnswer?.filter((item) => item !== variantId) + : [...currentAnswer, variantId], + variant.points || 0 + ); + } + updateAnswer(questionId, variant.id, variant.points || 0); if (answer === variant.id) { @@ -39,7 +127,7 @@ export const EmojiVariant = ({ variant, index, questionId }: EmojiVariantProps) sx={{ borderRadius: "12px", border: `1px solid`, - borderColor: answer === variant.id ? theme.palette.primary.main : "#9A9AAF", + borderColor: answer?.includes(variant.id) ? theme.palette.primary.main : "#9A9AAF", overflow: "hidden", maxWidth: "317px", width: "100%", @@ -85,6 +173,7 @@ export const EmojiVariant = ({ variant, index, questionId }: EmojiVariantProps) alignItems: variant.answer.length <= 60 ? "center" : "flex-start", position: "relative", height: "80px", + overflow: "auto", justifyContent: "center", "& .MuiFormControlLabel-label": { wordBreak: "break-word", @@ -101,16 +190,34 @@ export const EmojiVariant = ({ variant, index, questionId }: EmojiVariantProps) }} value={index} control={ - } - icon={} - sx={{ position: "absolute", top: "-162px", right: "12px" }} - /> + isMulti ? ( + } + icon={} + sx={{ position: "absolute", top: "-162px", right: "12px" }} + /> + ) : ( + } + icon={} + sx={{ position: "absolute", top: "-162px", right: "12px" }} + /> + ) } label={ - - {variant.answer} - + own ? ( + + ) : ( + + {variant.answer} + + ) } /> diff --git a/lib/components/ViewPublicationPage/questions/Emoji/index.tsx b/lib/components/ViewPublicationPage/questions/Emoji/index.tsx index e179290..fc51532 100644 --- a/lib/components/ViewPublicationPage/questions/Emoji/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Emoji/index.tsx @@ -3,6 +3,7 @@ import { Box, RadioGroup, Typography, useTheme } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill"; import { EmojiVariant } from "./EmojiVariant"; +import moment from "moment"; polyfillCountryFlagEmojis(); @@ -16,6 +17,8 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => { const theme = useTheme(); const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {}; + if (moment.isMoment(answer)) throw new Error("Answer is Moment in Variant question"); + return ( { }} > - {currentQuestion.content.variants.map((variant, index) => ( - - ))} + {currentQuestion.content.variants + .filter((v) => { + if (!v.isOwn) return true; + return v.isOwn && currentQuestion.content.own; + }) + .map((variant, index) => ( + + ))} diff --git a/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx b/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx index 986ad34..39845ea 100644 --- a/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx @@ -1,7 +1,7 @@ import { CheckboxIcon } from "@/assets/icons/Checkbox"; import type { QuestionVariant } from "@/model/questionTypes/shared"; import { useQuizSettings } from "@contexts/QuizDataContext"; -import { Box, Checkbox, FormControlLabel, Radio, useTheme } from "@mui/material"; +import { Box, Checkbox, FormControlLabel, Input, Radio, TextareaAutosize, useTheme } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import RadioCheck from "@ui_kit/RadioCheck"; import RadioIcon from "@ui_kit/RadioIcon"; @@ -12,11 +12,75 @@ type ImagesProps = { questionId: string; variant: QuestionVariant; index: number; - isMulti: boolean; answer: string | string[] | undefined; + isMulti: boolean; + own: boolean; + questionLargeCheck: boolean; + ownPlaceholder: string; }; -export const ImageVariant = ({ questionId, answer, isMulti, variant, index }: ImagesProps) => { +interface OwnInputProps { + questionId: string; + variant: QuestionVariant; + largeCheck: boolean; + ownPlaceholder: string; +} +const OwnInput = ({ questionId, variant, largeCheck, ownPlaceholder }: OwnInputProps) => { + const theme = useTheme(); + const ownVariants = useQuizViewStore((state) => state.ownVariants); + const { updateOwnVariant } = useQuizViewStore((state) => state); + + const ownAnswer = ownVariants[ownVariants.findIndex((v) => v.id === variant.id)]?.variant.answer || ""; + + return largeCheck ? ( + + ) => e.stopPropagation()} + onChange={(e: React.ChangeEvent) => { + updateOwnVariant(variant.id, e.target.value); + }} + /> + + ) : ( + ) => e.stopPropagation()} + onChange={(e: React.ChangeEvent) => { + updateOwnVariant(variant.id, e.target.value); + }} + /> + ); +}; + +export const ImageVariant = ({ + questionId, + answer, + isMulti, + variant, + index, + own, + questionLargeCheck, + ownPlaceholder, +}: ImagesProps) => { const { settings } = useQuizSettings(); const { deleteAnswer, updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); @@ -92,6 +156,7 @@ export const ImageVariant = ({ questionId, answer, isMulti, variant, index }: Im justifyContent: "center", position: "relative", height: "80px", + overflow: "auto", "& .MuiFormControlLabel-label": { wordBreak: "break-word", height: variant.answer.length <= 60 ? undefined : "60px", @@ -130,7 +195,18 @@ export const ImageVariant = ({ questionId, answer, isMulti, variant, index }: Im /> ) } - label={variant.answer} + label={ + own ? ( + + ) : ( + variant.answer + ) + } /> ); diff --git a/lib/components/ViewPublicationPage/questions/Images/index.tsx b/lib/components/ViewPublicationPage/questions/Images/index.tsx index 29c327e..efded4a 100644 --- a/lib/components/ViewPublicationPage/questions/Images/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Images/index.tsx @@ -16,8 +16,6 @@ export const Images = ({ currentQuestion }: ImagesProps) => { const isTablet = useRootContainerSize() < 1000; const isMobile = useRootContainerSize() < 500; - console.log(currentQuestion); - if (moment.isMoment(answer)) throw new Error("Answer is Moment in Variant question"); return ( @@ -48,16 +46,24 @@ export const Images = ({ currentQuestion }: ImagesProps) => { width: "100%", }} > - {currentQuestion.content.variants.map((variant, index) => ( - - ))} + {currentQuestion.content.variants + .filter((v) => { + if (!v.isOwn) return true; + return v.isOwn && currentQuestion.content.own; + }) + .map((variant, index) => ( + + ))} diff --git a/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx b/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx index b03de56..817628e 100644 --- a/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx +++ b/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx @@ -25,7 +25,7 @@ interface OwnInputProps { largeCheck: boolean; ownPlaceholder: string; } -const OwnInput = ({ questionId, variant, largeCheck }: OwnInputProps) => { +const OwnInput = ({ questionId, variant, largeCheck, ownPlaceholder }: OwnInputProps) => { const theme = useTheme(); const ownVariants = useQuizViewStore((state) => state.ownVariants); const { updateOwnVariant } = useQuizViewStore((state) => state); @@ -34,7 +34,7 @@ const OwnInput = ({ questionId, variant, largeCheck }: OwnInputProps) => { return largeCheck ? ( { /> ) : ( { diff --git a/lib/components/ViewPublicationPage/questions/Variant/index.tsx b/lib/components/ViewPublicationPage/questions/Variant/index.tsx index 4f506be..a848e00 100644 --- a/lib/components/ViewPublicationPage/questions/Variant/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Variant/index.tsx @@ -86,7 +86,7 @@ export const Variant = ({ currentQuestion }: VariantProps) => { variant={variant} answer={answer} index={index} - own={variant.isOwn} + own={Boolean(variant.isOwn)} questionLargeCheck={currentQuestion.content.largeCheck} ownPlaceholder={currentQuestion.content?.ownPlaceholder || ""} /> diff --git a/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx b/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx index cb804dc..c70ea6c 100644 --- a/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx @@ -26,7 +26,7 @@ interface OwnInputProps { largeCheck: boolean; ownPlaceholder: string; } -const OwnInput = ({ questionId, variant, largeCheck }: OwnInputProps) => { +const OwnInput = ({ questionId, variant, largeCheck, ownPlaceholder }: OwnInputProps) => { const theme = useTheme(); const ownVariants = useQuizViewStore((state) => state.ownVariants); const { updateOwnVariant } = useQuizViewStore((state) => state); @@ -35,7 +35,7 @@ const OwnInput = ({ questionId, variant, largeCheck }: OwnInputProps) => { return largeCheck ? ( { /> ) : ( { const ownVariant = ownVariants.find((variant) => variant.id === currentQuestion.id); const variant = currentQuestion.content.variants.find(({ id }) => answer === id); - console.log(variant); - useEffect(() => { if (!ownVariant) { updateOwnVariant(currentQuestion.id, ""); diff --git a/lib/stores/quizView.ts b/lib/stores/quizView.ts index 06078ae..db71ba7 100644 --- a/lib/stores/quizView.ts +++ b/lib/stores/quizView.ts @@ -95,7 +95,7 @@ export const createQuizViewStore = () => (state) => { const index = state.ownVariants.findIndex((variant) => variant.id === id); - if (index < 0 || !index) { + if (index < 0) { state.ownVariants.push({ id, variant: { diff --git a/lib/utils/sendQuestionAnswer.ts b/lib/utils/sendQuestionAnswer.ts index d7f012b..1a5aaeb 100644 --- a/lib/utils/sendQuestionAnswer.ts +++ b/lib/utils/sendQuestionAnswer.ts @@ -28,6 +28,37 @@ export function sendQuestionAnswer( }); } case "emoji": { + if (question.content.multi) { + const answer = questionAnswer.answer; + const ownVariant = Array.isArray(answer) + ? ownVariants[ownVariants.findIndex((variant) => answer.some((a: string) => a === variant.id))]?.variant || "" + : ownVariants[ownVariants.findIndex((variant) => variant.id === questionAnswer.answer)]?.variant || ""; + + if (moment.isMoment(answer)) throw new Error("Answer is Moment in Variant question"); + + //Оставляем только выбранные варианты + const selectedVariants = question.content.variants.filter((v) => answer.includes(v.id)); + + let answerString = ``; + selectedVariants.forEach((e) => { + if (e.isOwn) { + if (question.content.own && selectedVariants.some((v) => v.isOwn)) { + answerString += `\`${e.extendedText} ${ownVariant?.answer ?? ""}\`,`; + } + } else { + answerString += `\`${e.extendedText} ${e.answer ?? ""}\`,`; + } + }); + + answerString = answerString.slice(0, -1); + + return sendAnswer({ + questionId: question.id, + body: answerString, + qid: quizId, + }); + } + const variant = question.content.variants.find((v) => v.id === questionAnswer.answer); if (!variant) throw new Error(`Cannot find variant with id ${questionAnswer.answer} in question ${question.id}`); @@ -43,19 +74,25 @@ export function sendQuestionAnswer( case "images": { if (question.content.multi) { const answer = questionAnswer.answer; - if (!Array.isArray(answer)) throw new Error("Cannot send answer in select question"); + const ownAnswer = Array.isArray(answer) + ? ownVariants[ownVariants.findIndex((variant) => answer.some((a: string) => a === variant.id))]?.variant + ?.answer || "" + : ownVariants[ownVariants.findIndex((variant) => variant.id === questionAnswer.answer)]?.variant?.answer || + ""; + + if (moment.isMoment(answer)) throw new Error("Answer is Moment in Variant question"); //Оставляем только выбранные варианты const selectedVariants = question.content.variants.filter((v) => answer.includes(v.id)); let answerString = ``; - selectedVariants.forEach((variant) => { - const body = JSON.stringify({ - Image: variant.extendedText, - Description: variant.answer, - }); - answerString += `\`${body}\`,`; + selectedVariants.forEach((e) => { + if (!e.isOwn) answerString += `\`${e.answer}\`,`; }); + + if (question.content.own && selectedVariants.some((v) => v.isOwn)) { + answerString += `\`${ownAnswer}\`,`; + } answerString = answerString.slice(0, -1); return sendAnswer({ @@ -133,8 +170,6 @@ export function sendQuestionAnswer( : ownVariants[ownVariants.findIndex((variant) => variant.id === questionAnswer.answer)]?.variant?.answer || ""; - if (!Array.isArray(answer)) throw new Error("Cannot send answer in select question"); - //Оставляем только выбранные варианты const selectedVariants = question.content.variants.filter((v) => answer.includes(v.id)); diff --git a/src/ CHANGELOG.md b/src/ CHANGELOG.md new file mode 100644 index 0000000..517627c --- /dev/null +++ b/src/ CHANGELOG.md @@ -0,0 +1 @@ +1.0.0 Добавлены фичи "мультиответ", "перенос строки в своём ответе", "свой ответ", "плейсхолдер своего ответа"