feat: design logic

This commit is contained in:
IlyaDoronin 2024-03-04 19:40:53 +03:00
parent 284472c5bb
commit 69ea201ddc
14 changed files with 1719 additions and 1328 deletions

@ -1,6 +1,9 @@
import { useQuizData } from "@contexts/QuizDataContext";
import { Box, Typography, useTheme } from "@mui/material";
import { ReactNode } from "react";
import { Box, Typography, useTheme } from "@mui/material";
import { useQuizData } from "@contexts/QuizDataContext";
import Stepper from "@ui_kit/Stepper";
type FooterProps = {
stepNumber: number | null;
@ -10,8 +13,10 @@ type FooterProps = {
export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
const theme = useTheme();
const { questions } = useQuizData();
console.log(questions);
const { questions, settings } = useQuizData();
const questionsAmount = questions.filter(
({ type }) => type !== "result"
).length;
return (
<Box
@ -21,13 +26,16 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
borderTop: `1px solid ${theme.palette.grey[400]}`,
height: "75px",
display: "flex",
background: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: "transparent",
}}
>
<Box
sx={{
width: "100%",
maxWidth: "1000px",
padding: "0 10px",
maxWidth: "1410px",
padding: "10px",
margin: "0 auto",
display: "flex",
alignItems: "center",
@ -40,35 +48,11 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
{/* <NameplateLogoFQDark style={{ fontSize: "34px", width:"200px", height:"auto" }} />*/}
{/*)}*/}
{stepNumber !== null && (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
marginRight: "auto",
color: theme.palette.text.primary,
}}
>
<Typography>Шаг</Typography>
<Typography
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
fontWeight: "bold",
borderRadius: "50%",
width: "30px",
height: "30px",
color: "#FFF",
background: theme.palette.primary.main,
}}
>
{stepNumber}
</Typography>
<Typography>Из</Typography>
<Typography sx={{ fontWeight: "bold" }}>
{questions.filter((q) => q.type !== "result").length}
<Box sx={{ flexGrow: 1 }}>
<Typography sx={{ color: theme.palette.text.primary }}>
Вопрос {stepNumber} из {questionsAmount}
</Typography>
<Stepper activeStep={stepNumber} steps={questionsAmount} />
</Box>
)}

