Merge branch 'staging' into 'main'

подправлена стартовая станица мобилки, автофокус на инпуте, отправка данных...

See merge request frontend/squzanswerer!83
This commit is contained in:
Mikhail 2024-02-21 18:42:46 +00:00
commit 41f1b57c9a
18 changed files with 5422 additions and 411 deletions

@ -160,7 +160,7 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
sx={{
width: isWide && !isMobile ? "100%" : isMobile ? undefined : "530px",
borderRadius: "4px",
height: "90vh",
height: "100%",
display: isWide && !isMobile ? "flex" : undefined,
}}
>

@ -1,4 +1,4 @@
import {Box, Link, useTheme} from "@mui/material";
import { Box, Link, useTheme } from "@mui/material";
import { Footer } from "./Footer";
import { Date } from "./questions/Date";
@ -15,13 +15,12 @@ import { Varimg } from "./questions/Varimg";
import type { RealTypedQuizQuestion } from "../../model/questionTypes/shared";
import { useQuizData } from "@contexts/QuizDataContext";
import { NameplateLogoFQ } from "@icons/NameplateLogoFQ";
import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
import { useQuizData } from "@contexts/QuizDataContext";
import { notReachable } from "@utils/notReachable";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import { ReactNode } from "react";
import { useRootContainerSize } from "../../contexts/RootContainerWidthContext";
type Props = {
currentQuestion: RealTypedQuizQuestion;
@ -38,12 +37,11 @@ export const Question = ({
}: Props) => {
const theme = useTheme();
const { settings } = useQuizData();
const isMobile = useRootContainerSize() < 650;
console.log(settings)
console.log(currentQuestionStepNumber)
return (
<Box sx={{
backgroundColor: theme.palette.background.default,
height: isMobile ? "100%" : "100vh"
height: "100%",
}}>
<Box sx={{
height: "calc(100% - 75px)",
@ -56,11 +54,11 @@ console.log(settings)
flexDirection: "column",
justifyContent: "space-between"
}}>
<QuestionByType key={currentQuestion.id} question={currentQuestion} />
<QuestionByType key={currentQuestion.id} question={currentQuestion} stepNumber={currentQuestionStepNumber} />
{quizThemes[settings.cfg.theme].isLight ? (
<Link target={"_blank"} href={"https://quiz.pena.digital"}>
<NameplateLogoFQ style={{ fontSize: "34px", width: "200px", height: "auto" }} />
</Link>
<Link target={"_blank"} href={"https://quiz.pena.digital"}>
<NameplateLogoFQ style={{ fontSize: "34px", width: "200px", height: "auto" }} />
</Link>
) : (
<Link target={"_blank"} href={"https://quiz.pena.digital"}>
<NameplateLogoFQDark style={{ fontSize: "34px", width: "200px", height: "auto" }} />
@ -77,15 +75,16 @@ console.log(settings)
);
};
function QuestionByType({ question }: {
function QuestionByType({ question, stepNumber }: {
question: RealTypedQuizQuestion;
stepNumber: number | null;
}) {
switch (question.type) {
case "variant": return <Variant currentQuestion={question} />;
case "images": return <Images currentQuestion={question} />;
case "varimg": return <Varimg currentQuestion={question} />;
case "emoji": return <Emoji currentQuestion={question} />;
case "text": return <Text currentQuestion={question} />;
case "text": return <Text currentQuestion={question} stepNumber={stepNumber}/>;
case "select": return <Select currentQuestion={question} />;
case "date": return <Date currentQuestion={question} />;
case "number": return <Number currentQuestion={question} />;

@ -23,6 +23,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const { settings } = useQuizData();
const spec = settings.cfg.spec
return (
<Box
@ -32,7 +33,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
alignItems: "center",
justifyContent: "space-between",
height: "100%",
width: "100vw",
width: "100%",
pt: "28px",
overflow: "auto",
}}
@ -63,8 +64,8 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
component="img"
src={resultQuestion.content.back}
sx={{
width: isMobile ? "100%" : "490px",
height: isMobile ? "100%" : "280px",
width: spec ? "100%" : isMobile ? "100%" : "490px",
height: spec ? "auto" : isMobile ? "100%" : "280px",
}}
></Box>
)

@ -21,7 +21,7 @@ export const StartPageViewPublication = () => {
const handleCopyNumber = () => {
navigator.clipboard.writeText(settings.cfg.info.phonenumber);
};
console.log(settings.cfg.startpage.background.type)
console.log(settings.cfg.startpage.background.type);
const background =
settings.cfg.startpage.background.type === "image" ? (
@ -45,9 +45,7 @@ export const StartPageViewPublication = () => {
width:
settings.cfg.startpageType === "centered"
? "550px"
: settings.cfg.startpageType === "expanded"
? "100vw"
: "100%",
: "100%",
height:
settings.cfg.startpageType === "centered"
? "275px"
@ -304,7 +302,7 @@ function QuizPreviewLayoutByType({
justifyContent: "space-between",
alignItems: "flex-start",
p: "25px",
height: "80%",
height: "100%",
overflowY: "auto",
overflowX: "hidden"
}}
@ -345,7 +343,7 @@ function QuizPreviewLayoutByType({
<StartPageMobile />
) : (
<Box
id="pain"
id="pain"
sx={{
display: "flex",
flexDirection: alignType === "left" ? (isMobile ? "column-reverse" : "row") : "row-reverse",

@ -25,7 +25,7 @@ export const Date = ({ currentQuestion }: DateProps) => {
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const currentAnswer = moment(answer) || moment();
const [readySend, setReadySend] = useState(true)
const [isSending, setIsSending] = useState<boolean>(false);
return (
<Box>
@ -53,29 +53,26 @@ export const Date = ({ currentQuestion }: DateProps) => {
}}
value={currentAnswer}
onChange={async (date) => {
if (readySend) {
setReadySend(false)
if (!date) {
return;
}
if (isSending || !date) return;
try {
await sendAnswer({
questionId: currentQuestion.id,
body: moment(date).format("YYYY.MM.DD"),
qid: quizId,
});
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: moment(date).format("YYYY.MM.DD"),
qid: quizId,
});
updateAnswer(
currentQuestion.id,
date,
0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setReadySend(true)
updateAnswer(
currentQuestion.id,
date,
0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}}
slotProps={{
openPickerButton: {

@ -36,7 +36,7 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => {
answers.find(
({ questionId }) => questionId === currentQuestion.id
) ?? {};
const [readySend, setReadySend] = useState(true)
const [isSending, setIsSending] = useState<boolean>(false);
return (
<Box>
@ -70,6 +70,7 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => {
{currentQuestion.content.variants.map((variant, index) => (
<FormControl
key={variant.id}
disabled={isSending}
sx={{
borderRadius: "12px",
border: `1px solid`,
@ -130,45 +131,39 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => {
value={index}
onClick={async (event) => {
event.preventDefault();
if (readySend) {
setReadySend(false)
try {
if (isSending) return;
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].extendedText + " " + currentQuestion.content.variants[index].answer,
qid: quizId,
});
updateAnswer(
currentQuestion.id,
currentQuestion.content.variants[index].id,
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
if (answer === currentQuestion.content.variants[index].id) {
deleteAnswer(currentQuestion.id);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].extendedText + " " + currentQuestion.content.variants[index].answer,
body: "",
qid: quizId,
});
updateAnswer(
currentQuestion.id,
currentQuestion.content.variants[index].id,
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
if (answer === currentQuestion.content.variants[index].id) {
deleteAnswer(currentQuestion.id);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
}
setReadySend(true)
}
setIsSending(false);
}}
control={

@ -16,6 +16,7 @@ import { enqueueSnackbar } from "notistack";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
import type { QuizQuestionImages } from "../../../model/questionTypes/images";
import { useQuizData } from "@contexts/QuizDataContext";
import { useState } from "react";
type ImagesProps = {
currentQuestion: QuizQuestionImages;
@ -26,6 +27,7 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
const { answers } = useQuizViewStore();
const theme = useTheme();
const answer = answers.find(({ questionId }) => questionId === currentQuestion.id)?.answer;
const [isSending, setIsSending] = useState<boolean>(false);
const isTablet = useRootContainerSize() < 1000;
const isMobile = useRootContainerSize() < 500;
@ -65,43 +67,44 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
borderRadius: "5px",
border: `1px solid`,
borderColor: answer === variant.id ? theme.palette.primary.main : "#9A9AAF",
transition: "opacity 0.5s ease",
opacity: isSending ? 0.5 : 1,
pointerEvents: isSending ? "none" : "auto",
}}
onClick={async (event) => {
event.preventDefault();
if (isSending) return;
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: `${currentQuestion.content.variants[index].answer} <img style="width:100%; max-width:250px; max-height:250px" src="${currentQuestion.content.variants[index].extendedText}"/>`,
qid: quizId,
});
updateAnswer(
currentQuestion.id,
currentQuestion.content.variants[index].id,
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
if (answer === currentQuestion.content.variants[index].id) {
deleteAnswer(currentQuestion.id);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
}
setIsSending(false);
}}
>
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
@ -159,5 +162,4 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
</RadioGroup>
</Box>
);
};

@ -32,6 +32,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
useState<string>("100000000000");
const theme = useTheme();
const { answers } = useQuizViewStore();
const [isSending, setIsSending] = useState<boolean>(false);
const isMobile = useRootContainerSize() < 650;
const [minBorder, maxBorder] = currentQuestion.content.range
@ -40,8 +41,13 @@ export const Number = ({ currentQuestion }: NumberProps) => {
const min = minBorder < maxBorder ? minBorder : maxBorder;
const max = minBorder < maxBorder ? maxBorder : minBorder;
const reversed = minBorder > maxBorder;
useEffect(() => {
console.log("reversed:", reversed)
}, [reversed])
const sendAnswerToBackend = async (value: string, noUpdate = false) => {
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
@ -55,6 +61,8 @@ export const Number = ({ currentQuestion }: NumberProps) => {
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
};
const updateValueDebounced = useDebouncedCallback(async (value: string) => {
@ -353,7 +361,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{wordBreak: "break-word"}}>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>
{currentQuestion.title}
</Typography>
<Box

@ -43,7 +43,7 @@ export const Page = ({ currentQuestion }: PageProps) => {
containerSX={{
width: "100%",
height: "calc(100% - 270px)",
maxHeight: "80vh",
maxHeight: "80%",
objectFit: "contain",
}}
videoUrl={currentQuestion.content.video}

@ -20,6 +20,7 @@ import { enqueueSnackbar } from "notistack";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
import { useQuizData } from "@contexts/QuizDataContext";
import { useState } from "react";
type RatingProps = {
currentQuestion: QuizQuestionRating;
@ -61,6 +62,7 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
const { answers } = useQuizViewStore();
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const [isSending, setIsSending] = useState<boolean>(false);
const { answer } =
answers.find(
({ questionId }) => questionId === currentQuestion.id
@ -89,10 +91,10 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
}}
>
<RatingComponent
disabled={isSending}
value={Number(answer || 0)}
onChange={async (_, value) => {
setIsSending(true);
try {
await sendAnswer({
@ -106,12 +108,15 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}}
sx={{
height: "50px",
gap: isMobile ? undefined : "15px",
justifyContent: isMobile ? "space-between" : undefined,
width: isMobile ? "100%" : undefined
width: isMobile ? "100%" : undefined,
transition: "opacity 0.5s ease",
}}
max={currentQuestion.content.steps}
icon={form?.icon(theme.palette.primary.main)}

@ -8,6 +8,7 @@ import { sendAnswer } from "@api/quizRelase";
import { enqueueSnackbar } from "notistack";
import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
import { useQuizData } from "@contexts/QuizDataContext";
import { useState } from "react";
type SelectProps = {
currentQuestion: QuizQuestionSelect;
@ -16,6 +17,7 @@ type SelectProps = {
export const Select = ({ currentQuestion }: SelectProps) => {
const theme = useTheme();
const { quizId } = useQuizData();
const [isSending, setIsSending] = useState<boolean>(false);
const { answers } = useQuizViewStore();
const { answer } =
answers.find(
@ -24,7 +26,7 @@ export const Select = ({ currentQuestion }: SelectProps) => {
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{wordBreak: "break-word"}}>{currentQuestion.title}</Typography>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
<Box
sx={{
display: "flex",
@ -34,11 +36,13 @@ export const Select = ({ currentQuestion }: SelectProps) => {
}}
>
<SelectComponent
disabled={isSending}
placeholder={currentQuestion.content.default}
activeItemIndex={answer ? Number(answer) : -1}
items={currentQuestion.content.variants.map(({ answer }) => answer)}
colorMain={theme.palette.primary.main}
onChange={async (_, value) => {
setIsSending(true);
if (value < 0) {
deleteAnswer(currentQuestion.id);
try {
@ -52,7 +56,7 @@ export const Select = ({ currentQuestion }: SelectProps) => {
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
return;
return setIsSending(false);
}
try {
@ -69,7 +73,7 @@ export const Select = ({ currentQuestion }: SelectProps) => {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}}
/>
</Box>

@ -1,43 +1,102 @@
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import {Box, TextField, Typography, useTheme} from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField";
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
import { sendAnswer } from "@api/quizRelase";
import { useQuizData } from "@contexts/QuizDataContext";
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
import { enqueueSnackbar } from "notistack";
import {ChangeEvent, useEffect, useState} from "react";
import { useDebouncedCallback } from "use-debounce";
import type { QuizQuestionText } from "../../../model/questionTypes/text";
import { useQuizData } from "@contexts/QuizDataContext";
type TextProps = {
currentQuestion: QuizQuestionText;
stepNumber: number | null;
};
export const Text = ({ currentQuestion }: TextProps) => {
const Orientation = [
{horizontal: true},
{horizontal: false},
{horizontal: true},
{horizontal: true},
{horizontal: false},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: false},
{horizontal: true},
{horizontal: false},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: false},
{horizontal: false},
{horizontal: true},
{horizontal: true},
{horizontal: true},
{horizontal: true},
]
export const Text = ({ currentQuestion, stepNumber }: TextProps) => {
const theme = useTheme();
const { settings } = useQuizData();
const spec = settings.cfg.spec
const { quizId } = useQuizData();
const { answers } = useQuizViewStore();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const isMobile = useRootContainerSize() < 650;
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
const [isSending, setIsSending] = useState<boolean>(false);
const inputHC = useDebouncedCallback(async (text) => {
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: text,
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}, 400);
return (
useEffect(
() => () => {
inputHC.flush();
},
[inputHC]
);
switch (spec) {
case true:
return <TextSpecial currentQuestion={currentQuestion} answer={answer} inputHC={inputHC} stepNumber={stepNumber}/>;
case undefined:
return <TextNormal currentQuestion={currentQuestion} answer={answer} inputHC={inputHC} />;
default:
return <TextNormal currentQuestion={currentQuestion} answer={answer} inputHC={inputHC} />;
}
};
interface Props {
currentQuestion: QuizQuestionText;
answer: any,
inputHC: (a: string) => void;
stepNumber?: number | null;
}
const TextNormal = ({currentQuestion, answer, inputHC}: Props) => {
const isMobile = useRootContainerSize() < 650;
const theme = useTheme();
return(
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{wordBreak: "break-word"}}>{currentQuestion.title}</Typography>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
<Box
sx={{
display: "flex",
@ -47,21 +106,20 @@ export const Text = ({ currentQuestion }: TextProps) => {
alignItems: "center"
}}
>
<CustomTextField
placeholder={currentQuestion.content.placeholder}
//@ts-ignore
value={answer || ""}
onChange={async ({ target }) => {
updateAnswer(currentQuestion.id, target.value, 0);
inputHC(target.value);
}
}
sx={{
"&:focus-visible": {
borderColor: theme.palette.primary.main
}
}}
/>
<CustomTextField
placeholder={currentQuestion.content.placeholder}
// @ts-ignore
value={answer || ""}
onChange={async ({ target }) => {
updateAnswer(currentQuestion.id, target.value, 0);
inputHC(target.value);
}}
sx={{
"&:focus-visible": {
borderColor: theme.palette.primary.main
}
}}
/>
{currentQuestion.content.back && currentQuestion.content.back !== " " && (
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px", margin: "15px" }}>
<img
@ -74,5 +132,71 @@ export const Text = ({ currentQuestion }: TextProps) => {
)}
</Box>
</Box>
);
)
};
const TextSpecial = ({currentQuestion, answer, inputHC, stepNumber}: Props) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const isHorizontal = Orientation[Number(stepNumber) -1].horizontal
return(
<Box sx={{display: "flex", flexDirection: isMobile? "column" : undefined, alignItems: isMobile ? "center" : undefined,}}>
<Box
sx={{
display: "flex",
width: "100%",
marginTop: "20px",
flexDirection: "column",
alignItems: "center",
gap: "20px"
}}
>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
{isHorizontal && currentQuestion.content.back && currentQuestion.content.back !== " " && (
<Box sx={{margin: "30px", width: "50vw", maxHeight: "550px" }}>
<img
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
)}
{
//@ts-ignore
(<TextField
autoFocus={true}
multiline
maxRows={4}
placeholder={currentQuestion.content.placeholder}
//@ts-ignore
value={answer || ""}
onChange={async ({ target }:ChangeEvent<HTMLInputElement>) => {
updateAnswer(currentQuestion.id, target.value, 0);
inputHC(target.value);
}
}
inputProps={{maxLength:400}}
sx={{
width: "100%",
"&:focus-visible": {
borderColor: theme.palette.primary.main
}
}}
/>)
}
</Box>
{!isHorizontal && currentQuestion.content.back && currentQuestion.content.back !== " " && (
<Box sx={{margin: "15px", width: "40vw" }}>
<img
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
)}
</Box>
)
}

@ -38,16 +38,6 @@ type VariantProps = {
currentQuestion: QuizQuestionVariant;
};
type VariantItemProps = {
currentQuestion: QuizQuestionVariant;
variant: QuestionVariant;
answer: string | string[] | undefined;
index: number;
own?: boolean;
readySend: boolean;
setReadySend: (a: boolean) => void
};
export const Variant = ({ currentQuestion }: VariantProps) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
@ -60,7 +50,7 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
(variant) => variant.id === currentQuestion.id
);
const [readySend, setReadySend] = useState(true)
const [isSending, setIsSending] = useState(false);
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
@ -109,8 +99,8 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
// @ts-ignore
answer={answer}
index={index}
readySend={readySend}
setReadySend={setReadySend}
isSending={isSending}
setIsSending={setIsSending}
/>
))}
{currentQuestion.content.own && ownVariant && (
@ -121,8 +111,8 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
// @ts-ignore
answer={answer}
index={currentQuestion.content.variants.length + 2}
readySend={readySend}
setReadySend={setReadySend}
isSending={isSending}
setIsSending={setIsSending}
/>
)}
</Box>
@ -148,15 +138,24 @@ const VariantItem = ({
answer,
index,
own = false,
readySend,
setReadySend
}: VariantItemProps) => {
isSending,
setIsSending,
}: {
currentQuestion: QuizQuestionVariant;
variant: QuestionVariant;
answer: string | string[] | undefined;
index: number;
own?: boolean;
isSending: boolean;
setIsSending: (a: boolean) => void;
}) => {
const theme = useTheme();
const { settings, quizId } = useQuizData();
return (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
margin: "0",
borderRadius: "12px",
@ -205,74 +204,75 @@ const VariantItem = ({
label={own ? <TextField label="Другое..." /> : variant.answer}
onClick={async (event) => {
event.preventDefault();
if (readySend) {
setReadySend(false)
const variantId = currentQuestion.content.variants[index].id;
console.log(answer);
if (isSending) return;
if (currentQuestion.content.multi) {
const currentAnswer = typeof answer !== "string" ? answer || [] : [];
setIsSending(true);
const variantId = currentQuestion.content.variants[index].id;
console.log(answer);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId],
qid: quizId,
});
updateAnswer(
currentQuestion.id,
currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId],
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
return;
}
if (currentQuestion.content.multi) {
const currentAnswer = typeof answer !== "string" ? answer || [] : [];
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].answer,
body: currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId],
qid: quizId,
});
updateAnswer(currentQuestion.id, variantId,
answer === variantId ? 0
:
currentQuestion.content.variants[index].points || 0
updateAnswer(
currentQuestion.id,
currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId],
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
if (answer === variantId) {
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
setReadySend(true)
setIsSending(false);
return;
}
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].answer,
qid: quizId,
});
updateAnswer(currentQuestion.id, variantId,
answer === variantId ? 0
:
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
if (answer === variantId) {
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
setIsSending(false);
}}
/>
);

@ -18,6 +18,7 @@ import { quizThemes } from "@utils/themes/Publication/themePublication";
import { enqueueSnackbar } from "notistack";
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
import { useState } from "react";
type VarimgProps = {
currentQuestion: QuizQuestionVarImg;
@ -28,6 +29,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
const { answers } = useQuizViewStore();
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const [isSending, setIsSending] = useState<boolean>(false);
const { answer } =
answers.find(
@ -39,7 +41,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{wordBreak: "break-word"}}>{currentQuestion.title}</Typography>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
<Box sx={{
display: "flex",
marginTop: "20px",
@ -66,6 +68,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
{currentQuestion.content.variants.map((variant, index) => (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
marginBottom: "15px",
borderRadius: "5px",
@ -88,14 +91,13 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#b8babf",
}
}
},
}}
value={index}
onClick={async (event) => {
event.preventDefault();
setIsSending(true);
try {
await sendAnswer({
@ -129,6 +131,8 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
}
deleteAnswer(currentQuestion.id);
}
setIsSending(false);
}}
control={
<Radio checkedIcon={<RadioCheck color={theme.palette.primary.main} />} icon={<RadioIcon />} />
@ -165,20 +169,20 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
) : (
<BlankImage />
)
) : currentQuestion.content.back !== " "
&& currentQuestion.content.back !== null
&& currentQuestion.content.back.length > 0
? (
<img
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
) : (currentQuestion.content.replText !== " " && currentQuestion.content.replText.length > 0) ? currentQuestion.content.replText : variant?.extendedText || isMobile ? (
"Выберите вариант ответа ниже"
) : (
"Выберите вариант ответа слева"
)}
) : currentQuestion.content.back !== " "
&& currentQuestion.content.back !== null
&& currentQuestion.content.back.length > 0
? (
<img
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
) : (currentQuestion.content.replText !== " " && currentQuestion.content.replText.length > 0) ? currentQuestion.content.replText : variant?.extendedText || isMobile ? (
"Выберите вариант ответа ниже"
) : (
"Выберите вариант ответа слева"
)}
</Box>
{/* )} */}

@ -20,6 +20,7 @@ type SelectProps = {
colorMain?: string;
colorPlaceholder?: string;
placeholder?: string;
disabled?: boolean;
};
export const Select = ({
@ -31,6 +32,7 @@ export const Select = ({
placeholder = "",
colorMain = "#7E2AEA",
colorPlaceholder = "#9A9AAF",
disabled = false,
}: SelectProps) => {
const [activeItem, setActiveItem] = useState<number>(
empty ? -1 : activeItemIndex
@ -57,6 +59,7 @@ export const Select = ({
return (
<FormControl
disabled={disabled}
fullWidth
size="small"
sx={{ width: "100%", height: "48px", ...sx }}

@ -48,6 +48,7 @@ export type QuizSettings = {
};
export interface QuizConfig {
spec: undefined | true,
type: QuizType;
noStartPage: boolean;
startpageType: QuizStartpageType;

5290
pub.js

File diff suppressed because one or more lines are too long

@ -7,7 +7,7 @@ import QuizAnswerer from "../lib/components/QuizAnswerer";
import { ApologyPage } from "../lib/components/ViewPublicationPage/ApologyPage";
// const defaultQuizId = "45ef7f9c-784d-4e58-badb-f6b337f08ba0"; // branching
const defaultQuizId = "cde381db-8ccb-402c-b55f-2c814be9bf25"; //looooong header
const defaultQuizId = "26f2e98b-06ac-4e6c-b82e-0793e2768310"; //looooong header
// const defaultQuizId = "ad7f5a87-b833-4f5b-854e-453706ed655c"; // linear
export default function App() {