make quiz view store component store
move design list to separate file
This commit is contained in:
parent
73e6a95902
commit
979d0e7138
@ -16,6 +16,7 @@ import { ErrorBoundary } from "react-error-boundary";
|
||||
import useSWR from "swr";
|
||||
import { ApologyPage } from "./ViewPublicationPage/ApologyPage";
|
||||
import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage";
|
||||
import { QuizViewContext, createQuizViewStore } from "@/stores/quizView";
|
||||
|
||||
|
||||
moment.locale("ru");
|
||||
@ -28,6 +29,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function QuizAnswerer({ quizSettings, quizId, preview = false }: Props) {
|
||||
const [quizViewStore] = useState(createQuizViewStore);
|
||||
const [rootContainerWidth, setRootContainerWidth] = useState<number>(() => window.innerWidth);
|
||||
const rootContainerRef = useRef<HTMLDivElement>(null);
|
||||
const { data, error, isLoading } = useSWR(quizSettings ? null : ["quizData", quizId], params => getQuizData(params[1]), {
|
||||
@ -61,33 +63,35 @@ export default function QuizAnswerer({ quizSettings, quizId, preview = false }:
|
||||
if (!quizSettings) throw new Error("Quiz data is null");
|
||||
|
||||
return (
|
||||
<RootContainerWidthContext.Provider value={rootContainerWidth}>
|
||||
<QuizDataContext.Provider value={{ ...quizSettings, quizId, preview }}>
|
||||
<LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="ru" localeText={localeText}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<SnackbarProvider
|
||||
preventDuplicate={true}
|
||||
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
||||
>
|
||||
<CssBaseline />
|
||||
<Box
|
||||
ref={rootContainerRef}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
<QuizViewContext.Provider value={quizViewStore}>
|
||||
<RootContainerWidthContext.Provider value={rootContainerWidth}>
|
||||
<QuizDataContext.Provider value={{ ...quizSettings, quizId, preview }}>
|
||||
<LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="ru" localeText={localeText}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<SnackbarProvider
|
||||
preventDuplicate={true}
|
||||
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
||||
>
|
||||
<ErrorBoundary
|
||||
FallbackComponent={ApologyPage}
|
||||
onError={handleComponentError}
|
||||
<CssBaseline />
|
||||
<Box
|
||||
ref={rootContainerRef}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<ViewPublicationPage />
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
</SnackbarProvider>
|
||||
</ThemeProvider>
|
||||
</LocalizationProvider>
|
||||
</QuizDataContext.Provider>
|
||||
</RootContainerWidthContext.Provider>
|
||||
<ErrorBoundary
|
||||
FallbackComponent={ApologyPage}
|
||||
onError={handleComponentError}
|
||||
>
|
||||
<ViewPublicationPage />
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
</SnackbarProvider>
|
||||
</ThemeProvider>
|
||||
</LocalizationProvider>
|
||||
</QuizDataContext.Provider>
|
||||
</RootContainerWidthContext.Provider>
|
||||
</QuizViewContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import {quizThemes} from "@utils/themes/Publication/themePublication";
|
||||
import {enqueueSnackbar} from "notistack";
|
||||
import {useRootContainerSize} from "../../contexts/RootContainerWidthContext";
|
||||
import {useQuizData} from "@contexts/QuizDataContext";
|
||||
import {DESIGN_LIST} from "@/components/ViewPublicationPage/Question";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
|
||||
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
|
||||
|
@ -21,161 +21,128 @@ import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
|
||||
import { notReachable } from "@utils/notReachable";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
|
||||
import Desgin1 from "@icons/designs/design1.jpg";
|
||||
import Desgin2 from "@icons/designs/design2.jpg";
|
||||
import Desgin3 from "@icons/designs/design3.jpg";
|
||||
import Desgin4 from "@icons/designs/design4.jpg";
|
||||
import Desgin5 from "@icons/designs/design5.jpg";
|
||||
import Desgin6 from "@icons/designs/design6.jpg";
|
||||
import Desgin7 from "@icons/designs/design7.jpg";
|
||||
import Desgin8 from "@icons/designs/design8.jpg";
|
||||
import Desgin9 from "@icons/designs/design9.jpg";
|
||||
import Desgin10 from "@icons/designs/design10.jpg";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import type { QuizTheme } from "@model/settingsData";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
type Props = {
|
||||
currentQuestion: RealTypedQuizQuestion;
|
||||
currentQuestionStepNumber: number | null;
|
||||
nextButton: ReactNode;
|
||||
prevButton: ReactNode;
|
||||
};
|
||||
|
||||
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: "",
|
||||
currentQuestion: RealTypedQuizQuestion;
|
||||
currentQuestionStepNumber: number | null;
|
||||
nextButton: ReactNode;
|
||||
prevButton: ReactNode;
|
||||
};
|
||||
|
||||
export const Question = ({
|
||||
currentQuestion,
|
||||
currentQuestionStepNumber,
|
||||
nextButton,
|
||||
prevButton,
|
||||
currentQuestion,
|
||||
currentQuestionStepNumber,
|
||||
nextButton,
|
||||
prevButton,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const { settings, show_badge } = useQuizData();
|
||||
const theme = useTheme();
|
||||
const { settings, show_badge } = useQuizData();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "transparent"
|
||||
: "linear-gradient(90deg,#272626, transparent)"
|
||||
: theme.palette.background.default,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc(100% - 75px)",
|
||||
overflow: "auto",
|
||||
width: "100%"
|
||||
height: "100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc(100% - 75px)",
|
||||
width: "100%",
|
||||
maxWidth: "1440px",
|
||||
padding: "40px 25px 20px",
|
||||
margin: "0 auto",
|
||||
//overflow: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<QuestionByType
|
||||
key={currentQuestion.id}
|
||||
question={currentQuestion}
|
||||
stepNumber={currentQuestionStepNumber}
|
||||
/>
|
||||
{show_badge && (
|
||||
<Link target="_blank" href="https://quiz.pena.digital" sx={{mt: "20px", textAlign: "end"}}>
|
||||
{quizThemes[settings.cfg.theme].isLight ? (
|
||||
<NameplateLogoFQ
|
||||
style={{ fontSize: "34px", width: "200px", height: "auto" }}
|
||||
/>
|
||||
) : (
|
||||
<NameplateLogoFQDark
|
||||
style={{ fontSize: "34px", width: "200px", height: "auto" }}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
height: "100%",
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "transparent"
|
||||
: "linear-gradient(90deg,#272626, transparent)"
|
||||
: theme.palette.background.default,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc(100% - 75px)",
|
||||
overflow: "auto",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc(100% - 75px)",
|
||||
width: "100%",
|
||||
maxWidth: "1440px",
|
||||
padding: "40px 25px 20px",
|
||||
margin: "0 auto",
|
||||
//overflow: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<QuestionByType
|
||||
key={currentQuestion.id}
|
||||
question={currentQuestion}
|
||||
stepNumber={currentQuestionStepNumber}
|
||||
/>
|
||||
{show_badge && (
|
||||
<Link target="_blank" href="https://quiz.pena.digital" sx={{ mt: "20px", textAlign: "end" }}>
|
||||
{quizThemes[settings.cfg.theme].isLight ? (
|
||||
<NameplateLogoFQ
|
||||
style={{ fontSize: "34px", width: "200px", height: "auto" }}
|
||||
/>
|
||||
) : (
|
||||
<NameplateLogoFQDark
|
||||
style={{ fontSize: "34px", width: "200px", height: "auto" }}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Footer
|
||||
stepNumber={currentQuestionStepNumber}
|
||||
prevButton={prevButton}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Footer
|
||||
stepNumber={currentQuestionStepNumber}
|
||||
prevButton={prevButton}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
function QuestionByType({
|
||||
question,
|
||||
stepNumber,
|
||||
question,
|
||||
stepNumber,
|
||||
}: {
|
||||
question: RealTypedQuizQuestion;
|
||||
stepNumber: number | null;
|
||||
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} stepNumber={stepNumber} />;
|
||||
case "select":
|
||||
return <Select currentQuestion={question} />;
|
||||
case "date":
|
||||
return <Date currentQuestion={question} />;
|
||||
case "number":
|
||||
return <Number currentQuestion={question} />;
|
||||
case "file":
|
||||
return <File currentQuestion={question} />;
|
||||
case "page":
|
||||
return <Page currentQuestion={question} />;
|
||||
case "rating":
|
||||
return <Rating currentQuestion={question} />;
|
||||
default:
|
||||
notReachable(question);
|
||||
}
|
||||
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} stepNumber={stepNumber} />;
|
||||
case "select":
|
||||
return <Select currentQuestion={question} />;
|
||||
case "date":
|
||||
return <Date currentQuestion={question} />;
|
||||
case "number":
|
||||
return <Number currentQuestion={question} />;
|
||||
case "file":
|
||||
return <File currentQuestion={question} />;
|
||||
case "page":
|
||||
return <Page currentQuestion={question} />;
|
||||
case "rating":
|
||||
return <Rating currentQuestion={question} />;
|
||||
default:
|
||||
notReachable(question);
|
||||
}
|
||||
}
|
||||
|
@ -5,27 +5,28 @@ import {
|
||||
useTheme
|
||||
} from "@mui/material";
|
||||
|
||||
import {NameplateLogo} from "@icons/NameplateLogo";
|
||||
import { NameplateLogo } from "@icons/NameplateLogo";
|
||||
import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe";
|
||||
|
||||
import {useQuizData} from "@contexts/QuizDataContext";
|
||||
import {quizThemes} from "@utils/themes/Publication/themePublication";
|
||||
import {useRootContainerSize} from "../../contexts/RootContainerWidthContext";
|
||||
import type {QuizQuestionResult} from "../../model/questionTypes/result";
|
||||
import {setCurrentQuizStep} from "@stores/quizView";
|
||||
import {DESIGN_LIST} from "@/components/ViewPublicationPage/Question";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import { useRootContainerSize } from "../../contexts/RootContainerWidthContext";
|
||||
import type { QuizQuestionResult } from "../../model/questionTypes/result";
|
||||
import { useQuizViewStore } from "@/stores/quizView";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
type ResultFormProps = {
|
||||
resultQuestion: QuizQuestionResult;
|
||||
};
|
||||
|
||||
export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const isTablet = useRootContainerSize() < 1000;
|
||||
const {settings, show_badge, quizId} = useQuizData();
|
||||
const spec = settings.cfg.spec
|
||||
console.log(quizThemes[settings.cfg.theme].isLight)
|
||||
const { settings, show_badge, quizId } = useQuizData();
|
||||
const setCurrentQuizStep = useQuizViewStore(state => state.setCurrentQuizStep);
|
||||
const spec = settings.cfg.spec;
|
||||
console.log(quizThemes[settings.cfg.theme].isLight);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -73,15 +74,15 @@ export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
}}
|
||||
>
|
||||
{settings.cfg.startpage.logo &&
|
||||
<img
|
||||
src={settings.cfg.startpage.logo}
|
||||
style={{
|
||||
height: "40px",
|
||||
maxWidth: "110px",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src={settings.cfg.startpage.logo}
|
||||
style={{
|
||||
height: "40px",
|
||||
maxWidth: "110px",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
alt=""
|
||||
/>
|
||||
}
|
||||
<Typography
|
||||
sx={{
|
||||
@ -133,19 +134,19 @@ export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
)
|
||||
}
|
||||
{resultQuestion.description !== "" &&
|
||||
resultQuestion.description !== " " && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "23px",
|
||||
fontWeight: 700,
|
||||
m: "20px 0",
|
||||
color: theme.palette.text.primary,
|
||||
wordBreak: "break-word"
|
||||
}}
|
||||
>
|
||||
{resultQuestion.description}
|
||||
</Typography>
|
||||
)}
|
||||
resultQuestion.description !== " " && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "23px",
|
||||
fontWeight: 700,
|
||||
m: "20px 0",
|
||||
color: theme.palette.text.primary,
|
||||
wordBreak: "break-word"
|
||||
}}
|
||||
>
|
||||
{resultQuestion.description}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Typography
|
||||
sx={{
|
||||
@ -187,37 +188,37 @@ export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
}}
|
||||
>
|
||||
{show_badge &&
|
||||
<Box
|
||||
component={Link}
|
||||
target={"_blank"}
|
||||
href={
|
||||
`https://${window.location.hostname.includes("s") ? "s" : ""}quiz.pena.digital/squiz/quiz/logo?q=${quizId}`
|
||||
}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
mt: "15px",
|
||||
gap: "10px",
|
||||
textDecoration: "none",
|
||||
mb: "15px"
|
||||
}}
|
||||
>
|
||||
<NameplateLogo
|
||||
style={{
|
||||
fontSize: "23px",
|
||||
color: quizThemes[settings.cfg.theme].isLight ? "#000000" : "#F5F7FF",
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
<Box
|
||||
component={Link}
|
||||
target={"_blank"}
|
||||
href={
|
||||
`https://${window.location.hostname.includes("s") ? "s" : ""}quiz.pena.digital/squiz/quiz/logo?q=${quizId}`
|
||||
}
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color: quizThemes[settings.cfg.theme].isLight ? "#4D4D4D" : "#F5F7FF",
|
||||
whiteSpace: "nowrap",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
mt: "15px",
|
||||
gap: "10px",
|
||||
textDecoration: "none",
|
||||
mb: "15px"
|
||||
}}
|
||||
>
|
||||
Сделано на PenaQuiz
|
||||
</Typography>
|
||||
</Box>
|
||||
<NameplateLogo
|
||||
style={{
|
||||
fontSize: "23px",
|
||||
color: quizThemes[settings.cfg.theme].isLight ? "#000000" : "#F5F7FF",
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color: quizThemes[settings.cfg.theme].isLight ? "#4D4D4D" : "#F5F7FF",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
Сделано на PenaQuiz
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
|
||||
</Box>
|
||||
@ -234,16 +235,16 @@ export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
p:
|
||||
(
|
||||
settings.cfg.resultInfo.showResultForm === "before" &&
|
||||
!Boolean(settings.cfg.score)
|
||||
!settings.cfg.score
|
||||
) ||
|
||||
(
|
||||
settings.cfg.resultInfo.showResultForm === "after" &&
|
||||
resultQuestion.content.redirect
|
||||
)
|
||||
(
|
||||
settings.cfg.resultInfo.showResultForm === "after" &&
|
||||
resultQuestion.content.redirect
|
||||
)
|
||||
? "20px" : "0",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.resultInfo.showResultForm === "before" && !Boolean(settings.cfg.score) && (
|
||||
{settings.cfg.resultInfo.showResultForm === "before" && !settings.cfg.score && (
|
||||
<Button
|
||||
onClick={() => setCurrentQuizStep("contactform")}
|
||||
variant="contained"
|
||||
@ -257,15 +258,15 @@ export const ResultForm = ({resultQuestion}: ResultFormProps) => {
|
||||
</Button>
|
||||
)}
|
||||
{settings.cfg.resultInfo.showResultForm === "after" &&
|
||||
resultQuestion.content.redirect && (
|
||||
<Button
|
||||
href={resultQuestion.content.redirect}
|
||||
variant="contained"
|
||||
sx={{p: "10px 20px", width: "auto", height: "50px"}}
|
||||
>
|
||||
{resultQuestion.content.hint.text || "Перейти на сайт"}
|
||||
</Button>
|
||||
)}
|
||||
resultQuestion.content.redirect && (
|
||||
<Button
|
||||
href={resultQuestion.content.redirect}
|
||||
variant="contained"
|
||||
sx={{ p: "10px 20px", width: "auto", height: "50px" }}
|
||||
>
|
||||
{resultQuestion.content.hint.text || "Перейти на сайт"}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -5,209 +5,215 @@ import { useQuizData } from "@contexts/QuizDataContext";
|
||||
|
||||
import { notReachable } from "@utils/notReachable";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import { DESIGN_LIST } from "@/components/ViewPublicationPage/Question";
|
||||
|
||||
import type {
|
||||
QuizStartpageAlignType,
|
||||
QuizStartpageType,
|
||||
QuizStartpageAlignType,
|
||||
QuizStartpageType,
|
||||
} from "@model/settingsData";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
type StartPageDesktopProps = {
|
||||
quizHeaderBlock: JSX.Element;
|
||||
quizMainBlock: JSX.Element;
|
||||
backgroundBlock: JSX.Element | null;
|
||||
startpageType: QuizStartpageType;
|
||||
alignType: QuizStartpageAlignType;
|
||||
quizHeaderBlock: JSX.Element;
|
||||
quizMainBlock: JSX.Element;
|
||||
backgroundBlock: JSX.Element | null;
|
||||
startpageType: QuizStartpageType;
|
||||
alignType: QuizStartpageAlignType;
|
||||
};
|
||||
|
||||
type LayoutProps = Omit<StartPageDesktopProps, "startpageType">;
|
||||
|
||||
const StandartLayout = ({
|
||||
alignType,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
alignType,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
}: LayoutProps) => {
|
||||
const { settings } = useQuizData();
|
||||
const { settings } = useQuizData();
|
||||
|
||||
return (
|
||||
<Box
|
||||
id="pain"
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: alignType === "left" ? "row" : "row-reverse",
|
||||
height: "100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "40%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "flex-start",
|
||||
p: "25px",
|
||||
background:
|
||||
settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "linear-gradient(90deg,#272626,transparent)"
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
{quizHeaderBlock}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
{settings.cfg.startpage.background.desktop && (
|
||||
<Box sx={{ width: "60%", overflow: "hidden" }}>{backgroundBlock}</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
return (
|
||||
<Box
|
||||
id="pain"
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: alignType === "left" ? "row" : "row-reverse",
|
||||
height: "100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "40%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "flex-start",
|
||||
p: "25px",
|
||||
background:
|
||||
settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "linear-gradient(90deg,#272626,transparent)"
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
{quizHeaderBlock}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
{settings.cfg.startpage.background.desktop && (
|
||||
<Box sx={{ width: "60%", overflow: "hidden" }}>{backgroundBlock}</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const ExpandedLayout = ({
|
||||
alignType,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
alignType,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
}: LayoutProps) => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
height: "100%",
|
||||
width: "40%",
|
||||
padding: "16px",
|
||||
margin:
|
||||
alignType === "center"
|
||||
? "0 auto"
|
||||
: alignType === "left"
|
||||
? "0"
|
||||
: "0 0 0 auto",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
padding: "16px",
|
||||
minHeight: "calc(100% - 32px)",
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
alignItems: alignType === "center" ? "center" : "start",
|
||||
borderRight: alignType === "left" ? "1px solid #9A9AAF80" : null,
|
||||
borderLeft: alignType === "right" ? "1px solid #9A9AAF80" : null,
|
||||
}}
|
||||
>
|
||||
{quizHeaderBlock}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
zIndex: -1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{backgroundBlock}
|
||||
</Box>
|
||||
</>
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
height: "100%",
|
||||
width: "40%",
|
||||
padding: "16px",
|
||||
margin:
|
||||
alignType === "center"
|
||||
? "0 auto"
|
||||
: alignType === "left"
|
||||
? "0"
|
||||
: "0 0 0 auto",
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
padding: "16px",
|
||||
minHeight: "calc(100% - 32px)",
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
alignItems: alignType === "center" ? "center" : "start",
|
||||
borderRight: alignType === "left" ? "1px solid #9A9AAF80" : null,
|
||||
borderLeft: alignType === "right" ? "1px solid #9A9AAF80" : null,
|
||||
}}
|
||||
>
|
||||
{quizHeaderBlock}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
zIndex: -1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{backgroundBlock}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
const CenteredLayout = ({
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
}: LayoutProps) => {
|
||||
const isTablet = useRootContainerSize() < 1100;
|
||||
const isTablet = useRootContainerSize() < 1100;
|
||||
const { settings } = useQuizData();
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
overflow: "auto",
|
||||
padding: "10px 25px 25px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
}}
|
||||
>
|
||||
{quizHeaderBlock}
|
||||
{backgroundBlock && settings.cfg.startpage.background.desktop && (
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: "844px",
|
||||
height: isTablet ? "530px" : "306px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
"& > img": { width: "100%", borderRadius: "12px" },
|
||||
}}
|
||||
sx={{
|
||||
overflow: "auto",
|
||||
padding: "10px 25px 25px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundSize: "cover",
|
||||
backgroundImage: settings.cfg.design
|
||||
? `url(${DESIGN_LIST[settings.cfg.theme]})`
|
||||
: null,
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
{backgroundBlock}
|
||||
{quizHeaderBlock}
|
||||
{backgroundBlock && settings.cfg.startpage.background.desktop && (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: "844px",
|
||||
height: isTablet ? "530px" : "306px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
"& > img": { width: "100%", borderRadius: "12px" },
|
||||
}}
|
||||
>
|
||||
{backgroundBlock}
|
||||
</Box>
|
||||
)}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
)}
|
||||
{quizMainBlock}
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export const StartPageDesktop = ({
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
startpageType,
|
||||
alignType,
|
||||
quizHeaderBlock,
|
||||
quizMainBlock,
|
||||
backgroundBlock,
|
||||
startpageType,
|
||||
alignType,
|
||||
}: StartPageDesktopProps) => {
|
||||
switch (startpageType) {
|
||||
case null:
|
||||
case "standard": {
|
||||
return (
|
||||
<StandartLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
switch (startpageType) {
|
||||
case null:
|
||||
case "standard": {
|
||||
return (
|
||||
<StandartLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
case "expanded": {
|
||||
return (
|
||||
<ExpandedLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "expanded": {
|
||||
return (
|
||||
<ExpandedLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
case "centered": {
|
||||
return (
|
||||
<CenteredLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "centered": {
|
||||
return (
|
||||
<CenteredLayout
|
||||
alignType={alignType}
|
||||
quizHeaderBlock={quizHeaderBlock}
|
||||
quizMainBlock={quizMainBlock}
|
||||
backgroundBlock={backgroundBlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
notReachable(startpageType);
|
||||
}
|
||||
default:
|
||||
notReachable(startpageType);
|
||||
}
|
||||
};
|
||||
|
@ -4,9 +4,9 @@ import { useQuizData } from "@contexts/QuizDataContext";
|
||||
|
||||
import { notReachable } from "@utils/notReachable";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import { DESIGN_LIST } from "@/components/ViewPublicationPage/Question";
|
||||
|
||||
import type { QuizStartpageType } from "@model/settingsData";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
type StartPageMobileProps = {
|
||||
quizHeaderBlock: JSX.Element;
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Link,
|
||||
Paper,
|
||||
Typography,
|
||||
useTheme,
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Link,
|
||||
Paper,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
|
||||
import { QuizPreviewLayoutByType } from "./QuizPreviewLayoutByType";
|
||||
@ -13,365 +13,366 @@ import YoutubeEmbedIframe from "../tools/YoutubeEmbedIframe";
|
||||
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||
import { setCurrentQuizStep } from "@stores/quizView";
|
||||
|
||||
import { useUADevice } from "@utils/hooks/useUADevice";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
|
||||
import { DESIGN_LIST } from "../Question";
|
||||
|
||||
import { NameplateLogo } from "@icons/NameplateLogo";
|
||||
import { useQuizViewStore } from "@/stores/quizView";
|
||||
import { DESIGN_LIST } from "@/utils/designList";
|
||||
|
||||
export const StartPageViewPublication = () => {
|
||||
const theme = useTheme();
|
||||
const { settings, show_badge, quizId } = useQuizData();
|
||||
const { isMobileDevice } = useUADevice();
|
||||
const isMobile = useRootContainerSize() < 700;
|
||||
const isTablet = useRootContainerSize() < 800;
|
||||
const theme = useTheme();
|
||||
const { settings, show_badge, quizId } = useQuizData();
|
||||
const { isMobileDevice } = useUADevice();
|
||||
const setCurrentQuizStep = useQuizViewStore(state => state.setCurrentQuizStep);
|
||||
|
||||
const handleCopyNumber = () => {
|
||||
navigator.clipboard.writeText(settings.cfg.info.phonenumber);
|
||||
};
|
||||
const isMobile = useRootContainerSize() < 700;
|
||||
const isTablet = useRootContainerSize() < 800;
|
||||
|
||||
const background =
|
||||
settings.cfg.startpage.background.type === "image" ? (
|
||||
<img
|
||||
src={
|
||||
settings.cfg.startpage.background.desktop ||
|
||||
DESIGN_LIST[settings.cfg.theme] ||
|
||||
""
|
||||
}
|
||||
alt=""
|
||||
style={{
|
||||
display: "block",
|
||||
width:
|
||||
isMobile || settings.cfg.startpageType === "expanded"
|
||||
? "100%"
|
||||
: undefined,
|
||||
height: "100%",
|
||||
minWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
objectFit: "cover",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
/>
|
||||
) : settings.cfg.startpage.background.type === "video" ? (
|
||||
settings.cfg.startpage.background.video ? (
|
||||
<YoutubeEmbedIframe
|
||||
videoUrl={settings.cfg.startpage.background.video}
|
||||
containerSX={{
|
||||
width: settings.cfg.startpageType === "centered" ? "550px" : "100%",
|
||||
height:
|
||||
settings.cfg.startpageType === "centered" ? "275px" : "100%",
|
||||
borderRadius:
|
||||
settings.cfg.startpageType === "centered" ? "10px" : "0",
|
||||
overflow: "hidden",
|
||||
"& iframe": {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
transform:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? ""
|
||||
: settings.cfg.startpageType === "expanded"
|
||||
? "scale(1.5)"
|
||||
: "scale(2.4)",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
) : null;
|
||||
const handleCopyNumber = () => {
|
||||
navigator.clipboard.writeText(settings.cfg.info.phonenumber);
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
className="settings-preview-draghandle"
|
||||
sx={{
|
||||
borderRadius: 0,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
background:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? settings.cfg.startpage.position === "left"
|
||||
? "linear-gradient(90deg,#272626,transparent)"
|
||||
: settings.cfg.startpage.position === "center"
|
||||
? "linear-gradient(180deg,transparent,#272626)"
|
||||
: "linear-gradient(270deg,#272626,transparent)"
|
||||
: theme.palette.background.default,
|
||||
|
||||
color: settings.cfg.startpageType === "expanded" ? "white" : "black",
|
||||
}}
|
||||
>
|
||||
<QuizPreviewLayoutByType
|
||||
quizHeaderBlock={
|
||||
<Box
|
||||
sx={{
|
||||
margin:
|
||||
settings.cfg.startpageType === "centered" ? "0 auto" : null,
|
||||
padding: settings.cfg.startpageType === "standard" ? "" : "16px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
gap: "30px",
|
||||
mb: "7px",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.startpage.logo &&
|
||||
<img
|
||||
src={settings.cfg.startpage.logo}
|
||||
style={{
|
||||
height: "40px",
|
||||
maxWidth: "110px",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
alt=""
|
||||
/>
|
||||
}
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.orgname}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
quizMainBlock={
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
flexGrow: settings.cfg.startpageType === "centered" ? 0 : 1,
|
||||
alignItems:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? "center"
|
||||
: settings.cfg.startpageType === "expanded"
|
||||
? settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "start"
|
||||
: "start",
|
||||
marginTop: "28px",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: "bold",
|
||||
fontSize: "26px",
|
||||
fontStyle: "normal",
|
||||
fontStretch: "normal",
|
||||
lineHeight: "1.2",
|
||||
overflowWrap: "break-word",
|
||||
width: "100%",
|
||||
textAlign:
|
||||
settings.cfg.startpageType === "centered" ||
|
||||
settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "-moz-initial",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.name}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
margin: "16px 0 30px",
|
||||
overflowWrap: "break-word",
|
||||
width: "100%",
|
||||
textAlign:
|
||||
settings.cfg.startpageType === "centered" ||
|
||||
settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "-moz-initial",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.startpage.description}
|
||||
</Typography>
|
||||
<Box
|
||||
width={
|
||||
settings.cfg.startpageType === "standard" ? "100%" : "auto"
|
||||
const background =
|
||||
settings.cfg.startpage.background.type === "image" ? (
|
||||
<img
|
||||
src={
|
||||
settings.cfg.startpage.background.desktop ||
|
||||
DESIGN_LIST[settings.cfg.theme] ||
|
||||
""
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
padding: "10px 30px",
|
||||
width: "auto",
|
||||
background: theme.palette.primary.main,
|
||||
}}
|
||||
onClick={() => setCurrentQuizStep("question")}
|
||||
>
|
||||
{settings.cfg.startpage.button.trim()
|
||||
? settings.cfg.startpage.button
|
||||
: "Пройти тест"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
mt: "46px",
|
||||
display: "flex",
|
||||
flexGrow:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? isMobile
|
||||
? 0
|
||||
: 1
|
||||
: 0,
|
||||
gap: "20px",
|
||||
alignItems: "flex-end",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ maxWidth: "300px" }}>
|
||||
{settings.cfg.info.site && (
|
||||
<Link mb="16px" href={settings.cfg.info.site}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color: theme.palette.primary.main,
|
||||
alt=""
|
||||
style={{
|
||||
display: "block",
|
||||
width:
|
||||
isMobile || settings.cfg.startpageType === "expanded"
|
||||
? "100%"
|
||||
: undefined,
|
||||
height: "100%",
|
||||
minWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
objectFit: "cover",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
/>
|
||||
) : settings.cfg.startpage.background.type === "video" ? (
|
||||
settings.cfg.startpage.background.video ? (
|
||||
<YoutubeEmbedIframe
|
||||
videoUrl={settings.cfg.startpage.background.video}
|
||||
containerSX={{
|
||||
width: settings.cfg.startpageType === "centered" ? "550px" : "100%",
|
||||
height:
|
||||
settings.cfg.startpageType === "centered" ? "275px" : "100%",
|
||||
borderRadius:
|
||||
settings.cfg.startpageType === "centered" ? "10px" : "0",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: isTablet ? "200px" : "300px",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.site}
|
||||
</Typography>
|
||||
</Link>
|
||||
)}
|
||||
{settings.cfg.info.clickable ? (
|
||||
isMobileDevice ? (
|
||||
<Link href={`tel:${settings.cfg.info.phonenumber}`}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
</Link>
|
||||
) : (
|
||||
<ButtonBase onClick={handleCopyNumber}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
)
|
||||
) : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
marginTop: "5px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
"& iframe": {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
transform:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? ""
|
||||
: settings.cfg.startpageType === "expanded"
|
||||
? "scale(1.5)"
|
||||
: "scale(2.4)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflowWrap: "break-word",
|
||||
fontSize: "12px",
|
||||
maxHeight: "120px",
|
||||
overflow: "auto",
|
||||
marginTop: "5px",
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.law}
|
||||
</Typography>
|
||||
</Box>
|
||||
/>
|
||||
) : null
|
||||
) : null;
|
||||
|
||||
{show_badge && (
|
||||
<Box
|
||||
component={Link}
|
||||
target={"_blank"}
|
||||
href={
|
||||
`https://${window.location.hostname.includes("s") ? "s" : ""}quiz.pena.digital/squiz/quiz/logo?q=${quizId}`
|
||||
}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "15px",
|
||||
textDecoration: "none",
|
||||
}}
|
||||
>
|
||||
<NameplateLogo
|
||||
style={{
|
||||
fontSize: "23px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "#151515"
|
||||
: "#FFFFFF",
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#F5F7FF"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "#4D4D4D"
|
||||
: "#F5F7FF",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
Сделано на PenaQuiz
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
}
|
||||
backgroundBlock={background}
|
||||
startpageType={settings.cfg.startpageType}
|
||||
alignType={settings.cfg.startpage.position}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
return (
|
||||
<Paper
|
||||
className="settings-preview-draghandle"
|
||||
sx={{
|
||||
borderRadius: 0,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
background:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? settings.cfg.startpage.position === "left"
|
||||
? "linear-gradient(90deg,#272626,transparent)"
|
||||
: settings.cfg.startpage.position === "center"
|
||||
? "linear-gradient(180deg,transparent,#272626)"
|
||||
: "linear-gradient(270deg,#272626,transparent)"
|
||||
: theme.palette.background.default,
|
||||
|
||||
color: settings.cfg.startpageType === "expanded" ? "white" : "black",
|
||||
}}
|
||||
>
|
||||
<QuizPreviewLayoutByType
|
||||
quizHeaderBlock={
|
||||
<Box
|
||||
sx={{
|
||||
margin:
|
||||
settings.cfg.startpageType === "centered" ? "0 auto" : null,
|
||||
padding: settings.cfg.startpageType === "standard" ? "" : "16px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
gap: "30px",
|
||||
mb: "7px",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.startpage.logo &&
|
||||
<img
|
||||
src={settings.cfg.startpage.logo}
|
||||
style={{
|
||||
height: "40px",
|
||||
maxWidth: "110px",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
alt=""
|
||||
/>
|
||||
}
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.orgname}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
quizMainBlock={
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
flexGrow: settings.cfg.startpageType === "centered" ? 0 : 1,
|
||||
alignItems:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? "center"
|
||||
: settings.cfg.startpageType === "expanded"
|
||||
? settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "start"
|
||||
: "start",
|
||||
marginTop: "28px",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: "bold",
|
||||
fontSize: "26px",
|
||||
fontStyle: "normal",
|
||||
fontStretch: "normal",
|
||||
lineHeight: "1.2",
|
||||
overflowWrap: "break-word",
|
||||
width: "100%",
|
||||
textAlign:
|
||||
settings.cfg.startpageType === "centered" ||
|
||||
settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "-moz-initial",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.name}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
margin: "16px 0 30px",
|
||||
overflowWrap: "break-word",
|
||||
width: "100%",
|
||||
textAlign:
|
||||
settings.cfg.startpageType === "centered" ||
|
||||
settings.cfg.startpage.position === "center"
|
||||
? "center"
|
||||
: "-moz-initial",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.startpage.description}
|
||||
</Typography>
|
||||
<Box
|
||||
width={
|
||||
settings.cfg.startpageType === "standard" ? "100%" : "auto"
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
padding: "10px 30px",
|
||||
width: "auto",
|
||||
background: theme.palette.primary.main,
|
||||
}}
|
||||
onClick={() => setCurrentQuizStep("question")}
|
||||
>
|
||||
{settings.cfg.startpage.button.trim()
|
||||
? settings.cfg.startpage.button
|
||||
: "Пройти тест"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
mt: "46px",
|
||||
display: "flex",
|
||||
flexGrow:
|
||||
settings.cfg.startpageType === "centered"
|
||||
? isMobile
|
||||
? 0
|
||||
: 1
|
||||
: 0,
|
||||
gap: "20px",
|
||||
alignItems: "flex-end",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ maxWidth: "300px" }}>
|
||||
{settings.cfg.info.site && (
|
||||
<Link mb="16px" href={settings.cfg.info.site}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color: theme.palette.primary.main,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: isTablet ? "200px" : "300px",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.site}
|
||||
</Typography>
|
||||
</Link>
|
||||
)}
|
||||
{settings.cfg.info.clickable ? (
|
||||
isMobileDevice ? (
|
||||
<Link href={`tel:${settings.cfg.info.phonenumber}`}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
</Link>
|
||||
) : (
|
||||
<ButtonBase onClick={handleCopyNumber}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
)
|
||||
) : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
marginTop: "5px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.phonenumber}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflowWrap: "break-word",
|
||||
fontSize: "12px",
|
||||
maxHeight: "120px",
|
||||
overflow: "auto",
|
||||
marginTop: "5px",
|
||||
"&::-webkit-scrollbar": { width: 0 },
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "white"
|
||||
: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{settings.cfg.info.law}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{show_badge && (
|
||||
<Box
|
||||
component={Link}
|
||||
target={"_blank"}
|
||||
href={
|
||||
`https://${window.location.hostname.includes("s") ? "s" : ""}quiz.pena.digital/squiz/quiz/logo?q=${quizId}`
|
||||
}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "15px",
|
||||
textDecoration: "none",
|
||||
}}
|
||||
>
|
||||
<NameplateLogo
|
||||
style={{
|
||||
fontSize: "23px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#FFFFFF"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "#151515"
|
||||
: "#FFFFFF",
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color:
|
||||
settings.cfg.startpageType === "expanded"
|
||||
? "#F5F7FF"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "#4D4D4D"
|
||||
: "#F5F7FF",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
Сделано на PenaQuiz
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
}
|
||||
backgroundBlock={background}
|
||||
startpageType={settings.cfg.startpageType}
|
||||
alignType={settings.cfg.startpage.position}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ import PrevButton from "./tools/PrevButton";
|
||||
|
||||
export default function ViewPublicationPage() {
|
||||
const { settings, recentlyCompleted, quizId, preview } = useQuizData();
|
||||
const { answers } = useQuizViewStore();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
let currentQuizStep = useQuizViewStore((state) => state.currentQuizStep);
|
||||
const {
|
||||
currentQuestion,
|
||||
|
@ -2,8 +2,6 @@ import moment from "moment";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { Box, Typography, useTheme } from "@mui/material";
|
||||
|
||||
import { useQuizViewStore, updateAnswer } from "@stores/quizView";
|
||||
|
||||
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
||||
import CalendarIcon from "@icons/CalendarIcon";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
@ -12,105 +10,107 @@ import { sendAnswer } from "@api/quizRelase";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import { useState } from "react";
|
||||
import { useQuizViewStore } from "@/stores/quizView";
|
||||
|
||||
type DateProps = {
|
||||
currentQuestion: QuizQuestionDate;
|
||||
currentQuestion: QuizQuestionDate;
|
||||
};
|
||||
|
||||
export const Date = ({ currentQuestion }: DateProps) => {
|
||||
const theme = useTheme();
|
||||
const { settings, quizId, preview } = 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, preview } = useQuizData();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
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
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
<DatePicker
|
||||
format="DD/MM/YYYY"
|
||||
slots={{
|
||||
openPickerIcon: () => (
|
||||
<CalendarIcon
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
{currentQuestion.title}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
"& path": { stroke: theme.palette.primary.main },
|
||||
"& rect": { stroke: theme.palette.primary.main },
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
value={currentAnswer}
|
||||
onChange={async (date) => {
|
||||
if (isSending || !date) return;
|
||||
>
|
||||
<DatePicker
|
||||
format="DD/MM/YYYY"
|
||||
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;
|
||||
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: moment(date).format("YYYY.MM.DD"),
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: moment(date).format("YYYY.MM.DD"),
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
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: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(154,154,175, 0.2)"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderRadius: "10px",
|
||||
maxWidth: "250px",
|
||||
pr: "30px",
|
||||
"& 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
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(154,154,175, 0.2)"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderRadius: "10px",
|
||||
maxWidth: "250px",
|
||||
pr: "30px",
|
||||
"& input": {
|
||||
py: "11px",
|
||||
pl: "20px",
|
||||
lineHeight: "19px",
|
||||
},
|
||||
"& fieldset": {
|
||||
borderColor: "#9A9AAF",
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {
|
||||
Box,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
Box,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
|
||||
import { deleteAnswer, updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
@ -25,195 +25,196 @@ polyfillCountryFlagEmojis();
|
||||
import { useState } from "react";
|
||||
|
||||
type EmojiProps = {
|
||||
currentQuestion: QuizQuestionEmoji;
|
||||
currentQuestion: QuizQuestionEmoji;
|
||||
};
|
||||
|
||||
export const Emoji = ({ currentQuestion }: EmojiProps) => {
|
||||
const theme = useTheme();
|
||||
const { quizId, settings, preview } = useQuizData();
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } =
|
||||
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const theme = useTheme();
|
||||
const { quizId, settings, preview } = useQuizData();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
{currentQuestion.title}
|
||||
</Typography>
|
||||
<RadioGroup
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(
|
||||
({ id }) => answer === id
|
||||
)}
|
||||
onChange={({ target }) => {
|
||||
updateAnswer(
|
||||
currentQuestion.id,
|
||||
currentQuestion.content.variants[Number(target.value)].answer,
|
||||
currentQuestion.content.variants[Number(target.value)].points || 0
|
||||
);
|
||||
}}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{ display: "flex", width: "100%", gap: "42px", flexWrap: "wrap" }}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<FormControl
|
||||
key={index}
|
||||
disabled={isSending}
|
||||
sx={{
|
||||
borderRadius: "12px",
|
||||
border: `1px solid`,
|
||||
borderColor:
|
||||
answer === variant.id
|
||||
? theme.palette.primary.main
|
||||
: "#9A9AAF",
|
||||
overflow: "hidden",
|
||||
maxWidth: "317px",
|
||||
width: "100%",
|
||||
height: "255px",
|
||||
background: settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "rgba(255,255,255, 0.3)" : settings.cfg.design && quizThemes[settings.cfg.theme].isLight || quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "transparent",
|
||||
"&:hover": {borderColor: theme.palette.primary.main},
|
||||
}}
|
||||
// value={index}
|
||||
onClick={async (event) => {
|
||||
event.preventDefault();
|
||||
if (isSending) return;
|
||||
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body:
|
||||
currentQuestion.content.variants[index].extendedText +
|
||||
" " +
|
||||
currentQuestion.content.variants[index].answer,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
height: "193px",
|
||||
background: "#ffffff",
|
||||
cursor: "pointer"
|
||||
{currentQuestion.title}
|
||||
</Typography>
|
||||
<RadioGroup
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(
|
||||
({ id }) => answer === id
|
||||
)}
|
||||
onChange={({ target }) => {
|
||||
updateAnswer(
|
||||
currentQuestion.id,
|
||||
currentQuestion.content.variants[Number(target.value)].answer,
|
||||
currentQuestion.content.variants[Number(target.value)].points || 0
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{variant.extendedText && (
|
||||
<Typography fontSize={"100px"}>
|
||||
{variant.extendedText}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
sx={{
|
||||
margin: 0,
|
||||
padding: "15px",
|
||||
color: theme.palette.text.primary,
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems:
|
||||
variant.answer.length <= 60 ? "center" : "flex-start",
|
||||
position: "relative",
|
||||
height: "80px",
|
||||
"& .MuiFormControlLabel-label": {
|
||||
wordBreak: "break-word",
|
||||
height: variant.answer.length <= 60 ? undefined : "60px",
|
||||
overflow: "auto",
|
||||
paddingLeft: "45px",
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "4px",
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "#b8babf",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
value={index}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
<RadioCheck color={theme.palette.primary.main} />
|
||||
}
|
||||
icon={<RadioIcon />}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "-162px",
|
||||
right: "12px",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Box sx={{ display: "flex", gap: "10px" }}>
|
||||
<Typography
|
||||
sx={{
|
||||
wordBreak: "break-word",
|
||||
lineHeight: "normal",
|
||||
}}
|
||||
>
|
||||
{variant.answer}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
))}
|
||||
>
|
||||
<Box
|
||||
sx={{ display: "flex", width: "100%", gap: "42px", flexWrap: "wrap" }}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<FormControl
|
||||
key={index}
|
||||
disabled={isSending}
|
||||
sx={{
|
||||
borderRadius: "12px",
|
||||
border: `1px solid`,
|
||||
borderColor:
|
||||
answer === variant.id
|
||||
? theme.palette.primary.main
|
||||
: "#9A9AAF",
|
||||
overflow: "hidden",
|
||||
maxWidth: "317px",
|
||||
width: "100%",
|
||||
height: "255px",
|
||||
background: settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "rgba(255,255,255, 0.3)" : settings.cfg.design && quizThemes[settings.cfg.theme].isLight || quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "transparent",
|
||||
"&:hover": { borderColor: theme.palette.primary.main },
|
||||
}}
|
||||
// value={index}
|
||||
onClick={async (event) => {
|
||||
event.preventDefault();
|
||||
if (isSending) return;
|
||||
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body:
|
||||
currentQuestion.content.variants[index].extendedText +
|
||||
" " +
|
||||
currentQuestion.content.variants[index].answer,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
height: "193px",
|
||||
background: "#ffffff",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{variant.extendedText && (
|
||||
<Typography fontSize={"100px"}>
|
||||
{variant.extendedText}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
sx={{
|
||||
margin: 0,
|
||||
padding: "15px",
|
||||
color: theme.palette.text.primary,
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems:
|
||||
variant.answer.length <= 60 ? "center" : "flex-start",
|
||||
position: "relative",
|
||||
height: "80px",
|
||||
"& .MuiFormControlLabel-label": {
|
||||
wordBreak: "break-word",
|
||||
height: variant.answer.length <= 60 ? undefined : "60px",
|
||||
overflow: "auto",
|
||||
paddingLeft: "45px",
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "4px",
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "#b8babf",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
}}
|
||||
value={index}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
<RadioCheck color={theme.palette.primary.main} />
|
||||
}
|
||||
icon={<RadioIcon />}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "-162px",
|
||||
right: "12px",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Box sx={{ display: "flex", gap: "10px" }}>
|
||||
<Typography
|
||||
sx={{
|
||||
wordBreak: "break-word",
|
||||
lineHeight: "normal",
|
||||
}}
|
||||
>
|
||||
{variant.answer}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
))}
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
Typography,
|
||||
useTheme
|
||||
} from "@mui/material";
|
||||
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import CloseBold from "@icons/CloseBold";
|
||||
import UploadIcon from "@icons/UploadIcon";
|
||||
@ -29,7 +29,8 @@ type FileProps = {
|
||||
|
||||
export const File = ({ currentQuestion }: FileProps) => {
|
||||
const theme = useTheme();
|
||||
const { answers } = useQuizViewStore();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
const { quizId, preview } = useQuizData();
|
||||
const [modalWarningType, setModalWarningType] = useState<ModalWarningType>(null);
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
@ -43,8 +44,8 @@ export const File = ({ currentQuestion }: FileProps) => {
|
||||
const uploadFile = async (file: File | undefined) => {
|
||||
if (isSending) return;
|
||||
if (!file) return;
|
||||
console.log(file.size)
|
||||
console.log(MAX_FILE_SIZE)
|
||||
console.log(file.size);
|
||||
console.log(MAX_FILE_SIZE);
|
||||
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
|
||||
|
||||
const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].some(
|
||||
|
@ -1,13 +1,13 @@
|
||||
import {
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
|
||||
import { deleteAnswer, updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
|
||||
@ -20,174 +20,176 @@ import { useState } from "react";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
|
||||
type ImagesProps = {
|
||||
currentQuestion: QuizQuestionImages;
|
||||
currentQuestion: QuizQuestionImages;
|
||||
};
|
||||
|
||||
export const Images = ({ currentQuestion }: ImagesProps) => {
|
||||
const { quizId, preview } = useQuizData();
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const answer = answers.find(
|
||||
({ questionId }) => questionId === currentQuestion.id
|
||||
)?.answer;
|
||||
const { settings } = useQuizData();
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const isTablet = useRootContainerSize() < 1000;
|
||||
const isMobile = useRootContainerSize() < 500;
|
||||
const { quizId, preview } = useQuizData();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
const theme = useTheme();
|
||||
const answer = answers.find(
|
||||
({ questionId }) => questionId === currentQuestion.id
|
||||
)?.answer;
|
||||
const { settings } = useQuizData();
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const isTablet = useRootContainerSize() < 1000;
|
||||
const isMobile = useRootContainerSize() < 500;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
{currentQuestion.title}
|
||||
</Typography>
|
||||
<RadioGroup
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(
|
||||
({ id }) => answer === id
|
||||
)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gap: "15px",
|
||||
gridTemplateColumns: isTablet
|
||||
? isMobile
|
||||
? "repeat(1, 1fr)"
|
||||
: "repeat(2, 1fr)"
|
||||
: "repeat(3, 1fr)",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
borderRadius: "12px",
|
||||
border: `1px solid`,
|
||||
borderColor:
|
||||
answer === variant.id
|
||||
? theme.palette.primary.main
|
||||
: "#9A9AAF",
|
||||
"&:hover": {borderColor: theme.palette.primary.main},
|
||||
background: settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "rgba(255,255,255, 0.3)" : settings.cfg.design && quizThemes[settings.cfg.theme].isLight || quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "transparent",
|
||||
}}
|
||||
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,
|
||||
preview
|
||||
});
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Box sx={{ width: "100%", height: "300px" }}>
|
||||
{variant.extendedText && (
|
||||
<img
|
||||
src={variant.extendedText}
|
||||
alt=""
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
borderRadius: "12px 12px 0 0"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
{currentQuestion.title}
|
||||
</Typography>
|
||||
<RadioGroup
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(
|
||||
({ id }) => answer === id
|
||||
)}
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
color: theme.palette.text.primary,
|
||||
marginTop: "10px",
|
||||
marginLeft: 0,
|
||||
padding: "10px",
|
||||
display: "flex",
|
||||
alignItems:
|
||||
variant.answer.length <= 60 ? "center" : "flex-start",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
height: "80px",
|
||||
"& .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",
|
||||
},
|
||||
},
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
value={index}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
<RadioCheck color={theme.palette.primary.main} />
|
||||
}
|
||||
icon={<RadioIcon />}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "-297px",
|
||||
right: 0
|
||||
display: "grid",
|
||||
gap: "15px",
|
||||
gridTemplateColumns: isTablet
|
||||
? isMobile
|
||||
? "repeat(1, 1fr)"
|
||||
: "repeat(2, 1fr)"
|
||||
: "repeat(3, 1fr)",
|
||||
width: "100%",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={variant.answer}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
borderRadius: "12px",
|
||||
border: `1px solid`,
|
||||
borderColor:
|
||||
answer === variant.id
|
||||
? theme.palette.primary.main
|
||||
: "#9A9AAF",
|
||||
"&:hover": { borderColor: theme.palette.primary.main },
|
||||
background: settings.cfg.design && !quizThemes[settings.cfg.theme].isLight
|
||||
? "rgba(255,255,255, 0.3)" : settings.cfg.design && quizThemes[settings.cfg.theme].isLight || quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "transparent",
|
||||
}}
|
||||
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,
|
||||
preview
|
||||
});
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Box sx={{ width: "100%", height: "300px" }}>
|
||||
{variant.extendedText && (
|
||||
<img
|
||||
src={variant.extendedText}
|
||||
alt=""
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
borderRadius: "12px 12px 0 0"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
color: theme.palette.text.primary,
|
||||
marginTop: "10px",
|
||||
marginLeft: 0,
|
||||
padding: "10px",
|
||||
display: "flex",
|
||||
alignItems:
|
||||
variant.answer.length <= 60 ? "center" : "flex-start",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
height: "80px",
|
||||
"& .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}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
<RadioCheck color={theme.palette.primary.main} />
|
||||
}
|
||||
icon={<RadioIcon />}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "-297px",
|
||||
right: 0
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={variant.answer}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import { useDebouncedCallback } from "use-debounce";
|
||||
import { CustomSlider } from "@ui_kit/CustomSlider";
|
||||
import CustomTextField from "@ui_kit/CustomTextField";
|
||||
|
||||
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import { sendAnswer } from "@api/quizRelase";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
@ -18,458 +18,460 @@ 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, preview } = 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, preview } = 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(state => state.answers);
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
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;
|
||||
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]);
|
||||
useEffect(() => {
|
||||
console.log("reversed:", reversed);
|
||||
}, [reversed]);
|
||||
|
||||
const sendAnswerToBackend = async (value: string, noUpdate = false) => {
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: value,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
const sendAnswerToBackend = async (value: string, noUpdate = false) => {
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: value,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
if (!noUpdate) {
|
||||
updateAnswer(currentQuestion.id, value, 0);
|
||||
}
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
|
||||
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) {
|
||||
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]);
|
||||
if (!noUpdate) {
|
||||
updateAnswer(currentQuestion.id, value, 0);
|
||||
}
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
} else {
|
||||
|
||||
setIsSending(false);
|
||||
};
|
||||
|
||||
const updateValueDebounced = useDebouncedCallback(async (value: string) => {
|
||||
if (reversed) {
|
||||
setReversedInputValue(String(max + min - window.Number(answer)));
|
||||
} else {
|
||||
setInputValue(answer);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!answer) {
|
||||
setMinRange(String(currentQuestion.content.start));
|
||||
setMaxRange(String(max));
|
||||
const newValue =
|
||||
window.Number(value) < window.Number(minRange)
|
||||
? minRange
|
||||
: window.Number(value) > window.Number(maxRange)
|
||||
? maxRange
|
||||
: value;
|
||||
|
||||
if (currentQuestion.content.chooseRange) {
|
||||
setReversedMinRange(String(currentQuestion.content.start));
|
||||
setReversedMaxRange(String(min));
|
||||
}
|
||||
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]);
|
||||
|
||||
setReversedInputValue(String(currentQuestion.content.start));
|
||||
setInputValue(String(currentQuestion.content.start));
|
||||
}
|
||||
}, []);
|
||||
const newMinValue =
|
||||
window.Number(value.split("—")[0]) > max
|
||||
? String(max)
|
||||
: value.split("—")[0];
|
||||
|
||||
const onSliderChange = (_: Event, value: number | number[]) => {
|
||||
const range = Array.isArray(value)
|
||||
? `${value[0]}—${value[1]}`
|
||||
: String(value);
|
||||
setReversedMinRange(
|
||||
crowded ? String(max + min - window.Number(newMinValue)) : newMinValue
|
||||
);
|
||||
updateAnswer(
|
||||
currentQuestion.id,
|
||||
`${newMinRange}—${value.split("—")[1]}`,
|
||||
0
|
||||
);
|
||||
await sendAnswerToBackend(
|
||||
`${newMinValue}—${value.split("—")[1]}`,
|
||||
true
|
||||
);
|
||||
|
||||
updateAnswer(currentQuestion.id, range, 0);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
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]);
|
||||
const newMinValue = crowded
|
||||
? maxRange
|
||||
: window.Number(value.split("—")[0]) < min
|
||||
? String(min)
|
||||
: value.split("—")[0];
|
||||
|
||||
setMinRange(String(value[0]));
|
||||
setMaxRange(String(value[1]));
|
||||
setReversedMinRange(newMinReversedValue);
|
||||
setReversedMaxRange(newMaxReversedValue);
|
||||
await sendAnswerToBackend(
|
||||
`${newMinReversedValue}—${newMaxReversedValue}`,
|
||||
true
|
||||
);
|
||||
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]);
|
||||
|
||||
return;
|
||||
}
|
||||
const newMaxValue =
|
||||
window.Number(value.split("—")[1]) < min
|
||||
? String(min)
|
||||
: value.split("—")[1];
|
||||
|
||||
setMinRange(String(value[0]));
|
||||
setMaxRange(String(value[1]));
|
||||
await sendAnswerToBackend(`${value[0]}—${value[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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (reversed) {
|
||||
setReversedInputValue(String(max + min - window.Number(value)));
|
||||
} else {
|
||||
setInputValue(String(value));
|
||||
}
|
||||
const newMaxValue = crowded
|
||||
? minRange
|
||||
: window.Number(value.split("—")[1]) > max
|
||||
? String(max)
|
||||
: value.split("—")[1];
|
||||
|
||||
await sendAnswerToBackend(String(value));
|
||||
};
|
||||
setMaxRange(newMaxValue);
|
||||
await sendAnswerToBackend(`${value.split("—")[0]}—${newMaxValue}`);
|
||||
},
|
||||
1000
|
||||
);
|
||||
const answer = answers.find(
|
||||
({ questionId }) => questionId === currentQuestion.id
|
||||
)?.answer as string;
|
||||
|
||||
const changeValueLabelFormat = (value: number) => {
|
||||
if (!reversed) {
|
||||
return value;
|
||||
}
|
||||
const sliderValue =
|
||||
answer ||
|
||||
(reversed
|
||||
? max + min - currentQuestion.content.start + "—" + max
|
||||
: currentQuestion.content.start + "—" + max);
|
||||
|
||||
const [minSliderBorder, maxSliderBorder] = sliderValue
|
||||
.split("—")
|
||||
.map(window.Number);
|
||||
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 (value === minSliderBorder) {
|
||||
return max + min - minSliderBorder;
|
||||
}
|
||||
if (!answer) {
|
||||
setMinRange(String(currentQuestion.content.start));
|
||||
setMaxRange(String(max));
|
||||
|
||||
return max + min - maxSliderBorder;
|
||||
};
|
||||
if (currentQuestion.content.chooseRange) {
|
||||
setReversedMinRange(String(currentQuestion.content.start));
|
||||
setReversedMaxRange(String(min));
|
||||
}
|
||||
|
||||
const onInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = target.value.replace(/\D/g, "");
|
||||
setReversedInputValue(String(currentQuestion.content.start));
|
||||
setInputValue(String(currentQuestion.content.start));
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (reversed) {
|
||||
setReversedInputValue(value);
|
||||
} else {
|
||||
setInputValue(value);
|
||||
}
|
||||
const onSliderChange = (_: Event, value: number | number[]) => {
|
||||
const range = Array.isArray(value)
|
||||
? `${value[0]}—${value[1]}`
|
||||
: String(value);
|
||||
|
||||
updateValueDebounced(value);
|
||||
};
|
||||
updateAnswer(currentQuestion.id, range, 0);
|
||||
};
|
||||
|
||||
const onMinInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = target.value.replace(/\D/g, "");
|
||||
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]);
|
||||
|
||||
if (reversed) {
|
||||
setReversedMinRange(newValue);
|
||||
setMinRange(String(value[0]));
|
||||
setMaxRange(String(value[1]));
|
||||
setReversedMinRange(newMinReversedValue);
|
||||
setReversedMaxRange(newMaxReversedValue);
|
||||
await sendAnswerToBackend(
|
||||
`${newMinReversedValue}—${newMaxReversedValue}`,
|
||||
true
|
||||
);
|
||||
|
||||
if (window.Number(newValue) <= window.Number(reversedMaxRange)) {
|
||||
const value = max + min - window.Number(reversedMaxRange);
|
||||
updateMinRangeDebounced(`${value}—${value}`, true);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
setMinRange(String(value[0]));
|
||||
setMaxRange(String(value[1]));
|
||||
await sendAnswerToBackend(`${value[0]}—${value[1]}`);
|
||||
|
||||
updateMinRangeDebounced(
|
||||
`${newValue}—${max + min - window.Number(reversedMaxRange)}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (reversed) {
|
||||
setReversedInputValue(String(max + min - window.Number(value)));
|
||||
} else {
|
||||
setInputValue(String(value));
|
||||
}
|
||||
|
||||
setMinRange(newValue);
|
||||
await sendAnswerToBackend(String(value));
|
||||
};
|
||||
|
||||
if (window.Number(newValue) >= window.Number(maxRange)) {
|
||||
updateMinRangeDebounced(`${maxRange}—${maxRange}`, true);
|
||||
const changeValueLabelFormat = (value: number) => {
|
||||
if (!reversed) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
const [minSliderBorder, maxSliderBorder] = sliderValue
|
||||
.split("—")
|
||||
.map(window.Number);
|
||||
|
||||
updateMinRangeDebounced(`${newValue}—${maxRange}`);
|
||||
};
|
||||
if (value === minSliderBorder) {
|
||||
return max + min - minSliderBorder;
|
||||
}
|
||||
|
||||
const onMaxInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = target.value.replace(/\D/g, "");
|
||||
return max + min - maxSliderBorder;
|
||||
};
|
||||
|
||||
if (reversed) {
|
||||
setReversedMaxRange(newValue);
|
||||
const onInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = target.value.replace(/\D/g, "");
|
||||
|
||||
if (window.Number(newValue) >= window.Number(reversedMinRange)) {
|
||||
const value = max + min - window.Number(reversedMinRange);
|
||||
updateMaxRangeDebounced(`${value}—${value}`, true);
|
||||
if (reversed) {
|
||||
setReversedInputValue(value);
|
||||
} else {
|
||||
setInputValue(value);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
updateValueDebounced(value);
|
||||
};
|
||||
|
||||
updateMaxRangeDebounced(
|
||||
`${max + min - window.Number(reversedMinRange)}—${newValue}`
|
||||
);
|
||||
const onMinInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = target.value.replace(/\D/g, "");
|
||||
|
||||
return;
|
||||
}
|
||||
if (reversed) {
|
||||
setReversedMinRange(newValue);
|
||||
|
||||
setMaxRange(newValue);
|
||||
if (window.Number(newValue) <= window.Number(reversedMaxRange)) {
|
||||
const value = max + min - window.Number(reversedMaxRange);
|
||||
updateMinRangeDebounced(`${value}—${value}`, true);
|
||||
|
||||
if (window.Number(newValue) <= window.Number(minRange)) {
|
||||
updateMaxRangeDebounced(`${minRange}—${minRange}`, true);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
updateMinRangeDebounced(
|
||||
`${newValue}—${max + min - window.Number(reversedMaxRange)}`
|
||||
);
|
||||
|
||||
updateMaxRangeDebounced(`${minRange}—${newValue}`);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
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",
|
||||
padding: "0 30px",
|
||||
}}
|
||||
>
|
||||
<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,
|
||||
borderRadius: "8px",
|
||||
minWidth: "60px",
|
||||
height: "36px"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
setMinRange(newValue);
|
||||
|
||||
{!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: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
if (window.Number(newValue) >= window.Number(maxRange)) {
|
||||
updateMinRangeDebounced(`${maxRange}—${maxRange}`, true);
|
||||
|
||||
{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: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography color={theme.palette.text.primary}>до</Typography>
|
||||
<CustomTextField
|
||||
placeholder="0"
|
||||
value={reversed ? String(reversedMaxRange) : maxRange}
|
||||
onChange={onMaxInputChange}
|
||||
sx={{
|
||||
maxWidth: "80px",
|
||||
"& .MuiOutlinedInput-root": { background: "transparent" },
|
||||
"& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
backgroundColor: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
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",
|
||||
padding: "0 30px",
|
||||
}}
|
||||
>
|
||||
<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,
|
||||
borderRadius: "8px",
|
||||
minWidth: "60px",
|
||||
height: "36px"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
{!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: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{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: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography color={theme.palette.text.primary}>до</Typography>
|
||||
<CustomTextField
|
||||
placeholder="0"
|
||||
value={reversed ? String(reversedMaxRange) : maxRange}
|
||||
onChange={onMaxInputChange}
|
||||
sx={{
|
||||
maxWidth: "80px",
|
||||
"& .MuiOutlinedInput-root": { background: "transparent" },
|
||||
"& .MuiInputBase-input": { textAlign: "center", zIndex: 1 },
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
backgroundColor: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
useTheme
|
||||
} from "@mui/material";
|
||||
|
||||
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import FlagIcon from "@icons/questionsPage/FlagIcon";
|
||||
import StarIconMini from "@icons/questionsPage/StarIconMini";
|
||||
@ -59,7 +59,8 @@ const buttonRatingForm = [
|
||||
|
||||
export const Rating = ({ currentQuestion }: RatingProps) => {
|
||||
const { quizId, preview } = useQuizData();
|
||||
const { answers } = useQuizViewStore();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const isTablet = useRootContainerSize() < 750;
|
||||
@ -117,7 +118,7 @@ export const Rating = ({ currentQuestion }: RatingProps) => {
|
||||
height: "50px",
|
||||
gap: isMobile ? undefined : "15px",
|
||||
opacity: "1!important",
|
||||
"& .MuiRating-root.Mui-disabled": {opacity: "1!important"}
|
||||
"& .MuiRating-root.Mui-disabled": { opacity: "1!important" }
|
||||
}}
|
||||
max={currentQuestion.content.steps}
|
||||
icon={form?.icon(theme.palette.primary.main, isMobile ? 30 : isTablet ? 40 : 50)}
|
||||
|
@ -2,7 +2,7 @@ import { Box, Typography, useTheme } from "@mui/material";
|
||||
|
||||
import { Select as SelectComponent } from "../tools//Select";
|
||||
|
||||
import { deleteAnswer, updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import { sendAnswer } from "@api/quizRelase";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
@ -12,86 +12,88 @@ import { useState } from "react";
|
||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||
|
||||
type SelectProps = {
|
||||
currentQuestion: QuizQuestionSelect;
|
||||
currentQuestion: QuizQuestionSelect;
|
||||
};
|
||||
|
||||
export const Select = ({ currentQuestion }: SelectProps) => {
|
||||
const theme = useTheme();
|
||||
const { quizId, settings, preview } = useQuizData();
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } =
|
||||
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
const theme = useTheme();
|
||||
const { quizId, settings, preview } = useQuizData();
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
const { answer } =
|
||||
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
|
||||
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",
|
||||
}}
|
||||
>
|
||||
<SelectComponent
|
||||
disabled={isSending}
|
||||
placeholder={currentQuestion.content.default}
|
||||
activeItemIndex={answer ? Number(answer) : -1}
|
||||
items={currentQuestion.content.variants.map(({ answer }) => answer)}
|
||||
colorMain={theme.palette.primary.main}
|
||||
sx={{
|
||||
"& .MuiSelect-select.MuiSelect-outlined": { zIndex: 1 },
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: "transparent",
|
||||
},
|
||||
}}
|
||||
onChange={async (_, value) => {
|
||||
setIsSending(true);
|
||||
if (value < 0) {
|
||||
deleteAnswer(currentQuestion.id);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: "",
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
return setIsSending(false);
|
||||
}
|
||||
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",
|
||||
}}
|
||||
>
|
||||
<SelectComponent
|
||||
disabled={isSending}
|
||||
placeholder={currentQuestion.content.default}
|
||||
activeItemIndex={answer ? Number(answer) : -1}
|
||||
items={currentQuestion.content.variants.map(({ answer }) => answer)}
|
||||
colorMain={theme.palette.primary.main}
|
||||
sx={{
|
||||
"& .MuiSelect-select.MuiSelect-outlined": { zIndex: 1 },
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: "transparent",
|
||||
},
|
||||
}}
|
||||
onChange={async (_, value) => {
|
||||
setIsSending(true);
|
||||
if (value < 0) {
|
||||
deleteAnswer(currentQuestion.id);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: "",
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
return setIsSending(false);
|
||||
}
|
||||
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: String(
|
||||
currentQuestion.content.variants[Number(value)].answer
|
||||
),
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: String(
|
||||
currentQuestion.content.variants[Number(value)].answer
|
||||
),
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
updateAnswer(currentQuestion.id, String(value), 0);
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
updateAnswer(currentQuestion.id, String(value), 0);
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
setIsSending(false);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {
|
||||
Box,
|
||||
TextField as MuiTextField,
|
||||
TextFieldProps,
|
||||
Typography,
|
||||
useTheme,
|
||||
Box,
|
||||
TextField as MuiTextField,
|
||||
TextFieldProps,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
|
||||
import CustomTextField from "@ui_kit/CustomTextField";
|
||||
|
||||
import { updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import { sendAnswer } from "@api/quizRelase";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
@ -22,265 +22,265 @@ 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, preview } = 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 { settings, preview } = useQuizData();
|
||||
const spec = settings.cfg.spec;
|
||||
const { quizId } = useQuizData();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
const inputHC = useDebouncedCallback(async (text) => {
|
||||
setIsSending(true);
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: text,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
} 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
const { settings } = useQuizData();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const theme = useTheme();
|
||||
const { settings } = useQuizData();
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
|
||||
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": {
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: "transparent",
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
"&:focus-visible": { borderColor: theme.palette.primary.main },
|
||||
}}
|
||||
/>
|
||||
{currentQuestion.content.back &&
|
||||
currentQuestion.content.back !== " " && (
|
||||
<Box
|
||||
sx={{
|
||||
maxWidth: "400px",
|
||||
width: "100%",
|
||||
height: "300px",
|
||||
margin: "15px",
|
||||
}}
|
||||
return (
|
||||
<Box>
|
||||
<Typography
|
||||
variant="h5"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
<img
|
||||
key={currentQuestion.id}
|
||||
src={currentQuestion.content.back}
|
||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||
alt=""
|
||||
/>
|
||||
{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": {
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: "transparent",
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "#9A9AAF"
|
||||
},
|
||||
"&: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>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const TextSpecial = ({
|
||||
currentQuestion,
|
||||
answer,
|
||||
inputHC,
|
||||
stepNumber,
|
||||
currentQuestion,
|
||||
answer,
|
||||
inputHC,
|
||||
stepNumber,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const isHorizontal = Orientation[Number(stepNumber) - 1].horizontal;
|
||||
const { settings } = useQuizData();
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const isHorizontal = Orientation[Number(stepNumber) - 1].horizontal;
|
||||
const { settings } = useQuizData();
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
|
||||
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,
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(154,154,175, 0.2)"
|
||||
: "transparent",
|
||||
}}
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
"& .MuiOutlinedInput-root": {
|
||||
backgroundColor: settings.cfg.design
|
||||
? "rgba(154,154,175, 0.2)"
|
||||
: "#FFFFFF",
|
||||
},
|
||||
"&:focus-visible": {
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
display: "flex",
|
||||
flexDirection: isMobile ? "column" : undefined,
|
||||
alignItems: isMobile ? "center" : undefined,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</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>
|
||||
);
|
||||
>
|
||||
<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,
|
||||
background: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#F2F3F7"
|
||||
: "rgba(154,154,175, 0.2)"
|
||||
: "transparent",
|
||||
}}
|
||||
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,19 @@
|
||||
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,
|
||||
useQuizViewStore,
|
||||
} from "@stores/quizView";
|
||||
|
||||
import { CheckboxIcon } from "@icons/Checkbox";
|
||||
@ -36,270 +33,275 @@ 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 = useQuizViewStore(state => state.answers);
|
||||
const ownVariants = useQuizViewStore(state => state.ownVariants);
|
||||
const updateOwnVariant = useQuizViewStore(state => state.updateOwnVariant);
|
||||
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const { answer } =
|
||||
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
const ownVariant = ownVariants.find(
|
||||
(variant) => variant.id === currentQuestion.id
|
||||
);
|
||||
|
||||
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ownVariant) {
|
||||
updateOwnVariant(currentQuestion.id, "");
|
||||
}
|
||||
}, []);
|
||||
const Group = currentQuestion.content.multi ? FormGroup : RadioGroup;
|
||||
|
||||
if (moment.isMoment(answer))
|
||||
throw new Error("Answer is Moment in Variant question");
|
||||
useEffect(() => {
|
||||
if (!ownVariant) {
|
||||
updateOwnVariant(currentQuestion.id, "");
|
||||
}
|
||||
}, []);
|
||||
|
||||
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=""
|
||||
/>
|
||||
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>
|
||||
)}
|
||||
</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, preview } = useQuizData();
|
||||
const theme = useTheme();
|
||||
const { settings, quizId, preview } = useQuizData();
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
|
||||
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
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
display: "flex",
|
||||
maxWidth: "685px",
|
||||
maxHeight: "85px",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
"&:hover": {borderColor: theme.palette.primary.main},
|
||||
"&.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",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
}}
|
||||
value={index}
|
||||
labelPlacement="start"
|
||||
control={
|
||||
currentQuestion.content.multi ? (
|
||||
<Checkbox
|
||||
checked={!!answer?.includes(variant.id)}
|
||||
checkedIcon={
|
||||
<CheckboxIcon checked color={theme.palette.primary.main} />
|
||||
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
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: quizThemes[settings.cfg.theme].isLight
|
||||
? "white"
|
||||
: theme.palette.background.default,
|
||||
display: "flex",
|
||||
maxWidth: "685px",
|
||||
maxHeight: "85px",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
"&:hover": { borderColor: theme.palette.primary.main },
|
||||
"&.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",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
}}
|
||||
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 />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
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;
|
||||
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,
|
||||
preview
|
||||
});
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: currentAnswer.includes(variantId)
|
||||
? currentAnswer?.filter((item) => item !== variantId)
|
||||
: [...currentAnswer, variantId],
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
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,
|
||||
preview
|
||||
});
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: currentQuestion.content.variants[index].answer,
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
|
||||
updateAnswer(
|
||||
currentQuestion.id,
|
||||
variantId,
|
||||
answer === variantId
|
||||
? 0
|
||||
: currentQuestion.content.variants[index].points || 0
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
deleteAnswer(currentQuestion.id);
|
||||
}
|
||||
if (answer === variantId) {
|
||||
try {
|
||||
await sendAnswer({
|
||||
questionId: currentQuestion.id,
|
||||
body: "",
|
||||
qid: quizId,
|
||||
preview
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
}
|
||||
deleteAnswer(currentQuestion.id);
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
setIsSending(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,12 +1,12 @@
|
||||
import {
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { deleteAnswer, updateAnswer, useQuizViewStore } from "@stores/quizView";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
@ -21,202 +21,205 @@ 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, preview } = useQuizData();
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
const { settings, quizId, preview } = useQuizData();
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const deleteAnswer = useQuizViewStore(state => state.deleteAnswer);
|
||||
const updateAnswer = useQuizViewStore(state => state.updateAnswer);
|
||||
|
||||
const { answer } =
|
||||
answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||
const variant = currentQuestion.content.variants.find(
|
||||
({ id }) => answer === id
|
||||
);
|
||||
const theme = useTheme();
|
||||
const isMobile = useRootContainerSize() < 650;
|
||||
const [isSending, setIsSending] = useState<boolean>(false);
|
||||
|
||||
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: "30px",
|
||||
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: "20px",
|
||||
"&:focus": {color: theme.palette.text.primary },
|
||||
"&:active": {color: theme.palette.text.primary }
|
||||
}}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
disabled={isSending}
|
||||
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={{
|
||||
marginBottom: "15px",
|
||||
borderRadius: "12px",
|
||||
padding: "20px",
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: 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: 0,
|
||||
"&:hover": {borderColor: theme.palette.primary.main},
|
||||
"& .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",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
display: "flex",
|
||||
marginTop: "20px",
|
||||
flexDirection: isMobile ? "column-reverse" : undefined,
|
||||
gap: "30px",
|
||||
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: "20px",
|
||||
"&:focus": { color: theme.palette.text.primary },
|
||||
"&:active": { color: theme.palette.text.primary }
|
||||
}}
|
||||
>
|
||||
{currentQuestion.content.variants.map((variant, index) => (
|
||||
<FormControlLabel
|
||||
key={variant.id}
|
||||
disabled={isSending}
|
||||
sx={{
|
||||
marginBottom: "15px",
|
||||
borderRadius: "12px",
|
||||
padding: "20px",
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: settings.cfg.design
|
||||
? quizThemes[settings.cfg.theme].isLight
|
||||
? "#FFFFFF"
|
||||
: "rgba(255,255,255, 0.3)"
|
||||
: 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: 0,
|
||||
"&:hover": { borderColor: theme.palette.primary.main },
|
||||
"& .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",
|
||||
},
|
||||
},
|
||||
"& .MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
}}
|
||||
labelPlacement="start"
|
||||
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,
|
||||
preview
|
||||
});
|
||||
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} 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: "#9A9AAF30",
|
||||
color: theme.palette.text.primary,
|
||||
}
|
||||
}}
|
||||
labelPlacement="start"
|
||||
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,
|
||||
preview
|
||||
});
|
||||
|
||||
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,
|
||||
preview
|
||||
});
|
||||
} 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: "#9A9AAF30",
|
||||
color: theme.palette.text.primary,
|
||||
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 ? (
|
||||
"Выберите вариант ответа ниже"
|
||||
) : (
|
||||
"Выберите вариант ответа слева"
|
||||
)}
|
||||
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>
|
||||
{/* )} */}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
@ -1,123 +1,102 @@
|
||||
import { QuestionVariant } from "@model/questionTypes/shared";
|
||||
import { produce } from "immer";
|
||||
import { nanoid } from "nanoid";
|
||||
import { create } from "zustand";
|
||||
import { devtools } from "zustand/middleware";
|
||||
import type { Moment } from "moment";
|
||||
import { QuizStep } from "@model/settingsData";
|
||||
|
||||
type QuestionAnswer = {
|
||||
questionId: string;
|
||||
answer: string | string[] | Moment;
|
||||
};
|
||||
|
||||
type OwnVariant = {
|
||||
id: string;
|
||||
variant: QuestionVariant;
|
||||
};
|
||||
|
||||
interface QuizViewStore {
|
||||
answers: QuestionAnswer[];
|
||||
ownVariants: OwnVariant[];
|
||||
pointsSum: number;
|
||||
points: Record<string, number>;
|
||||
currentQuizStep: QuizStep;
|
||||
}
|
||||
|
||||
export const useQuizViewStore = create<QuizViewStore>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
answers: [],
|
||||
ownVariants: [],
|
||||
points: {},
|
||||
pointsSum: 0,
|
||||
currentQuizStep: "startpage",
|
||||
}),
|
||||
{
|
||||
name: "quizView",
|
||||
enabled: import.meta.env.DEV,
|
||||
trace: import.meta.env.DEV,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
function setProducedState<A extends string | { type: string; }>(
|
||||
recipe: (state: QuizViewStore) => void,
|
||||
action?: A,
|
||||
) {
|
||||
useQuizViewStore.setState(state => produce(state, recipe), false, action);
|
||||
}
|
||||
|
||||
const calcPoints = () => {
|
||||
const storePoints = useQuizViewStore.getState().points;
|
||||
let sum = Object.values(storePoints).reduce((accumulator, currentValue) => accumulator + currentValue)
|
||||
console.log("сумма ", sum)
|
||||
useQuizViewStore.setState({ pointsSum: sum })
|
||||
}
|
||||
|
||||
export const updateAnswer = (
|
||||
questionId: string,
|
||||
answer: string | string[] | Moment,
|
||||
points: number
|
||||
) => {
|
||||
setProducedState(state => {
|
||||
const index = state.answers.findIndex(answer => questionId === answer.questionId);
|
||||
|
||||
if (index < 0) {
|
||||
state.answers.push({ questionId, answer });
|
||||
} else {
|
||||
state.answers[index] = { questionId, answer };
|
||||
}
|
||||
}, {
|
||||
type: "updateAnswer",
|
||||
questionId,
|
||||
answer
|
||||
})
|
||||
const storePoints = useQuizViewStore.getState().points;
|
||||
useQuizViewStore.setState({ points: { ...storePoints, ...{ [questionId]: points } } })
|
||||
calcPoints()
|
||||
};
|
||||
|
||||
export const deleteAnswer = (questionId: string) => useQuizViewStore.setState(state => ({
|
||||
answers: state.answers.filter(answer => questionId !== answer.questionId)
|
||||
}), false, {
|
||||
type: "deleteAnswer",
|
||||
questionId
|
||||
});
|
||||
|
||||
export const updateOwnVariant = (id: string, answer: string) => setProducedState(state => {
|
||||
const index = state.ownVariants.findIndex((variant) => variant.id === id);
|
||||
|
||||
if (index < 0) {
|
||||
state.ownVariants.push({
|
||||
id,
|
||||
variant: {
|
||||
id: nanoid(),
|
||||
answer,
|
||||
extendedText: "",
|
||||
hints: "",
|
||||
originalImageUrl: "",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
state.ownVariants[index].variant.answer = answer;
|
||||
}
|
||||
}, {
|
||||
type: "updateOwnVariant",
|
||||
id,
|
||||
answer
|
||||
});
|
||||
|
||||
export const deleteOwnVariant = (id: string) => useQuizViewStore.setState(state => ({
|
||||
ownVariants: state.ownVariants.filter((variant) => variant.id !== id)
|
||||
}), false, {
|
||||
type: "deleteOwnVariant",
|
||||
id
|
||||
});
|
||||
|
||||
export const setCurrentQuizStep = (currentQuizStep: QuizStep) => useQuizViewStore.setState({
|
||||
currentQuizStep
|
||||
}, false, {
|
||||
type: "setCurrentQuizStep",
|
||||
currentQuizStep
|
||||
});
|
||||
import { QuestionVariant } from "@model/questionTypes/shared";
|
||||
import { QuizStep } from "@model/settingsData";
|
||||
import type { Moment } from "moment";
|
||||
import { nanoid } from "nanoid";
|
||||
import { createContext, useContext } from "react";
|
||||
import { createStore, useStore } from "zustand";
|
||||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
type QuestionAnswer = {
|
||||
questionId: string;
|
||||
answer: string | string[] | Moment;
|
||||
};
|
||||
|
||||
type OwnVariant = {
|
||||
id: string;
|
||||
variant: QuestionVariant;
|
||||
};
|
||||
|
||||
interface QuizViewStore {
|
||||
answers: QuestionAnswer[];
|
||||
ownVariants: OwnVariant[];
|
||||
pointsSum: number;
|
||||
points: Record<string, number>;
|
||||
currentQuizStep: QuizStep;
|
||||
}
|
||||
|
||||
interface QuizViewActions {
|
||||
updateAnswer: (questionId: string, answer: string | string[] | Moment, points: number) => void;
|
||||
deleteAnswer: (questionId: string) => void;
|
||||
updateOwnVariant: (id: string, answer: string) => void;
|
||||
deleteOwnVariant: (id: string) => void;
|
||||
setCurrentQuizStep: (step: QuizStep) => void;
|
||||
}
|
||||
|
||||
export const QuizViewContext = createContext<ReturnType<typeof createQuizViewStore> | null>(null);
|
||||
|
||||
export function useQuizViewStore<U>(selector: (state: QuizViewStore & QuizViewActions) => U): U {
|
||||
const context = useContext(QuizViewContext);
|
||||
if (!context) throw new Error("QuizViewStore context is null");
|
||||
|
||||
return useStore(context, selector);
|
||||
}
|
||||
|
||||
export const createQuizViewStore = () => createStore<QuizViewStore & QuizViewActions>()(
|
||||
immer(
|
||||
(set, get) => ({
|
||||
answers: [],
|
||||
ownVariants: [],
|
||||
points: {},
|
||||
pointsSum: 0,
|
||||
currentQuizStep: "startpage",
|
||||
updateAnswer(questionId, answer, points) {
|
||||
set(state => {
|
||||
const index = state.answers.findIndex(answer => questionId === answer.questionId);
|
||||
|
||||
if (index < 0) {
|
||||
state.answers.push({ questionId, answer });
|
||||
} else {
|
||||
state.answers[index] = { questionId, answer };
|
||||
}
|
||||
|
||||
state.points = { ...state.points, ...{ [questionId]: points } };
|
||||
|
||||
state.pointsSum = Object.values(state.points).reduce((sum, value) => sum + value);
|
||||
});
|
||||
},
|
||||
deleteAnswer(questionId) {
|
||||
set(state => {
|
||||
state.answers = state.answers.filter(answer => questionId !== answer.questionId);
|
||||
});
|
||||
},
|
||||
updateOwnVariant(id, answer) {
|
||||
set(state => {
|
||||
const index = state.ownVariants.findIndex((variant) => variant.id === id);
|
||||
|
||||
if (index < 0) {
|
||||
state.ownVariants.push({
|
||||
id,
|
||||
variant: {
|
||||
id: nanoid(),
|
||||
answer,
|
||||
extendedText: "",
|
||||
hints: "",
|
||||
originalImageUrl: "",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
state.ownVariants[index].variant.answer = answer;
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteOwnVariant(id) {
|
||||
set(state => {
|
||||
state.ownVariants = state.ownVariants.filter((variant) => variant.id !== id);
|
||||
});
|
||||
},
|
||||
setCurrentQuizStep(step) {
|
||||
set({ currentQuizStep: step });
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
|
36
lib/utils/designList.ts
Normal file
36
lib/utils/designList.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import type { QuizTheme } from "@model/settingsData";
|
||||
import Desgin1 from "@icons/designs/design1.jpg";
|
||||
import Desgin2 from "@icons/designs/design2.jpg";
|
||||
import Desgin3 from "@icons/designs/design3.jpg";
|
||||
import Desgin4 from "@icons/designs/design4.jpg";
|
||||
import Desgin5 from "@icons/designs/design5.jpg";
|
||||
import Desgin6 from "@icons/designs/design6.jpg";
|
||||
import Desgin7 from "@icons/designs/design7.jpg";
|
||||
import Desgin8 from "@icons/designs/design8.jpg";
|
||||
import Desgin9 from "@icons/designs/design9.jpg";
|
||||
import Desgin10 from "@icons/designs/design10.jpg";
|
||||
|
||||
|
||||
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: "",
|
||||
};
|
@ -1,205 +1,206 @@
|
||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||
import { setCurrentQuizStep, useQuizViewStore } from "@stores/quizView";
|
||||
import { useCallback, useDebugValue, useMemo, useState } from "react";
|
||||
import { isResultQuestionEmpty } from "../../components/ViewPublicationPage/tools/checkEmptyData";
|
||||
import moment from "moment";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
|
||||
export function useQuestionFlowControl() {
|
||||
const { settings, questions } = useQuizData();
|
||||
const [currentQuestion, setCurrentQuestion] = useState<AnyTypedQuizQuestion>(getFirstQuestion);
|
||||
const { answers, pointsSum } = useQuizViewStore(state => state);
|
||||
|
||||
|
||||
const linearQuestionIndex = questions.every(({ content }) => content.rule.parentId !== "root") // null when branching enabled
|
||||
? questions.indexOf(currentQuestion)
|
||||
: null;
|
||||
|
||||
function getFirstQuestion() {
|
||||
if (questions.length === 0) throw new Error("No questions found");
|
||||
|
||||
if (settings.cfg.haveRoot) {
|
||||
const nextQuestion = questions.find(
|
||||
question => question.id === settings.cfg.haveRoot || question.content.id === settings.cfg.haveRoot
|
||||
);
|
||||
if (!nextQuestion) throw new Error("Root question not found");
|
||||
|
||||
return nextQuestion;
|
||||
}
|
||||
|
||||
return questions[0];
|
||||
}
|
||||
|
||||
|
||||
const nextQuestionIdPointsLogic = () => {
|
||||
return questions.find(question =>
|
||||
question.type === "result" && question.content.rule.parentId === "line"
|
||||
);
|
||||
};
|
||||
|
||||
const nextQuestionIdMainLogic = () => {
|
||||
const questionAnswer = answers.find(({ questionId }) => questionId === currentQuestion.id);
|
||||
|
||||
//Если ответ существует и не является объектом момента
|
||||
if (questionAnswer && !moment.isMoment(questionAnswer.answer)) {
|
||||
//Ответы должны храниться в массиве
|
||||
const userAnswers = Array.isArray(questionAnswer.answer) ? questionAnswer.answer : [questionAnswer.answer];
|
||||
|
||||
//Сравниваем список условий ветвления и выбираем подходящее
|
||||
for (const branchingRule of currentQuestion.content.rule.main) {
|
||||
if (userAnswers.some(answer => branchingRule.rules[0].answers.includes(answer))) {
|
||||
return branchingRule.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentQuestion.required) {//вопрос не обязателен и не нашли совпадений между ответами и условиями ветвления
|
||||
const defaultNextQuestionId = currentQuestion.content.rule.default;
|
||||
if (defaultNextQuestionId.length > 1 && defaultNextQuestionId !== " ") return defaultNextQuestionId;
|
||||
//Вопросы типа страница, ползунок, своё поле для ввода и дата не могут иметь больше 1 ребёнка. Пользователь не может настроить там дефолт
|
||||
//Кинуть на ребёнка надо даже если там нет дефолта
|
||||
if (
|
||||
["date", "page", "text", "number"].includes(currentQuestion.type)
|
||||
&& currentQuestion.content.rule.children.length === 1
|
||||
) return currentQuestion.content.rule.children[0];
|
||||
}
|
||||
|
||||
//ничё не нашли, ищем резулт
|
||||
return questions.find(q => {
|
||||
return q.type === "result" && q.content.rule.parentId === currentQuestion.content.id;
|
||||
})?.id;
|
||||
};
|
||||
const calculateNextQuestionId = useMemo(() => {
|
||||
if (Boolean(settings.cfg.score)) {
|
||||
return nextQuestionIdPointsLogic();
|
||||
}
|
||||
return nextQuestionIdMainLogic();
|
||||
}, [answers, currentQuestion, questions]);
|
||||
|
||||
const prevQuestion = linearQuestionIndex !== null
|
||||
? questions[linearQuestionIndex - 1]
|
||||
: questions.find(q =>
|
||||
q.id === currentQuestion.content.rule.parentId
|
||||
|| q.content.id === currentQuestion.content.rule.parentId
|
||||
);
|
||||
|
||||
const findResultPointsLogic = () => {
|
||||
const results = questions
|
||||
.filter(e => e.type === "result" && e.content.rule.minScore !== undefined && e.content.rule.minScore <= pointsSum);
|
||||
const numbers = results.map(e => e.type === "result" && e.content.rule.minScore !== undefined ? e.content.rule.minScore : 0);
|
||||
const indexOfNext = Math.max(...numbers);
|
||||
console.log(results);
|
||||
console.log(numbers);
|
||||
console.log(indexOfNext);
|
||||
return results[numbers.indexOf(indexOfNext)];
|
||||
};
|
||||
|
||||
const getNextQuestion = () => {
|
||||
let next;
|
||||
console.log(11111111111);
|
||||
//Искать можно двумя логиками. Основной и балловой
|
||||
if (Boolean(settings.cfg.score)) {
|
||||
//Балловая
|
||||
console.log(222222222);
|
||||
|
||||
|
||||
//Ищем линейно
|
||||
if (linearQuestionIndex !== null) {
|
||||
console.log(33333333333);
|
||||
|
||||
|
||||
next = questions[linearQuestionIndex + 1];
|
||||
console.log(4444444);
|
||||
console.log("перед ифом", next);
|
||||
if (next?.type === "result" || next == undefined) next = findResultPointsLogic();
|
||||
console.log(5555555555);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
console.log(6666666);
|
||||
//Основная
|
||||
if (linearQuestionIndex !== null) {
|
||||
console.log(777777777);
|
||||
//Ищем линейно
|
||||
next = questions[linearQuestionIndex + 1] ?? questions.find(question =>
|
||||
question.type === "result" && question.content.rule.parentId === "line"
|
||||
);
|
||||
} else {
|
||||
console.log(88888888888888);
|
||||
//Ищем ветвлением
|
||||
next = questions.find(q => q.id === calculateNextQuestionId || q.content.id === calculateNextQuestionId);
|
||||
}
|
||||
}
|
||||
console.log("next", next);
|
||||
if (!next && currentQuestion.type !== "result") throw new Error("Не найден следующий вопрос");
|
||||
return next;
|
||||
};
|
||||
const nextQuestion = getNextQuestion();
|
||||
const showResult = useCallback(() => {
|
||||
if (nextQuestion?.type !== "result") throw new Error("Current question is not result");
|
||||
|
||||
setCurrentQuestion(nextQuestion);
|
||||
if (
|
||||
settings.cfg.resultInfo.showResultForm === "after"
|
||||
|| isResultQuestionEmpty(nextQuestion)
|
||||
) setCurrentQuizStep("contactform");
|
||||
}, [nextQuestion, settings.cfg.resultInfo.showResultForm]);
|
||||
|
||||
const showResultAfterContactForm = useCallback(() => {
|
||||
if (currentQuestion.type !== "result") throw new Error("Current question is not result");
|
||||
if (isResultQuestionEmpty(currentQuestion)) {
|
||||
enqueueSnackbar("Данные отправлены");
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentQuizStep("question");
|
||||
}, [currentQuestion]);
|
||||
|
||||
const moveToPrevQuestion = useCallback(() => {
|
||||
if (!prevQuestion) throw new Error("Previous question not found");
|
||||
|
||||
setCurrentQuestion(prevQuestion);
|
||||
}, [prevQuestion]);
|
||||
|
||||
const moveToNextQuestion = useCallback(() => {
|
||||
if (!nextQuestion) throw new Error("Next question not found");
|
||||
|
||||
if (nextQuestion.type === "result") return showResult();
|
||||
|
||||
setCurrentQuestion(nextQuestion);
|
||||
}, [nextQuestion, showResult]);
|
||||
|
||||
const isPreviousButtonEnabled = Boolean(prevQuestion);
|
||||
|
||||
const isNextButtonEnabled = useMemo(() => {
|
||||
const hasAnswer = answers.some(({ questionId }) => questionId === currentQuestion.id);
|
||||
|
||||
if ("required" in currentQuestion.content && currentQuestion.content.required) {
|
||||
return hasAnswer;
|
||||
}
|
||||
|
||||
return Boolean(nextQuestion);
|
||||
}, [answers, currentQuestion.content, currentQuestion.id, nextQuestion]);
|
||||
|
||||
useDebugValue({
|
||||
linearQuestionIndex,
|
||||
currentQuestion: currentQuestion,
|
||||
prevQuestion: prevQuestion,
|
||||
nextQuestion: nextQuestion,
|
||||
});
|
||||
|
||||
return {
|
||||
currentQuestion,
|
||||
currentQuestionStepNumber: linearQuestionIndex === null ? null : linearQuestionIndex + 1,
|
||||
isNextButtonEnabled,
|
||||
isPreviousButtonEnabled,
|
||||
moveToPrevQuestion,
|
||||
moveToNextQuestion,
|
||||
showResultAfterContactForm,
|
||||
};
|
||||
}
|
||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||
import { useQuizViewStore } from "@stores/quizView";
|
||||
import { useCallback, useDebugValue, useMemo, useState } from "react";
|
||||
import { isResultQuestionEmpty } from "../../components/ViewPublicationPage/tools/checkEmptyData";
|
||||
import moment from "moment";
|
||||
import { useQuizData } from "@contexts/QuizDataContext";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
|
||||
export function useQuestionFlowControl() {
|
||||
const { settings, questions } = useQuizData();
|
||||
const [currentQuestion, setCurrentQuestion] = useState<AnyTypedQuizQuestion>(getFirstQuestion);
|
||||
const answers = useQuizViewStore(state => state.answers);
|
||||
const pointsSum = useQuizViewStore(state => state.pointsSum);
|
||||
const setCurrentQuizStep = useQuizViewStore(state => state.setCurrentQuizStep);
|
||||
|
||||
const linearQuestionIndex = questions.every(({ content }) => content.rule.parentId !== "root") // null when branching enabled
|
||||
? questions.indexOf(currentQuestion)
|
||||
: null;
|
||||
|
||||
function getFirstQuestion() {
|
||||
if (questions.length === 0) throw new Error("No questions found");
|
||||
|
||||
if (settings.cfg.haveRoot) {
|
||||
const nextQuestion = questions.find(
|
||||
question => question.id === settings.cfg.haveRoot || question.content.id === settings.cfg.haveRoot
|
||||
);
|
||||
if (!nextQuestion) throw new Error("Root question not found");
|
||||
|
||||
return nextQuestion;
|
||||
}
|
||||
|
||||
return questions[0];
|
||||
}
|
||||
|
||||
|
||||
const nextQuestionIdPointsLogic = () => {
|
||||
return questions.find(question =>
|
||||
question.type === "result" && question.content.rule.parentId === "line"
|
||||
);
|
||||
};
|
||||
|
||||
const nextQuestionIdMainLogic = () => {
|
||||
const questionAnswer = answers.find(({ questionId }) => questionId === currentQuestion.id);
|
||||
|
||||
//Если ответ существует и не является объектом момента
|
||||
if (questionAnswer && !moment.isMoment(questionAnswer.answer)) {
|
||||
//Ответы должны храниться в массиве
|
||||
const userAnswers = Array.isArray(questionAnswer.answer) ? questionAnswer.answer : [questionAnswer.answer];
|
||||
|
||||
//Сравниваем список условий ветвления и выбираем подходящее
|
||||
for (const branchingRule of currentQuestion.content.rule.main) {
|
||||
if (userAnswers.some(answer => branchingRule.rules[0].answers.includes(answer))) {
|
||||
return branchingRule.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentQuestion.required) {//вопрос не обязателен и не нашли совпадений между ответами и условиями ветвления
|
||||
const defaultNextQuestionId = currentQuestion.content.rule.default;
|
||||
if (defaultNextQuestionId.length > 1 && defaultNextQuestionId !== " ") return defaultNextQuestionId;
|
||||
//Вопросы типа страница, ползунок, своё поле для ввода и дата не могут иметь больше 1 ребёнка. Пользователь не может настроить там дефолт
|
||||
//Кинуть на ребёнка надо даже если там нет дефолта
|
||||
if (
|
||||
["date", "page", "text", "number"].includes(currentQuestion.type)
|
||||
&& currentQuestion.content.rule.children.length === 1
|
||||
) return currentQuestion.content.rule.children[0];
|
||||
}
|
||||
|
||||
//ничё не нашли, ищем резулт
|
||||
return questions.find(q => {
|
||||
return q.type === "result" && q.content.rule.parentId === currentQuestion.content.id;
|
||||
})?.id;
|
||||
};
|
||||
const calculateNextQuestionId = useMemo(() => {
|
||||
if (settings.cfg.score) {
|
||||
return nextQuestionIdPointsLogic();
|
||||
}
|
||||
return nextQuestionIdMainLogic();
|
||||
}, [answers, currentQuestion, questions]);
|
||||
|
||||
const prevQuestion = linearQuestionIndex !== null
|
||||
? questions[linearQuestionIndex - 1]
|
||||
: questions.find(q =>
|
||||
q.id === currentQuestion.content.rule.parentId
|
||||
|| q.content.id === currentQuestion.content.rule.parentId
|
||||
);
|
||||
|
||||
const findResultPointsLogic = () => {
|
||||
const results = questions
|
||||
.filter(e => e.type === "result" && e.content.rule.minScore !== undefined && e.content.rule.minScore <= pointsSum);
|
||||
const numbers = results.map(e => e.type === "result" && e.content.rule.minScore !== undefined ? e.content.rule.minScore : 0);
|
||||
const indexOfNext = Math.max(...numbers);
|
||||
console.log(results);
|
||||
console.log(numbers);
|
||||
console.log(indexOfNext);
|
||||
return results[numbers.indexOf(indexOfNext)];
|
||||
};
|
||||
|
||||
const getNextQuestion = () => {
|
||||
let next;
|
||||
console.log(11111111111);
|
||||
//Искать можно двумя логиками. Основной и балловой
|
||||
if (settings.cfg.score) {
|
||||
//Балловая
|
||||
console.log(222222222);
|
||||
|
||||
|
||||
//Ищем линейно
|
||||
if (linearQuestionIndex !== null) {
|
||||
console.log(33333333333);
|
||||
|
||||
|
||||
next = questions[linearQuestionIndex + 1];
|
||||
console.log(4444444);
|
||||
console.log("перед ифом", next);
|
||||
if (next?.type === "result" || next == undefined) next = findResultPointsLogic();
|
||||
console.log(5555555555);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
console.log(6666666);
|
||||
//Основная
|
||||
if (linearQuestionIndex !== null) {
|
||||
console.log(777777777);
|
||||
//Ищем линейно
|
||||
next = questions[linearQuestionIndex + 1] ?? questions.find(question =>
|
||||
question.type === "result" && question.content.rule.parentId === "line"
|
||||
);
|
||||
} else {
|
||||
console.log(88888888888888);
|
||||
//Ищем ветвлением
|
||||
next = questions.find(q => q.id === calculateNextQuestionId || q.content.id === calculateNextQuestionId);
|
||||
}
|
||||
}
|
||||
console.log("next", next);
|
||||
if (!next && currentQuestion.type !== "result") throw new Error("Не найден следующий вопрос");
|
||||
return next;
|
||||
};
|
||||
const nextQuestion = getNextQuestion();
|
||||
const showResult = useCallback(() => {
|
||||
if (nextQuestion?.type !== "result") throw new Error("Current question is not result");
|
||||
|
||||
setCurrentQuestion(nextQuestion);
|
||||
if (
|
||||
settings.cfg.resultInfo.showResultForm === "after"
|
||||
|| isResultQuestionEmpty(nextQuestion)
|
||||
) setCurrentQuizStep("contactform");
|
||||
}, [nextQuestion, settings.cfg.resultInfo.showResultForm]);
|
||||
|
||||
const showResultAfterContactForm = useCallback(() => {
|
||||
if (currentQuestion.type !== "result") throw new Error("Current question is not result");
|
||||
if (isResultQuestionEmpty(currentQuestion)) {
|
||||
enqueueSnackbar("Данные отправлены");
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentQuizStep("question");
|
||||
}, [currentQuestion]);
|
||||
|
||||
const moveToPrevQuestion = useCallback(() => {
|
||||
if (!prevQuestion) throw new Error("Previous question not found");
|
||||
|
||||
setCurrentQuestion(prevQuestion);
|
||||
}, [prevQuestion]);
|
||||
|
||||
const moveToNextQuestion = useCallback(() => {
|
||||
if (!nextQuestion) throw new Error("Next question not found");
|
||||
|
||||
if (nextQuestion.type === "result") return showResult();
|
||||
|
||||
setCurrentQuestion(nextQuestion);
|
||||
}, [nextQuestion, showResult]);
|
||||
|
||||
const isPreviousButtonEnabled = Boolean(prevQuestion);
|
||||
|
||||
const isNextButtonEnabled = useMemo(() => {
|
||||
const hasAnswer = answers.some(({ questionId }) => questionId === currentQuestion.id);
|
||||
|
||||
if ("required" in currentQuestion.content && currentQuestion.content.required) {
|
||||
return hasAnswer;
|
||||
}
|
||||
|
||||
return Boolean(nextQuestion);
|
||||
}, [answers, currentQuestion.content, currentQuestion.id, nextQuestion]);
|
||||
|
||||
useDebugValue({
|
||||
linearQuestionIndex,
|
||||
currentQuestion: currentQuestion,
|
||||
prevQuestion: prevQuestion,
|
||||
nextQuestion: nextQuestion,
|
||||
});
|
||||
|
||||
return {
|
||||
currentQuestion,
|
||||
currentQuestionStepNumber: linearQuestionIndex === null ? null : linearQuestionIndex + 1,
|
||||
isNextButtonEnabled,
|
||||
isPreviousButtonEnabled,
|
||||
moveToPrevQuestion,
|
||||
moveToNextQuestion,
|
||||
showResultAfterContactForm,
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@frontend/squzanswerer",
|
||||
"version": "1.0.16",
|
||||
"version": "1.0.17",
|
||||
"type": "module",
|
||||
"main": "./dist-package/index.js",
|
||||
"module": "./dist-package/index.js",
|
||||
|
Loading…
Reference in New Issue
Block a user