@ -33,7 +33,7 @@ import Desgin9 from "@icons/designs/design9.jpg";
import Desgin10 from "@icons/designs/design10.jpg";
import type { ReactNode } from "react";
import type { Design } from "@model/settingsData";
import type { QuizTheme } from "@model/settingsData";
type Props = {
currentQuestion: RealTypedQuizQuestion;
@ -42,18 +42,28 @@ type Props = {
prevButton: ReactNode;
};
export const DESIGN_LIST: Record<Design, string> = {
"": "",
design1: Desgin1,
design2: Desgin2,
design3: Desgin3,
design4: Desgin4,
design5: Desgin5,
design6: Desgin6,
design7: Desgin7,
design8: Desgin8,
design9: Desgin9,
design10: Desgin10,
export const DESIGN_LIST: Record<QuizTheme, string> = {
Design1: Desgin1,
Design2: Desgin2,
Design3: Desgin3,
Design4: Desgin4,
Design5: Desgin5,
Design6: Desgin6,
Design7: Desgin7,
Design8: Desgin8,
Design9: Desgin9,
Design10: Desgin10,
StandardTheme: "",
StandardDarkTheme: "",
PinkTheme: "",
PinkDarkTheme: "",
BlackWhiteTheme: "",
OliveTheme: "",
YellowTheme: "",
GoldDarkTheme: "",
PurpleTheme: "",
BlueTheme: "",
BlueDarkTheme: "",
};
export const Question = ({
@ -64,19 +74,20 @@ export const Question = ({
}: Props) => {
const theme = useTheme();
const { settings } = useQuizData();
const design = DESIGN_LIST[settings.cfg.design];
return (
<Box
sx={{
backgroundPosition: "center",
backgroundSize: "cover",
backgroundImage: `url(${design})`,
backgroundImage: settings.cfg.design
? `url(${DESIGN_LIST[settings.cfg.theme]})`
: null,
}}
>
<Box
sx={{
background: design
background: settings.cfg.design
? "linear-gradient(90deg,#272626, transparent)"
: theme.palette.background.default,
}}
@ -100,19 +111,21 @@ export const Question = ({
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"}>
<NameplateLogoFQDark
style={{ fontSize: "34px", width: "200px", height: "auto" }}
/>
</Link>
)}
<Box sx={{ marginLeft: "auto" }}>
{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"}>
<NameplateLogoFQDark
style={{ fontSize: "34px", width: "200px", height: "auto" }}
/>
</Link>
)}
</Box>
</Box>
<Footer
stepNumber={currentQuestionStepNumber}

@ -44,11 +44,13 @@ export const StartPageViewPublication = () => {
}
alt=""
style={{
display: "block",
width:
isMobile || settings.cfg.startpageType === "expanded"
? "100%"
: undefined,
height: "100%",
maxHeight: "100vh",
objectFit: "cover",
overflow: "hidden",
}}
@ -214,7 +216,7 @@ export const StartPageViewPublication = () => {
fontSize: "18px",
padding: "10px 30px",
width: "auto",
background: "#7E2AEA",
background: theme.palette.primary.main,
}}
onClick={() => setCurrentQuizStep("question")}
>
@ -248,7 +250,7 @@ export const StartPageViewPublication = () => {
<Typography
sx={{
fontSize: "16px",
color: "#7E2AEA",
color: theme.palette.primary.main,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
@ -262,19 +264,35 @@ export const StartPageViewPublication = () => {
{settings.cfg.info.clickable ? (
isMobileDevice ? (
<Link href={`tel:${settings.cfg.info.phonenumber}`}>
<Typography sx={{ fontSize: "16px" }}>
<Typography
sx={{
fontSize: "16px",
color: theme.palette.text.primary,
}}
>
{settings.cfg.info.phonenumber}
</Typography>
</Link>
) : (
<ButtonBase onClick={handleCopyNumber}>
<Typography sx={{ fontSize: "16px" }}>
<Typography
sx={{
fontSize: "16px",
color: theme.palette.text.primary,
}}
>
{settings.cfg.info.phonenumber}
</Typography>
</ButtonBase>
)
) : (
<Typography sx={{ fontSize: "16px", marginTop: "5px" }}>
<Typography
sx={{
fontSize: "16px",
marginTop: "5px",
color: theme.palette.text.primary,
}}
>
{settings.cfg.info.phonenumber}
</Typography>
)}

@ -61,7 +61,16 @@ export default function ViewPublicationPage() {
<Button
disabled={!isPreviousButtonEnabled}
variant="contained"
sx={{ fontSize: "16px", padding: "10px 15px" }}
sx={{
fontSize: "16px",
padding: "10px 15px",
color: "#FFFFFF",
border: "1px solid #9A9AAF",
background: "rgba(154,154,175, 0.2)",
"&:disabled": {
color: "#9A9AAF",
},
}}
onClick={moveToPrevQuestion}
>
{isMobileMini ? "←" : "← Назад"}

@ -14,97 +14,99 @@ import { useQuizData } from "@contexts/QuizDataContext";
import { useState } from "react";
type DateProps = {
currentQuestion: QuizQuestionDate;
currentQuestion: QuizQuestionDate;
};
export const Date = ({ currentQuestion }: DateProps) => {
const theme = useTheme();
const { settings, quizId } = useQuizData();
const { answers } = useQuizViewStore();
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const currentAnswer = moment(answer) || moment();
const [isSending, setIsSending] = useState<boolean>(false);
const theme = useTheme();
const { settings, quizId } = useQuizData();
const { answers } = useQuizViewStore();
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const currentAnswer = moment(answer) || moment();
const [isSending, setIsSending] = useState<boolean>(false);
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>
{currentQuestion.title}
</Typography>
<Box
return (
<Box>
<Typography
variant="h5"
color={theme.palette.text.primary}
sx={{ wordBreak: "break-word" }}
>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
}}
>
<DatePicker
slots={{
openPickerIcon: () => (
<CalendarIcon
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
"& path": { stroke: theme.palette.primary.main },
"& rect": { stroke: theme.palette.primary.main },
}}
>
<DatePicker
slots={{
openPickerIcon: () => (
<CalendarIcon
sx={{
"& path": { stroke: theme.palette.primary.main },
"& rect": { stroke: theme.palette.primary.main },
}}
/>
),
}}
value={currentAnswer}
onChange={async (date) => {
if (isSending || !date) return;
/>
),
}}
value={currentAnswer}
onChange={async (date) => {
if (isSending || !date) return;
setIsSending(true);
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("ответ не был засчитан");
}
updateAnswer(currentQuestion.id, date, 0);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}}
slotProps={{
openPickerButton: {
sx: {
p: 0,
},
"data-cy": "open-datepicker",
},
layout: {
sx: { backgroundColor: theme.palette.background.default },
},
}}
sx={{
"& .MuiInputBase-root": {
backgroundColor: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
borderRadius: "10px",
maxWidth: "250px",
pr: "22px",
"& input": {
py: "11px",
pl: "20px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
</Box>
</Box>
);
setIsSending(false);
}}
slotProps={{
openPickerButton: {
sx: {
p: 0,
},
"data-cy": "open-datepicker",
},
layout: {
sx: { backgroundColor: theme.palette.background.default },
},
}}
sx={{
"& .MuiInputBase-root": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
borderRadius: "10px",
maxWidth: "250px",
pr: "22px",
"& input": {
py: "11px",
pl: "20px",
lineHeight: "19px",
},
"& fieldset": {
borderColor: "#9A9AAF",
},
},
}}
/>
</Box>
</Box>
);
};

@ -189,7 +189,7 @@ export const File = ({ currentQuestion }: FileProps) => {
justifyContent: "flex-start",
alignItems: "center",
padding: "33px 44px 33px 55px",
backgroundColor: theme.palette.background.default,
backgroundColor: "#F2F3F7",
border: `1px solid ${isDropzoneHighlighted ? "red" : "#9A9AAF"}`,
borderRadius: "8px",
}}

@ -18,445 +18,458 @@ import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
import type { ChangeEvent, SyntheticEvent } from "react";
type NumberProps = {
currentQuestion: QuizQuestionNumber;
currentQuestion: QuizQuestionNumber;
};
export const Number = ({ currentQuestion }: NumberProps) => {
const { settings, quizId } = useQuizData();
const [inputValue, setInputValue] = useState<string>("0");
const [minRange, setMinRange] = useState<string>("0");
const [maxRange, setMaxRange] = useState<string>("100000000000");
const [reversedInputValue, setReversedInputValue] = useState<string>("0");
const [reversedMinRange, setReversedMinRange] = useState<string>("0");
const [reversedMaxRange, setReversedMaxRange] =
useState<string>("100000000000");
const theme = useTheme();
const { answers } = useQuizViewStore();
const [isSending, setIsSending] = useState<boolean>(false);
const { settings, quizId } = useQuizData();
const [inputValue, setInputValue] = useState<string>("0");
const [minRange, setMinRange] = useState<string>("0");
const [maxRange, setMaxRange] = useState<string>("100000000000");
const [reversedInputValue, setReversedInputValue] = useState<string>("0");
const [reversedMinRange, setReversedMinRange] = useState<string>("0");
const [reversedMaxRange, setReversedMaxRange] =
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
.split("—")
.map(window.Number);
const min = minBorder < maxBorder ? minBorder : maxBorder;
const max = minBorder < maxBorder ? maxBorder : minBorder;
const reversed = minBorder > maxBorder;
useEffect(() => {
console.log("reversed:", reversed)
}, [reversed])
const isMobile = useRootContainerSize() < 650;
const [minBorder, maxBorder] = currentQuestion.content.range
.split("—")
.map(window.Number);
const min = minBorder < maxBorder ? minBorder : maxBorder;
const max = minBorder < maxBorder ? maxBorder : minBorder;
const reversed = minBorder > maxBorder;
const sendAnswerToBackend = async (value: string, noUpdate = false) => {
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: value,
qid: quizId,
});
useEffect(() => {
console.log("reversed:", reversed);
}, [reversed]);
if (!noUpdate) {
updateAnswer(currentQuestion.id, value, 0);
}
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
const sendAnswerToBackend = async (value: string, noUpdate = false) => {
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: value,
qid: quizId,
});
setIsSending(false);
};
if (!noUpdate) {
updateAnswer(currentQuestion.id, value, 0);
}
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
const updateValueDebounced = useDebouncedCallback(async (value: string) => {
setIsSending(false);
};
const updateValueDebounced = useDebouncedCallback(async (value: string) => {
if (reversed) {
const newValue =
window.Number(value) < window.Number(min)
? String(min)
: window.Number(value) > window.Number(max)
? String(max)
: value;
setReversedInputValue(newValue);
updateAnswer(
currentQuestion.id,
String(max + min - window.Number(newValue)),
0
);
await sendAnswerToBackend(String(window.Number(newValue)), true);
return;
}
const newValue =
window.Number(value) < window.Number(minRange)
? minRange
: window.Number(value) > window.Number(maxRange)
? maxRange
: value;
setInputValue(newValue);
await sendAnswerToBackend(newValue);
}, 1000);
const updateMinRangeDebounced = useDebouncedCallback(
async (value: string, crowded = false) => {
if (reversed) {
const newMinRange = crowded
? window.Number(value.split("—")[1])
: max + min - window.Number(value.split("—")[0]) < min
? min
: max + min - window.Number(value.split("—")[0]);
const newMinValue =
window.Number(value.split("—")[0]) > max
? String(max)
: value.split("—")[0];
setReversedMinRange(
crowded ? String(max + min - window.Number(newMinValue)) : newMinValue
);
updateAnswer(
currentQuestion.id,
`${newMinRange}${value.split("—")[1]}`,
0
);
await sendAnswerToBackend(
`${newMinValue}${value.split("—")[1]}`,
true
);
return;
}
const newMinValue = crowded
? maxRange
: window.Number(value.split("—")[0]) < min
? String(min)
: value.split("—")[0];
setMinRange(newMinValue);
await sendAnswerToBackend(`${newMinValue}${value.split("—")[1]}`);
},
1000
);
const updateMaxRangeDebounced = useDebouncedCallback(
async (value: string, crowded = false) => {
if (reversed) {
const newMaxRange = crowded
? window.Number(value.split("—")[1])
: max + min - window.Number(value.split("—")[1]) > max
? max
: max + min - window.Number(value.split("—")[1]);
const newMaxValue =
window.Number(value.split("—")[1]) < min
? String(min)
: value.split("—")[1];
setReversedMaxRange(
crowded ? String(max + min - window.Number(newMaxValue)) : newMaxValue
);
updateAnswer(
currentQuestion.id,
`${value.split("—")[0]}${newMaxRange}`,
0
);
await sendAnswerToBackend(
`${value.split("—")[0]}${newMaxValue}`,
true
);
return;
}
const newMaxValue = crowded
? minRange
: window.Number(value.split("—")[1]) > max
? String(max)
: value.split("—")[1];
setMaxRange(newMaxValue);
await sendAnswerToBackend(`${value.split("—")[0]}${newMaxValue}`);
},
1000
);
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const sliderValue =
answer ||
(reversed
? max + min - currentQuestion.content.start + "—" + max
: currentQuestion.content.start + "—" + max);
useEffect(() => {
if (answer) {
if (answer.includes("—")) {
if (reversed) {
const newValue =
window.Number(value) < window.Number(min)
? String(min)
: window.Number(value) > window.Number(max)
? String(max)
: value;
setReversedInputValue(newValue);
updateAnswer(
currentQuestion.id,
String(max + min - window.Number(newValue)),
0
);
await sendAnswerToBackend(String(window.Number(newValue)), true);
return;
}
const newValue =
window.Number(value) < window.Number(minRange)
? minRange
: window.Number(value) > window.Number(maxRange)
? maxRange
: value;
setInputValue(newValue);
await sendAnswerToBackend(newValue);
}, 1000);
const updateMinRangeDebounced = useDebouncedCallback(
async (value: string, crowded = false) => {
if (reversed) {
const newMinRange = crowded
? window.Number(value.split("—")[1])
: max + min - window.Number(value.split("—")[0]) < min
? min
: max + min - window.Number(value.split("—")[0]);
const newMinValue =
window.Number(value.split("—")[0]) > max
? String(max)
: value.split("—")[0];
setReversedMinRange(
crowded ? String(max + min - window.Number(newMinValue)) : newMinValue
);
updateAnswer(
currentQuestion.id,
`${newMinRange}${value.split("—")[1]}`,
0
);
await sendAnswerToBackend(
`${newMinValue}${value.split("—")[1]}`,
true
);
return;
}
const newMinValue = crowded
? maxRange
: window.Number(value.split("—")[0]) < min
? String(min)
: value.split("—")[0];
setMinRange(newMinValue);
await sendAnswerToBackend(`${newMinValue}${value.split("—")[1]}`);
},
1000
);
const updateMaxRangeDebounced = useDebouncedCallback(
async (value: string, crowded = false) => {
if (reversed) {
const newMaxRange = crowded
? window.Number(value.split("—")[1])
: max + min - window.Number(value.split("—")[1]) > max
? max
: max + min - window.Number(value.split("—")[1]);
const newMaxValue =
window.Number(value.split("—")[1]) < min
? String(min)
: value.split("—")[1];
setReversedMaxRange(
crowded ? String(max + min - window.Number(newMaxValue)) : newMaxValue
);
updateAnswer(
currentQuestion.id,
`${value.split("—")[0]}${newMaxRange}`,
0
);
await sendAnswerToBackend(
`${value.split("—")[0]}${newMaxValue}`,
true
);
return;
}
const newMaxValue = crowded
? minRange
: window.Number(value.split("—")[1]) > max
? String(max)
: value.split("—")[1];
setMaxRange(newMaxValue);
await sendAnswerToBackend(`${value.split("—")[0]}${newMaxValue}`);
},
1000
);
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.id
)?.answer as string;
const sliderValue =
answer ||
(reversed
? max + min - currentQuestion.content.start + "—" + max
: currentQuestion.content.start + "—" + max);
useEffect(() => {
if (answer) {
if (answer.includes("—")) {
if (reversed) {
setReversedMinRange(
String(max + min - window.Number(answer.split("—")[0]))
);
setReversedMaxRange(
String(max + min - window.Number(answer.split("—")[1]))
);
} else {
setMinRange(answer.split("—")[0]);
setMaxRange(answer.split("—")[1]);
}
} else {
if (reversed) {
setReversedInputValue(String(max + min - window.Number(answer)));
} else {
setInputValue(answer);
}
}
}
if (!answer) {
setMinRange(String(currentQuestion.content.start));
setMaxRange(String(max));
if (currentQuestion.content.chooseRange) {
setReversedMinRange(String(currentQuestion.content.start));
setReversedMaxRange(String(min));
}
setReversedInputValue(String(currentQuestion.content.start));
setInputValue(String(currentQuestion.content.start));
}
}, []);
const onSliderChange = (_: Event, value: number | number[]) => {
const range = Array.isArray(value)
? `${value[0]}${value[1]}`
: String(value);
updateAnswer(currentQuestion.id, range, 0);
};
const onChangeCommitted = async (
_: Event | SyntheticEvent<Element, Event>,
value: number | number[]
) => {
if (currentQuestion.content.chooseRange && Array.isArray(value)) {
if (reversed) {
const newMinReversedValue = String(max + min - value[0]);
const newMaxReversedValue = String(max + min - value[1]);
setMinRange(String(value[0]));
setMaxRange(String(value[1]));
setReversedMinRange(newMinReversedValue);
setReversedMaxRange(newMaxReversedValue);
await sendAnswerToBackend(
`${newMinReversedValue}${newMaxReversedValue}`,
true
);
return;
}
setMinRange(String(value[0]));
setMaxRange(String(value[1]));
await sendAnswerToBackend(`${value[0]}${value[1]}`);
return;
}
if (reversed) {
setReversedInputValue(String(max + min - window.Number(value)));
setReversedMinRange(
String(max + min - window.Number(answer.split("—")[0]))
);
setReversedMaxRange(
String(max + min - window.Number(answer.split("—")[1]))
);
} else {
setInputValue(String(value));
setMinRange(answer.split("—")[0]);
setMaxRange(answer.split("—")[1]);
}
await sendAnswerToBackend(String(value));
};
const changeValueLabelFormat = (value: number) => {
if (!reversed) {
return value;
}
const [minSliderBorder, maxSliderBorder] = sliderValue
.split("—")
.map(window.Number);
if (value === minSliderBorder) {
return max + min - minSliderBorder;
}
return max + min - maxSliderBorder;
};
const onInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const value = target.value.replace(/\D/g, "");
} else {
if (reversed) {
setReversedInputValue(value);
setReversedInputValue(String(max + min - window.Number(answer)));
} else {
setInputValue(value);
setInputValue(answer);
}
}
}
updateValueDebounced(value);
};
if (!answer) {
setMinRange(String(currentQuestion.content.start));
setMaxRange(String(max));
const onMinInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const newValue = target.value.replace(/\D/g, "");
if (currentQuestion.content.chooseRange) {
setReversedMinRange(String(currentQuestion.content.start));
setReversedMaxRange(String(min));
}
if (reversed) {
setReversedMinRange(newValue);
setReversedInputValue(String(currentQuestion.content.start));
setInputValue(String(currentQuestion.content.start));
}
}, []);
if (window.Number(newValue) <= window.Number(reversedMaxRange)) {
const value = max + min - window.Number(reversedMaxRange);
updateMinRangeDebounced(`${value}${value}`, true);
const onSliderChange = (_: Event, value: number | number[]) => {
const range = Array.isArray(value)
? `${value[0]}${value[1]}`
: String(value);
return;
}
updateAnswer(currentQuestion.id, range, 0);
};
updateMinRangeDebounced(
`${newValue}${max + min - window.Number(reversedMaxRange)}`
);
const onChangeCommitted = async (
_: Event | SyntheticEvent<Element, Event>,
value: number | number[]
) => {
if (currentQuestion.content.chooseRange && Array.isArray(value)) {
if (reversed) {
const newMinReversedValue = String(max + min - value[0]);
const newMaxReversedValue = String(max + min - value[1]);
return;
}
setMinRange(String(value[0]));
setMaxRange(String(value[1]));
setReversedMinRange(newMinReversedValue);
setReversedMaxRange(newMaxReversedValue);
await sendAnswerToBackend(
`${newMinReversedValue}${newMaxReversedValue}`,
true
);
setMinRange(newValue);
return;
}
if (window.Number(newValue) >= window.Number(maxRange)) {
updateMinRangeDebounced(`${maxRange}${maxRange}`, true);
setMinRange(String(value[0]));
setMaxRange(String(value[1]));
await sendAnswerToBackend(`${value[0]}${value[1]}`);
return;
}
return;
}
updateMinRangeDebounced(`${newValue}${maxRange}`);
};
if (reversed) {
setReversedInputValue(String(max + min - window.Number(value)));
} else {
setInputValue(String(value));
}
const onMaxInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const newValue = target.value.replace(/\D/g, "");
await sendAnswerToBackend(String(value));
};
if (reversed) {
setReversedMaxRange(newValue);
const changeValueLabelFormat = (value: number) => {
if (!reversed) {
return value;
}
if (window.Number(newValue) >= window.Number(reversedMinRange)) {
const value = max + min - window.Number(reversedMinRange);
updateMaxRangeDebounced(`${value}${value}`, true);
const [minSliderBorder, maxSliderBorder] = sliderValue
.split("—")
.map(window.Number);
return;
}
if (value === minSliderBorder) {
return max + min - minSliderBorder;
}
updateMaxRangeDebounced(
`${max + min - window.Number(reversedMinRange)}${newValue}`
);
return max + min - maxSliderBorder;
};
return;
}
const onInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const value = target.value.replace(/\D/g, "");
setMaxRange(newValue);
if (reversed) {
setReversedInputValue(value);
} else {
setInputValue(value);
}
if (window.Number(newValue) <= window.Number(minRange)) {
updateMaxRangeDebounced(`${minRange}${minRange}`, true);
updateValueDebounced(value);
};
return;
}
const onMinInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const newValue = target.value.replace(/\D/g, "");
updateMaxRangeDebounced(`${minRange}${newValue}`);
};
if (reversed) {
setReversedMinRange(newValue);
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
gap: "30px",
paddingRight: isMobile ? "10px" : undefined,
}}
>
<CustomSlider
value={
currentQuestion.content.chooseRange
? sliderValue.split("—").length || 0 > 1
? sliderValue.split("—").map((item) => window.Number(item))
: [min, min + 1]
: window.Number(sliderValue.split("—")[0])
}
min={min}
max={max}
step={currentQuestion.content.step || 1}
onChange={onSliderChange}
onChangeCommitted={onChangeCommitted}
valueLabelFormat={changeValueLabelFormat}
sx={{
color: theme.palette.primary.main,
"& .MuiSlider-valueLabel": {
background: theme.palette.primary.main,
},
}}
/>
if (window.Number(newValue) <= window.Number(reversedMaxRange)) {
const value = max + min - window.Number(reversedMaxRange);
updateMinRangeDebounced(`${value}${value}`, true);
{!currentQuestion.content.chooseRange && (
<CustomTextField
placeholder="0"
value={reversed ? reversedInputValue : inputValue}
onChange={onInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiInputBase-input": {
textAlign: "center",
backgroundColor: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
)}
return;
}
{currentQuestion.content.chooseRange && (
<Box
sx={{
display: "flex",
gap: "15px",
alignItems: "center",
"& .MuiFormControl-root": { width: "auto" },
}}
>
<CustomTextField
placeholder="0"
value={reversed ? String(reversedMinRange) : minRange}
onChange={onMinInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiInputBase-input": {
textAlign: "center",
backgroundColor: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
<Typography color={theme.palette.text.primary}>до</Typography>
<CustomTextField
placeholder="0"
value={reversed ? String(reversedMaxRange) : maxRange}
onChange={onMaxInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiInputBase-input": {
textAlign: "center",
backgroundColor: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
</Box>
)}
</Box>
</Box>
);
updateMinRangeDebounced(
`${newValue}${max + min - window.Number(reversedMaxRange)}`
);
return;
}
setMinRange(newValue);
if (window.Number(newValue) >= window.Number(maxRange)) {
updateMinRangeDebounced(`${maxRange}${maxRange}`, true);
return;
}
updateMinRangeDebounced(`${newValue}${maxRange}`);
};
const onMaxInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const newValue = target.value.replace(/\D/g, "");
if (reversed) {
setReversedMaxRange(newValue);
if (window.Number(newValue) >= window.Number(reversedMinRange)) {
const value = max + min - window.Number(reversedMinRange);
updateMaxRangeDebounced(`${value}${value}`, true);
return;
}
updateMaxRangeDebounced(
`${max + min - window.Number(reversedMinRange)}${newValue}`
);
return;
}
setMaxRange(newValue);
if (window.Number(newValue) <= window.Number(minRange)) {
updateMaxRangeDebounced(`${minRange}${minRange}`, true);
return;
}
updateMaxRangeDebounced(`${minRange}${newValue}`);
};
return (
<Box>
<Typography
variant="h5"
color={theme.palette.text.primary}
sx={{ wordBreak: "break-word" }}
>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
gap: "30px",
paddingRight: isMobile ? "10px" : undefined,
}}
>
<CustomSlider
value={
currentQuestion.content.chooseRange
? sliderValue.split("—").length || 0 > 1
? sliderValue.split("—").map((item) => window.Number(item))
: [min, min + 1]
: window.Number(sliderValue.split("—")[0])
}
min={min}
max={max}
step={currentQuestion.content.step || 1}
onChange={onSliderChange}
onChangeCommitted={onChangeCommitted}
valueLabelFormat={changeValueLabelFormat}
sx={{
color: theme.palette.primary.main,
"& .MuiSlider-valueLabel": {
background: theme.palette.primary.main,
},
}}
/>
{!currentQuestion.content.chooseRange && (
<CustomTextField
placeholder="0"
value={reversed ? reversedInputValue : inputValue}
onChange={onInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiOutlinedInput-root": { background: "transparent" },
"& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
"& .MuiOutlinedInput-notchedOutline": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
)}
{currentQuestion.content.chooseRange && (
<Box
sx={{
display: "flex",
gap: "15px",
alignItems: "center",
"& .MuiFormControl-root": { width: "auto" },
}}
>
<CustomTextField
placeholder="0"
value={reversed ? String(reversedMinRange) : minRange}
onChange={onMinInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiOutlinedInput-root": { background: "transparent" },
"& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
"& .MuiOutlinedInput-notchedOutline": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
<Typography color={theme.palette.text.primary}>до</Typography>
<CustomTextField
placeholder="0"
value={reversed ? String(reversedMaxRange) : maxRange}
onChange={onMaxInputChange}
sx={{
maxWidth: "80px",
borderColor: theme.palette.text.primary,
"& .MuiOutlinedInput-root": { background: "transparent" },
"& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
"& .MuiOutlinedInput-notchedOutline": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
},
}}
/>
</Box>
)}
</Box>
</Box>
);
};

