add variant disabled states when sending answer

This commit is contained in:
nflnkr 2024-02-19 17:09:27 +03:00
parent 1a488e2731
commit 437713aabd
10 changed files with 176 additions and 156 deletions

@ -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

@ -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>

@ -9,6 +9,7 @@ import { enqueueSnackbar } from "notistack";
import { useDebouncedCallback } from "use-debounce";
import type { QuizQuestionText } from "../../../model/questionTypes/text";
import { useQuizData } from "@contexts/QuizDataContext";
import { useState } from "react";
type TextProps = {
currentQuestion: QuizQuestionText;
@ -20,24 +21,25 @@ export const Text = ({ currentQuestion }: TextProps) => {
const { answers } = useQuizViewStore();
const isMobile = useMediaQuery(theme.breakpoints.down(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 (
<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",

@ -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 }}