@ -1,4 +1,10 @@
import {Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme} from "@mui/material";
import {
Box,
TextField as MuiTextField,
TextFieldProps,
Typography,
useTheme,
} from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField";
@ -8,194 +14,259 @@ import { sendAnswer } from "@api/quizRelase";
import { useQuizData } from "@contexts/QuizDataContext";
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
import { enqueueSnackbar } from "notistack";
import {ChangeEvent, FC, useEffect, useState} from "react";
import { ChangeEvent, FC, useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import type { QuizQuestionText } from "../../../model/questionTypes/text";
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
type TextProps = {
currentQuestion: QuizQuestionText;
stepNumber: number | null;
currentQuestion: QuizQuestionText;
stepNumber: number | null;
};
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},
]
{ 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 = useRootContainerSize() < 650;
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
const [isSending, setIsSending] = useState<boolean>(false);
const theme = useTheme();
const { settings } = useQuizData();
const spec = settings.cfg.spec;
const { quizId } = useQuizData();
const { answers } = useQuizViewStore();
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);
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} />;
const inputHC = useDebouncedCallback(async (text) => {
setIsSending(true);
try {
await sendAnswer({
questionId: currentQuestion.id,
body: text,
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
setIsSending(false);
}, 400);
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;
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>
const TextNormal = ({ currentQuestion, answer, inputHC }: Props) => {
const isMobile = useRootContainerSize() < 650;
const theme = useTheme();
const { settings } = useQuizData();
return (
<Box>
<Typography
variant="h5"
color={theme.palette.text.primary}
sx={{ wordBreak: "break-word" }}
>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
width: "100%",
marginTop: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
alignItems: "center",
}}
>
<CustomTextField
placeholder={currentQuestion.content.placeholder}
value={answer || ""}
onChange={async ({ target }) => {
updateAnswer(currentQuestion.id, target.value, 0);
inputHC(target.value);
}}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: "#FFFFFF",
},
"&:focus-visible": { borderColor: theme.palette.primary.main },
}}
/>
{currentQuestion.content.back &&
currentQuestion.content.back !== " " && (
<Box
sx={{
display: "flex",
width: "100%",
marginTop: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
alignItems: "center"
}}
sx={{
maxWidth: "400px",
width: "100%",
height: "300px",
margin: "15px",
}}
>
<CustomTextField
placeholder={currentQuestion.content.placeholder}
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
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
)}
<img
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
</Box>
)
)}
</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>
)}
{
(<TextField
autoFocus={true}
multiline
maxRows={4}
placeholder={currentQuestion.content.placeholder}
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
}
}}
/>)
}
const TextSpecial = ({
currentQuestion,
answer,
inputHC,
stepNumber,
}: Props) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const isHorizontal = Orientation[Number(stepNumber) - 1].horizontal;
const { settings } = useQuizData();
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>
{!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>
)
}
)}
{
<TextField
autoFocus={true}
multiline
maxRows={4}
placeholder={currentQuestion.content.placeholder}
value={answer || ""}
onChange={async ({ target }: ChangeEvent<HTMLInputElement>) => {
updateAnswer(currentQuestion.id, target.value, 0);
inputHC(target.value);
}}
inputProps={{ maxLength: 400 }}
sx={{
width: "100%",
"& .MuiOutlinedInput-root": {
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: "#FFFFFF",
},
"&: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>
);
};

@ -1,22 +1,22 @@
import {
Box,
Checkbox,
FormControlLabel,
FormGroup,
TextField as MuiTextField,
Radio,
RadioGroup,
TextFieldProps,
Typography,
useTheme
Box,
Checkbox,
FormControlLabel,
FormGroup,
TextField as MuiTextField,
Radio,
RadioGroup,
TextFieldProps,
Typography,
useTheme,
} from "@mui/material";
import { FC, useEffect, useState } from "react";
import {
deleteAnswer,
updateAnswer,
updateOwnVariant,
useQuizViewStore
deleteAnswer,
updateAnswer,
updateOwnVariant,
useQuizViewStore,
} from "@stores/quizView";
import { CheckboxIcon } from "@icons/Checkbox";
@ -36,245 +36,261 @@ import moment from "moment";
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
type VariantProps = {
currentQuestion: QuizQuestionVariant;
currentQuestion: QuizQuestionVariant;
};
export const Variant = ({ currentQuestion }: VariantProps) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const { answers, ownVariants } = useQuizViewStore();
const { answer } =
answers.find(
({ questionId }) => questionId === currentQuestion.id
) ?? {};
const ownVariant = ownVariants.find(
(variant) => variant.id === currentQuestion.id
);
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const { answers, ownVariants } = useQuizViewStore();
const { answer } =
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
const ownVariant = ownVariants.find(
(variant) => variant.id === currentQuestion.id
);
const [isSending, setIsSending] = useState(false);
const [isSending, setIsSending] = useState(false);
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
useEffect(() => {
if (!ownVariant) {
updateOwnVariant(currentQuestion.id, "");
}
}, []);
useEffect(() => {
if (!ownVariant) {
updateOwnVariant(currentQuestion.id, "");
}
}, []);
if (moment.isMoment(answer)) throw new Error("Answer is Moment in Variant question");
if (moment.isMoment(answer))
throw new Error("Answer is Moment in Variant question");
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
<Box sx={{
display: "flex", gap: "20px",
flexDirection: isMobile ? "column-reverse" : undefined, alignItems: isMobile ? "center" : undefined
}}>
<Group
name={currentQuestion.id.toString()}
value={currentQuestion.content.variants.findIndex(
({ id }) => answer === id
)}
sx={{
display: "flex",
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "space-between",
flexBasis: "100%",
marginTop: "20px",
width: isMobile ? "100%" : undefined
}}
>
<Box
sx={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
width: "100%",
gap: "20px",
}}
>
{currentQuestion.content.variants.map((variant, index) => (
<VariantItem
key={variant.id}
currentQuestion={currentQuestion}
variant={variant}
answer={answer}
index={index}
isSending={isSending}
setIsSending={setIsSending}
/>
))}
{currentQuestion.content.own && ownVariant && (
<VariantItem
own
currentQuestion={currentQuestion}
variant={ownVariant.variant}
answer={answer}
index={currentQuestion.content.variants.length + 2}
isSending={isSending}
setIsSending={setIsSending}
/>
)}
</Box>
</Group>
{currentQuestion.content.back && currentQuestion.content.back !== " " && (
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
<img
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
)}
return (
<Box>
<Typography
variant="h5"
color={theme.palette.text.primary}
sx={{ wordBreak: "break-word" }}
>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
gap: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
alignItems: isMobile ? "center" : undefined,
}}
>
<Group
name={currentQuestion.id.toString()}
value={currentQuestion.content.variants.findIndex(
({ id }) => answer === id
)}
sx={{
display: "flex",
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "space-between",
flexBasis: "100%",
marginTop: "20px",
width: isMobile ? "100%" : undefined,
}}
>
<Box
sx={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
width: "100%",
gap: "20px",
}}
>
{currentQuestion.content.variants.map((variant, index) => (
<VariantItem
key={variant.id}
currentQuestion={currentQuestion}
variant={variant}
answer={answer}
index={index}
isSending={isSending}
setIsSending={setIsSending}
/>
))}
{currentQuestion.content.own && ownVariant && (
<VariantItem
own
currentQuestion={currentQuestion}
variant={ownVariant.variant}
answer={answer}
index={currentQuestion.content.variants.length + 2}
isSending={isSending}
setIsSending={setIsSending}
/>
)}
</Box>
</Group>
{currentQuestion.content.back &&
currentQuestion.content.back !== " " && (
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
<img
key={currentQuestion.id}
src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
</Box>
</Box>
);
)}
</Box>
</Box>
);
};
const VariantItem = ({
currentQuestion,
variant,
answer,
index,
own = false,
isSending,
setIsSending,
currentQuestion,
variant,
answer,
index,
own = false,
isSending,
setIsSending,
}: {
currentQuestion: QuizQuestionVariant;
variant: QuestionVariant;
answer: string | string[] | undefined;
index: number;
own?: boolean;
isSending: boolean;
setIsSending: (a: boolean) => void;
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();
const theme = useTheme();
const { settings, quizId } = useQuizData();
return (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
margin: "0",
borderRadius: "12px",
color: theme.palette.text.primary,
padding: "15px",
border: `1px solid`,
borderColor: answer === variant.id
? theme.palette.primary.main
: "#9A9AAF",
backgroundColor: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
display: "flex",
maxWidth: "685px",
maxHeight: "85px",
justifyContent: "space-between",
width: "100%",
"&.MuiFormControl-root": {
width: "100%",
},
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
lineHeight: "normal",
"&::-webkit-scrollbar": {
width: "4px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#b8babf",
}
}
}}
value={index}
labelPlacement="start"
control={
currentQuestion.content.multi ?
<Checkbox
checked={!!answer?.includes(variant.id)}
checkedIcon={<CheckboxIcon checked color={theme.palette.primary.main} />}
icon={<CheckboxIcon />}
/>
:
<Radio checkedIcon={<RadioCheck color={theme.palette.primary.main} />} icon={<RadioIcon />} />
return (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
margin: "0",
borderRadius: "12px",
color: theme.palette.text.primary,
padding: "15px",
border: `1px solid`,
borderColor:
answer === variant.id ? theme.palette.primary.main : "#9A9AAF",
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
display: "flex",
maxWidth: "685px",
maxHeight: "85px",
justifyContent: "space-between",
width: "100%",
"&.MuiFormControl-root": {
width: "100%",
},
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
lineHeight: "normal",
"&::-webkit-scrollbar": {
width: "4px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#b8babf",
},
},
}}
value={index}
labelPlacement="start"
control={
currentQuestion.content.multi ? (
<Checkbox
checked={!!answer?.includes(variant.id)}
checkedIcon={
<CheckboxIcon checked color={theme.palette.primary.main} />
}
label={own ? <TextField label="Другое..." /> : variant.answer}
onClick={async (event) => {
event.preventDefault();
if (isSending) return;
icon={<CheckboxIcon />}
/>
) : (
<Radio
checkedIcon={<RadioCheck color={theme.palette.primary.main} />}
icon={<RadioIcon />}
/>
)
}
label={own ? <TextField label="Другое..." /> : variant.answer}
onClick={async (event) => {
event.preventDefault();
if (isSending) return;
setIsSending(true);
const variantId = currentQuestion.content.variants[index].id;
console.log(answer);
setIsSending(true);
const variantId = currentQuestion.content.variants[index].id;
console.log(answer);
if (currentQuestion.content.multi) {
const currentAnswer = typeof answer !== "string" ? answer || [] : [];
if (currentQuestion.content.multi) {
const currentAnswer = typeof answer !== "string" ? answer || [] : [];
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentAnswer.includes(variantId)
? currentAnswer?.filter((item) => item !== variantId)
: [...currentAnswer, variantId],
qid: quizId,
});
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("ответ не был засчитан");
}
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("ответ не был засчитан");
}
setIsSending(false);
return;
}
setIsSending(false);
return;
}
try {
await sendAnswer({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].answer,
qid: quizId,
});
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
);
updateAnswer(
currentQuestion.id,
variantId,
answer === variantId
? 0
: currentQuestion.content.variants[index].points || 0
);
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
} 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);
}
if (answer === variantId) {
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
console.log(e);
enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
setIsSending(false);
}}
/>
);
setIsSending(false);
}}
/>
);
};

@ -1,10 +1,10 @@
import {
Box,
FormControlLabel,
Radio,
RadioGroup,
Typography,
useTheme
Box,
FormControlLabel,
Radio,
RadioGroup,
Typography,
useTheme,
} from "@mui/material";
import { deleteAnswer, updateAnswer, useQuizViewStore } from "@stores/quizView";
@ -21,173 +21,192 @@ import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
import { useState } from "react";
type VarimgProps = {
currentQuestion: QuizQuestionVarImg;
currentQuestion: QuizQuestionVarImg;
};
export const Varimg = ({ currentQuestion }: VarimgProps) => {
const { settings, quizId } = useQuizData();
const { answers } = useQuizViewStore();
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const [isSending, setIsSending] = useState<boolean>(false);
const { settings, quizId } = useQuizData();
const { answers } = useQuizViewStore();
const theme = useTheme();
const isMobile = useRootContainerSize() < 650;
const [isSending, setIsSending] = useState<boolean>(false);
const { answer } =
answers.find(
({ questionId }) => questionId === currentQuestion.id
) ?? {};
const variant = currentQuestion.content.variants.find(
({ id }) => answer === id
);
const { answer } =
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
const variant = currentQuestion.content.variants.find(
({ id }) => answer === id
);
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary} sx={{ wordBreak: "break-word" }}>{currentQuestion.title}</Typography>
<Box sx={{
display: "flex",
marginTop: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
gap: isMobile ? "30px" : undefined,
alignItems: isMobile ? "center" : undefined
return (
<Box>
<Typography
variant="h5"
color={theme.palette.text.primary}
sx={{ wordBreak: "break-word" }}
>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
marginTop: "20px",
flexDirection: isMobile ? "column-reverse" : undefined,
gap: isMobile ? "30px" : undefined,
alignItems: isMobile ? "center" : undefined,
}}
>
<RadioGroup
name={currentQuestion.id}
value={currentQuestion.content.variants.findIndex(
({ id }) => answer === id
)}
sx={{
display: "flex",
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "space-between",
flexBasis: "100%",
width: isMobile ? "100%" : undefined,
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
gap: isMobile ? "20px" : undefined,
}}
>
{currentQuestion.content.variants.map((variant, index) => (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
marginBottom: "15px",
borderRadius: "5px",
padding: "15px",
color: theme.palette.text.primary,
backgroundColor: settings.cfg.design
? "rgba(154,154,175, 0.2)"
: quizThemes[settings.cfg.theme].isLight
? "white"
: theme.palette.background.default,
border: `1px solid`,
borderColor:
answer === variant.id
? theme.palette.primary.main
: "#9A9AAF",
display: "flex",
margin: isMobile ? 0 : undefined,
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
lineHeight: "normal",
paddingLeft: "45px",
"&::-webkit-scrollbar": {
width: "4px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#b8babf",
},
},
}}
value={index}
onClick={async (event) => {
event.preventDefault();
}}>
<RadioGroup
name={currentQuestion.id}
value={currentQuestion.content.variants.findIndex(
({ id }) => answer === id
)}
sx={{
display: "flex",
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "space-between",
flexBasis: "100%",
width: isMobile ? "100%" : undefined
}}
>
<Box sx={{ display: "flex", flexDirection: "column", width: "100%", gap: isMobile ? "20px" : undefined }}>
{currentQuestion.content.variants.map((variant, index) => (
<FormControlLabel
key={variant.id}
disabled={isSending}
sx={{
marginBottom: "15px",
borderRadius: "5px",
padding: "15px",
color: theme.palette.text.primary,
backgroundColor: quizThemes[settings.cfg.theme].isLight ? "white" : theme.palette.background.default,
border: `1px solid`,
borderColor: answer === variant.id ? theme.palette.primary.main : "#9A9AAF",
display: "flex",
margin: isMobile ? 0 : undefined,
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
lineHeight: "normal",
paddingLeft: "45px",
"&::-webkit-scrollbar": {
width: "4px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#b8babf",
}
},
}}
value={index}
onClick={async (event) => {
event.preventDefault();
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,
});
setIsSending(true);
try {
updateAnswer(
currentQuestion.id,
currentQuestion.content.variants[index].id,
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
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,
});
if (answer === currentQuestion.content.variants[index].id) {
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
updateAnswer(
currentQuestion.id,
currentQuestion.content.variants[index].id,
currentQuestion.content.variants[index].points || 0
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
if (answer === currentQuestion.content.variants[index].id) {
try {
await sendAnswer({
questionId: currentQuestion.id,
body: "",
qid: quizId,
});
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
setIsSending(false);
}}
control={
<Radio checkedIcon={<RadioCheck color={theme.palette.primary.main} />} icon={<RadioIcon />} />
}
label={variant.answer}
/>
))}
</Box>
</RadioGroup>
{/* {(variant?.extendedText || currentQuestion.content.back) && ( */}
<Box
sx={{
maxWidth: "450px",
width: "100%",
height: "450px",
border: "1px solid #9A9AAF",
borderRadius: "12px",
overflow: "hidden",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#9A9AAF12",
color: "#9A9AAF",
textAlign: "center"
}}
>
{answer ? (
variant?.extendedText ? (
<img
src={variant?.extendedText}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
) : (
<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 ? (
"Выберите вариант ответа ниже"
) : (
"Выберите вариант ответа слева"
)}
</Box>
{/* )} */}
</Box>
setIsSending(false);
}}
control={
<Radio
checkedIcon={
<RadioCheck color={theme.palette.primary.main} />
}
icon={<RadioIcon />}
/>
}
label={variant.answer}
/>
))}
</Box>
</RadioGroup>
{/* {(variant?.extendedText || currentQuestion.content.back) && ( */}
<Box
sx={{
maxWidth: "450px",
width: "100%",
height: "450px",
border: "1px solid #9A9AAF",
borderRadius: "12px",
overflow: "hidden",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#9A9AAF12",
color: "#9A9AAF",
textAlign: "center",
}}
>
{answer ? (
variant?.extendedText ? (
<img
src={variant?.extendedText}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt=""
/>
) : (
<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 ? (
"Выберите вариант ответа ниже"
) : (
"Выберите вариант ответа слева"
)}
</Box>
);
{/* )} */}
</Box>
</Box>
);
};

@ -121,8 +121,7 @@ export const Select = ({
"& .MuiTypography-root": {
overflow: "hidden",
textOverflow: "ellipsis",
}
},
},
}}
IconComponent={(props) => <ArrowDown {...props} />}
@ -139,7 +138,7 @@ export const Select = ({
borderRadius: "5px",
color: colorPlaceholder,
whiteSpace: "normal",
wordBreak: "break-word"
wordBreak: "break-word",
}}
>
{item}

@ -21,7 +21,17 @@ export type QuizTheme =
| "GoldDarkTheme"
| "PurpleTheme"
| "BlueTheme"
| "BlueDarkTheme";
| "BlueDarkTheme"
| "Design1"
| "Design2"
| "Design3"
| "Design4"
| "Design5"
| "Design6"
| "Design7"
| "Design8"
| "Design9"
| "Design10";
export type FCField = {
text: string;
@ -47,18 +57,6 @@ export type QuizSettings = {
recentlyCompleted: boolean;
};
export type Design =
| ""
| "design1"
| "design2"
| "design3"
| "design4"
| "design5"
| "design6"
| "design7"
| "design8"
| "design9"
| "design10";
export interface QuizConfig {
spec: undefined | true;
@ -69,7 +67,7 @@ export interface QuizConfig {
results: QuizResultsType;
haveRoot: string | null;
theme: QuizTheme;
design: Design;
design: boolean;
resultInfo: {
when: "email" | "";
share: boolean;

37
lib/ui_kit/Stepper.tsx Normal file

@ -0,0 +1,37 @@
import { useTheme } from "@mui/material";
import MobileStepper from "@mui/material/MobileStepper";
interface Props {
activeStep: number;
steps: number;
}
export default function ProgressMobileStepper({ activeStep, steps }: Props) {
const theme = useTheme();
return (
<MobileStepper
variant="progress"
steps={steps + 1}
position="static"
activeStep={activeStep}
sx={{
width: "100%",
padding: "10px 0 0",
background: "transparent",
"& .MuiLinearProgress-root": {
height: "4px",
background: theme.palette.primary.light,
width: "100%",
opacity: 0.5,
},
"& .MuiLinearProgress-bar": {
background: theme.palette.primary.main,
opacity: 1,
},
}}
nextButton={<></>}
backButton={<></>}
/>
);
}

@ -1,229 +1,431 @@
import { QuizTheme } from "@model/settingsData";
import { Theme, createTheme } from "@mui/material";
import { createTheme } from "@mui/material";
import themePublic from "./genericPublication";
import type { Theme } from "@mui/material";
import type { QuizTheme } from "@model/settingsData";
const StandardTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#7E2AEA",
},
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#7E2AEA",
},
background: {
default: "#FFFFFF",
},
}
})
background: {
default: "#FFFFFF",
},
},
});
const StandardDarkTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734"
},
text: {
primary: "#FFFFFF",
secondary: "#7E2AEA",
},
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#7E2AEA",
},
background: {
default: "#333647",
},
}
})
background: {
default: "#333647",
},
},
});
const PinkTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#D34085",
},
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#D34085",
},
background: {
default: "#FFF9FC",
},
}
})
background: {
default: "#FFF9FC",
},
},
});
const PinkDarkTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734"
},
text: {
primary: "#FFFFFF",
secondary: "#D34085",
},
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#D34085",
},
background: {
default: "#333647",
},
}
})
background: {
default: "#333647",
},
},
});
const BlackWhiteTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#4E4D51",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#FFF9FC",
},
...themePublic,
palette: {
primary: {
main: "#4E4D51",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#FFF9FC",
},
background: {
default: "#FFFFFF",
},
}
})
background: {
default: "#FFFFFF",
},
},
});
const OliveTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#758E4F",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#758E4F",
},
...themePublic,
palette: {
primary: {
main: "#758E4F",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#758E4F",
},
background: {
default: "#F9FBF1",
},
}
})
background: {
default: "#F9FBF1",
},
},
});
const PurpleTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#7E2AEA",
},
...themePublic,
palette: {
primary: {
main: "#7E2AEA",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#7E2AEA",
},
background: {
default: "#FBF8FF",
},
}
})
background: {
default: "#FBF8FF",
},
},
});
const YellowTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#F2B133",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#F2B133",
},
...themePublic,
palette: {
primary: {
main: "#F2B133",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#F2B133",
},
background: {
default: "#FFFCF6",
},
}
})
background: {
default: "#FFFCF6",
},
},
});
const GoldDarkTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#E6AA37",
},
secondary: {
main: "#FFFCF6",
},
text: {
primary: "#FFFFFF",
secondary: "#F2B133",
},
...themePublic,
palette: {
primary: {
main: "#E6AA37",
},
secondary: {
main: "#FFFCF6",
},
text: {
primary: "#FFFFFF",
secondary: "#F2B133",
},
background: {
default: "#333647",
},
}
})
background: {
default: "#333647",
},
},
});
const BlueTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#4964ED",
},
secondary: {
main: "#252734"
},
text: {
primary: "#333647",
secondary: "#4964ED",
},
...themePublic,
palette: {
primary: {
main: "#4964ED",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#4964ED",
},
background: {
default: "#F5F7FF",
},
}
})
background: {
default: "#F5F7FF",
},
},
});
const BlueDarkTheme = createTheme({
...themePublic,
palette: {
primary: {
main: "#07A0C3",
},
secondary: {
main: "#252734"
},
text: {
primary: "#FFFFFF",
secondary: "#07A0C3",
},
...themePublic,
palette: {
primary: {
main: "#07A0C3",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#07A0C3",
},
background: {
default: "#333647",
},
}
})
background: {
default: "#333647",
},
},
});
export const quizThemes: Record<QuizTheme, { theme: Theme; isLight: boolean; }> = {
const Design1 = createTheme({
...themePublic,
palette: {
primary: {
main: "#F2B133",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#F2B133",
},
background: {
default: "#FFFCF6",
},
},
});
const Design2 = createTheme({
...themePublic,
palette: {
primary: {
main: "#758E4F",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#758E4F",
},
background: {
default: "#F9FBF1",
},
},
});
const Design3 = createTheme({
...themePublic,
palette: {
primary: {
main: "#07A0C3",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#07A0C3",
},
background: {
default: "#333647",
},
},
});
const Design4 = createTheme({
...themePublic,
palette: {
primary: {
main: "#F2B133",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#F2B133",
},
background: {
default: "#FFFCF6",
},
},
});
const Design5 = createTheme({
...themePublic,
palette: {
primary: {
main: "#07A0C3",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#07A0C3",
},
background: {
default: "#333647",
},
},
});
const Design6 = createTheme({
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#D34085",
},
background: {
default: "#333647",
},
},
});
const Design8 = createTheme({
...themePublic,
palette: {
primary: {
main: "#D34085",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#D34085",
},
background: {
default: "#333647",
},
},
});
const Design7 = createTheme({
...themePublic,
palette: {
primary: {
main: "#F2B133",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#F2B133",
},
background: {
default: "#FFFCF6",
},
},
});
const Design9 = createTheme({
...themePublic,
palette: {
primary: {
main: "#758E4F",
},
secondary: {
main: "#252734",
},
text: {
primary: "#333647",
secondary: "#758E4F",
},
background: {
default: "#F9FBF1",
},
},
});
const Design10 = createTheme({
...themePublic,
palette: {
primary: {
main: "#07A0C3",
},
secondary: {
main: "#252734",
},
text: {
primary: "#FFFFFF",
secondary: "#07A0C3",
},
background: {
default: "#333647",
},
},
});
export const quizThemes: Record<QuizTheme, { theme: Theme; isLight: boolean }> =
{
StandardTheme: { theme: StandardTheme, isLight: true },
StandardDarkTheme: { theme: StandardDarkTheme, isLight: false },
PinkTheme: { theme: PinkTheme, isLight: true },
@ -235,4 +437,14 @@ export const quizThemes: Record<QuizTheme, { theme: Theme; isLight: boolean; }>
PurpleTheme: { theme: PurpleTheme, isLight: true },
BlueTheme: { theme: BlueTheme, isLight: true },
BlueDarkTheme: { theme: BlueDarkTheme, isLight: false },
};
Design1: { theme: Design1, isLight: false },
Design2: { theme: Design2, isLight: false },
Design3: { theme: Design3, isLight: true },
Design4: { theme: Design4, isLight: false },
Design5: { theme: Design5, isLight: false },
Design6: { theme: Design6, isLight: false },
Design7: { theme: Design7, isLight: false },
Design8: { theme: Design8, isLight: false },
Design9: { theme: Design9, isLight: false },
Design10: { theme: Design10, isLight: false },
};