diff --git a/lib/api/hooks.ts b/lib/api/hooks.ts new file mode 100644 index 0000000..633b773 --- /dev/null +++ b/lib/api/hooks.ts @@ -0,0 +1,11 @@ +import useSWR from "swr"; +import { getQuizData } from "./quizRelase"; + +export function useQuizData(quizId: string) { + return useSWR(["quizData", quizId], (params) => getQuizData(params[1]), { + revalidateOnFocus: false, + revalidateOnReconnect: false, + shouldRetryOnError: false, + refreshInterval: 0, + }); +} diff --git a/lib/components/QuizAnswerer.tsx b/lib/components/QuizAnswerer.tsx index b24778b..6877688 100644 --- a/lib/components/QuizAnswerer.tsx +++ b/lib/components/QuizAnswerer.tsx @@ -1,30 +1,23 @@ -import { startTransition, useEffect, useLayoutEffect, useRef, useState } from "react"; -import { ErrorBoundary } from "react-error-boundary"; -import useSWR from "swr"; -import { SnackbarProvider } from "notistack"; -import moment from "moment"; -import { Box, ScopedCssBaseline, CssBaseline, ThemeProvider } from "@mui/material"; +import { useQuizData } from "@/api/hooks"; +import { QuizViewContext, createQuizViewStore } from "@/stores/quizView"; +import LoadingSkeleton from "@/ui_kit/LoadingSkeleton"; +import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals"; +import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals"; +import { QuizSettingsContext } from "@contexts/QuizDataContext"; +import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext"; +import type { QuizSettings } from "@model/settingsData"; +import { Box, CssBaseline, ScopedCssBaseline, ThemeProvider } from "@mui/material"; import { LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment"; import { ruRU } from "@mui/x-date-pickers/locales"; - -import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage"; -import { ApologyPage } from "./ViewPublicationPage/ApologyPage"; - -import { QuizViewContext, createQuizViewStore } from "@/stores/quizView"; - -import { getQuizData } from "@/api/quizRelase"; - -import { QuizDataContext } from "@contexts/QuizDataContext"; -import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext"; -import LoadingSkeleton from "@/ui_kit/LoadingSkeleton"; - -import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals"; -import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals"; import { handleComponentError } from "@utils/handleComponentError"; import lightTheme from "@utils/themes/light"; - -import type { QuizSettings } from "@model/settingsData"; +import moment from "moment"; +import { SnackbarProvider } from "notistack"; +import { startTransition, useEffect, useLayoutEffect, useRef, useState } from "react"; +import { ErrorBoundary } from "react-error-boundary"; +import { ApologyPage } from "./ViewPublicationPage/ApologyPage"; +import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage"; moment.locale("ru"); const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText; @@ -49,16 +42,7 @@ function QuizAnswererInner({ const [quizViewStore] = useState(createQuizViewStore); const [rootContainerWidth, setRootContainerWidth] = useState(() => window.innerWidth); const rootContainerRef = useRef(null); - const { data, error, isLoading } = useSWR( - quizSettings ? null : ["quizData", quizId], - (params) => getQuizData(params[1]), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - shouldRetryOnError: false, - refreshInterval: 0, - } - ); + const { data, error, isLoading } = useQuizData(quizId); const vkMetrics = useVkMetricsGoals(quizSettings?.settings.cfg.vkMetricsNumber); const yandexMetrics = useYandexMetricsGoals(quizSettings?.settings.cfg.yandexMetricsNumber); @@ -67,6 +51,7 @@ function QuizAnswererInner({ vkMetrics.quizOpened(); yandexMetrics.quizOpened(); }, 4000); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useLayoutEffect(() => { @@ -88,6 +73,7 @@ function QuizAnswererInner({ if (isLoading) return ; if (error) return ; + if (!data) return ; quizSettings ??= data; if (!quizSettings) throw new Error("Quiz data is null"); @@ -114,7 +100,7 @@ function QuizAnswererInner({ return ( - + {disableGlobalCss ? ( {quizContainer} )} - + ); diff --git a/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx b/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx index 12f8a67..6b449ba 100644 --- a/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx @@ -8,7 +8,7 @@ import { Inputs } from "@/components/ViewPublicationPage/ContactForm/Inputs/Inpu import { ContactTextBlock } from "./ContactTextBlock"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { sendFC, SendFCParams } from "@api/quizRelase"; @@ -32,7 +32,7 @@ type Props = { export const ContactForm = ({ currentQuestion, onShowResult }: Props) => { const theme = useTheme(); - const { settings, questions, quizId, show_badge, preview } = useQuizData(); + const { settings, questions, quizId, show_badge, preview } = useQuizSettings(); const [ready, setReady] = useState(false); const [name, setName] = useState(""); diff --git a/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx b/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx index 312c14b..cc27f3b 100644 --- a/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx @@ -1,6 +1,6 @@ import { Box, InputAdornment, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext.ts"; -import { useQuizData } from "@contexts/QuizDataContext.ts"; +import { useQuizSettings } from "@contexts/QuizDataContext.ts"; import { useIMask } from "react-imask"; import { quizThemes } from "@utils/themes/Publication/themePublication.ts"; import { FC, useState } from "react"; @@ -21,7 +21,7 @@ const TextField = MuiTextField as unknown as FC; export const CustomInput = ({ title, desc, Icon, onChange, isPhone }: InputProps) => { const theme = useTheme(); const isMobile = useRootContainerSize() < 600; - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); const [mask, setMask] = useState(phoneMasksByCountry["RU"][1]); const { ref } = useIMask({ mask }); return ( diff --git a/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx b/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx index bb94104..4a6fcbb 100644 --- a/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx @@ -1,4 +1,4 @@ -import { useQuizData } from "@contexts/QuizDataContext.ts"; +import { useQuizSettings } from "@contexts/QuizDataContext.ts"; import NameIcon from "@icons/ContactFormIcon/NameIcon.tsx"; import EmailIcon from "@icons/ContactFormIcon/EmailIcon.tsx"; import TextIcon from "@icons/ContactFormIcon/TextIcon.tsx"; @@ -32,7 +32,7 @@ export const Inputs = ({ adress, setAdress, }: InputsProps) => { - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); const FC = settings.cfg.formContact.fields; if (!FC) return null; diff --git a/lib/components/ViewPublicationPage/Footer.tsx b/lib/components/ViewPublicationPage/Footer.tsx index fa2f621..ee5203e 100644 --- a/lib/components/ViewPublicationPage/Footer.tsx +++ b/lib/components/ViewPublicationPage/Footer.tsx @@ -1,7 +1,7 @@ import { ReactNode } from "react"; import { Box, Typography, useTheme } from "@mui/material"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import Stepper from "@ui_kit/Stepper"; @@ -13,7 +13,7 @@ type FooterProps = { export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { const theme = useTheme(); - const { questions, settings } = useQuizData(); + const { questions, settings } = useQuizSettings(); const questionsAmount = questions.filter(({ type }) => type !== "result").length; return ( diff --git a/lib/components/ViewPublicationPage/Question.tsx b/lib/components/ViewPublicationPage/Question.tsx index 7579d72..b9a1747 100644 --- a/lib/components/ViewPublicationPage/Question.tsx +++ b/lib/components/ViewPublicationPage/Question.tsx @@ -15,7 +15,7 @@ import { Varimg } from "./questions/Varimg"; import type { RealTypedQuizQuestion } from "../../model/questionTypes/shared"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { NameplateLogoFQ } from "@icons/NameplateLogoFQ"; import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark"; import { notReachable } from "@utils/notReachable"; @@ -40,7 +40,7 @@ export const Question = ({ questionSelect, }: Props) => { const theme = useTheme(); - const { settings, show_badge } = useQuizData(); + const { settings, show_badge } = useQuizSettings(); return ( { const theme = useTheme(); const isMobile = useRootContainerSize() < 650; const isTablet = useRootContainerSize() < 1000; - const { settings, show_badge, quizId } = useQuizData(); + const { settings, show_badge, quizId } = useQuizSettings(); const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep); const spec = settings.cfg.spec; const vkMetrics = useVkMetricsGoals(settings.cfg.vkMetricsNumber); diff --git a/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx b/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx index 7e2c846..3bf5d98 100644 --- a/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx +++ b/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx @@ -1,7 +1,7 @@ import { Box } from "@mui/material"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { notReachable } from "@utils/notReachable"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -22,7 +22,7 @@ type LayoutProps = Omit; const StandartLayout = ({ alignType, quizHeaderBlock, quizMainBlock, backgroundBlock }: LayoutProps) => { const size = useRootContainerSize(); const isTablet = size >= 700 && size < 1100; - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); return ( { const isTablet = useRootContainerSize() < 1100; - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); return ( ; const StandartMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => { - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); return ( { - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); return ( { const theme = useTheme(); - const { settings, show_badge, quizId, questions } = useQuizData(); + const { settings, show_badge, quizId, questions } = useQuizSettings(); const { isMobileDevice } = useUADevice(); const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep); diff --git a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx index 3919ac3..2804a48 100644 --- a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx +++ b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx @@ -1,5 +1,5 @@ import { sendAnswer } from "@api/quizRelase"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { ThemeProvider, Typography } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import { useQuestionFlowControl } from "@utils/hooks/useQuestionFlowControl"; @@ -18,7 +18,7 @@ import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics"; import { ContactForm } from "@/components/ViewPublicationPage/ContactForm/ContactForm.tsx"; export default function ViewPublicationPage() { - const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle } = useQuizData(); + const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); let currentQuizStep = useQuizViewStore((state) => state.currentQuizStep); const { @@ -50,7 +50,7 @@ export default function ViewPublicationPage() { [changeFaviconAndTitle, settings.cfg.startpage.favIcon, settings.name] ); - if (recentlyCompleted) throw new Error("Quiz already completed"); + if (settings.cfg.antifraud && recentlyCompleted) throw new Error("Quiz already completed"); if (currentQuizStep === "startpage" && settings.cfg.noStartPage) currentQuizStep = "question"; if (!currentQuestion) diff --git a/lib/components/ViewPublicationPage/questions/Date/index.tsx b/lib/components/ViewPublicationPage/questions/Date/index.tsx index 4a64c9f..31cf3ff 100644 --- a/lib/components/ViewPublicationPage/questions/Date/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Date/index.tsx @@ -6,7 +6,7 @@ import { enqueueSnackbar } from "notistack"; import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@/stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -21,7 +21,7 @@ type DateProps = { export const Date = ({ currentQuestion }: DateProps) => { const [isSending, setIsSending] = useState(false); - const { settings, quizId, preview } = useQuizData(); + const { settings, quizId, preview } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx index bdcaa17..741a5cd 100644 --- a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx @@ -4,7 +4,7 @@ import { enqueueSnackbar } from "notistack"; import { useQuizViewStore } from "@stores/quizView"; import { sendAnswer } from "@api/quizRelase"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import RadioCheck from "@ui_kit/RadioCheck"; @@ -25,7 +25,7 @@ type EmojiVariantProps = { }; export const EmojiVariant = ({ currentQuestion, variant, index, isSending, setIsSending }: EmojiVariantProps) => { - const { quizId, settings, preview } = useQuizData(); + const { quizId, settings, preview } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx b/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx index 69343f7..668c9b3 100644 --- a/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx +++ b/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx @@ -3,7 +3,7 @@ import { Box, ButtonBase, Skeleton, Typography, useTheme } from "@mui/material"; import { enqueueSnackbar } from "notistack"; import { sendAnswer, sendFile } from "@api/quizRelase"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { useQuizViewStore } from "@stores/quizView"; @@ -27,7 +27,7 @@ type UploadFileProps = { }; export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, setIsSending }: UploadFileProps) => { - const { quizId, preview } = useQuizData(); + const { quizId, preview } = useQuizSettings(); const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState(false); const theme = useTheme(); const answers = useQuizViewStore((state) => state.answers); diff --git a/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx b/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx index e18e6b6..a14b5f5 100644 --- a/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx +++ b/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx @@ -1,7 +1,7 @@ import { Box, IconButton, Typography, useTheme } from "@mui/material"; import { sendAnswer } from "@api/quizRelase"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { useQuizViewStore } from "@stores/quizView"; import CloseBold from "@icons/CloseBold"; @@ -14,7 +14,7 @@ type UploadedFileProps = { }; export const UploadedFile = ({ currentQuestion, setIsSending }: UploadedFileProps) => { - const { quizId, preview } = useQuizData(); + const { quizId, preview } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx b/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx index 9cca91f..eb70069 100644 --- a/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx @@ -3,7 +3,7 @@ import { enqueueSnackbar } from "notistack"; import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import RadioCheck from "@ui_kit/RadioCheck"; @@ -22,8 +22,7 @@ type ImagesProps = { }; export const ImageVariant = ({ currentQuestion, variant, isSending, setIsSending, index }: ImagesProps) => { - const { quizId, preview } = useQuizData(); - const { settings } = useQuizData(); + const { settings, quizId, preview } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { deleteAnswer, updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Number/index.tsx b/lib/components/ViewPublicationPage/questions/Number/index.tsx index 4bd47fa..621683f 100644 --- a/lib/components/ViewPublicationPage/questions/Number/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Number/index.tsx @@ -11,7 +11,7 @@ import { sendAnswer } from "@api/quizRelase"; import { enqueueSnackbar } from "notistack"; import type { QuizQuestionNumber } from "@model/questionTypes/number"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import type { ChangeEvent, SyntheticEvent } from "react"; @@ -28,7 +28,7 @@ export const Number = ({ currentQuestion }: NumberProps) => { const [reversedInputValue, setReversedInputValue] = useState("0"); const [reversedMinRange, setReversedMinRange] = useState("0"); const [reversedMaxRange, setReversedMaxRange] = useState("100000000000"); - const { settings, quizId, preview } = useQuizData(); + const { settings, quizId, preview } = useQuizSettings(); const { updateAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Rating/index.tsx b/lib/components/ViewPublicationPage/questions/Rating/index.tsx index 6a20928..e8397fb 100644 --- a/lib/components/ViewPublicationPage/questions/Rating/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Rating/index.tsx @@ -5,7 +5,7 @@ import { enqueueSnackbar } from "notistack"; import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@stores/quizView"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import FlagIcon from "@icons/questionsPage/FlagIcon"; import StarIconMini from "@icons/questionsPage/StarIconMini"; @@ -54,7 +54,7 @@ type RatingProps = { export const Rating = ({ currentQuestion }: RatingProps) => { const [isSending, setIsSending] = useState(false); - const { quizId, preview } = useQuizData(); + const { quizId, preview } = useQuizSettings(); const { updateAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Select/index.tsx b/lib/components/ViewPublicationPage/questions/Select/index.tsx index 03e86a2..6e80b1e 100644 --- a/lib/components/ViewPublicationPage/questions/Select/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Select/index.tsx @@ -6,7 +6,7 @@ import { Select as SelectComponent } from "@/components/ViewPublicationPage/tool import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -18,7 +18,7 @@ type SelectProps = { export const Select = ({ currentQuestion }: SelectProps) => { const [isSending, setIsSending] = useState(false); - const { quizId, settings, preview } = useQuizData(); + const { quizId, settings, preview } = useQuizSettings(); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx b/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx index d5ff179..1745fd3 100644 --- a/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx @@ -3,7 +3,7 @@ import { Box, Typography, useTheme } from "@mui/material"; import CustomTextField from "@ui_kit/CustomTextField"; import { Answer, useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -19,7 +19,7 @@ interface TextNormalProps { } export const TextNormal = ({ currentQuestion, answer, inputHC }: TextNormalProps) => { - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); const { updateAnswer } = useQuizViewStore((state) => state); const isMobile = useRootContainerSize() < 650; const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx b/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx index 752f967..3ed9bd7 100644 --- a/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx @@ -1,7 +1,7 @@ import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material"; import { Answer, useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -46,7 +46,7 @@ interface TextSpecialProps { } export const TextSpecial = ({ currentQuestion, answer, inputHC, stepNumber }: TextSpecialProps) => { - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); const { updateAnswer } = useQuizViewStore((state) => state); const isHorizontal = ORIENTATION[Number(stepNumber) - 1].horizontal; const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Text/index.tsx b/lib/components/ViewPublicationPage/questions/Text/index.tsx index dc5dc0b..06ae862 100644 --- a/lib/components/ViewPublicationPage/questions/Text/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/index.tsx @@ -7,7 +7,7 @@ import { TextNormal } from "./TextNormal"; import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import type { QuizQuestionText } from "@model/questionTypes/text"; @@ -18,8 +18,7 @@ type TextProps = { export const Text = ({ currentQuestion, stepNumber }: TextProps) => { const [isSending, setIsSending] = useState(false); - const { settings, preview } = useQuizData(); - const { quizId } = useQuizData(); + const { settings, preview, quizId } = useQuizSettings(); const answers = useQuizViewStore((state) => state.answers); const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {}; diff --git a/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx b/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx index d50dc4e..60266bd 100644 --- a/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx +++ b/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx @@ -3,7 +3,7 @@ import { enqueueSnackbar } from "notistack"; import { sendAnswer } from "@api/quizRelase"; import { useQuizViewStore } from "@stores/quizView"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -34,7 +34,7 @@ export const VariantItem = ({ isSending: boolean; setIsSending: (a: boolean) => void; }) => { - const { settings, quizId, preview } = useQuizData(); + const { settings, quizId, preview } = useQuizSettings(); const theme = useTheme(); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); diff --git a/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx b/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx index 12dd016..06d4f6a 100644 --- a/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx @@ -4,7 +4,7 @@ import { enqueueSnackbar } from "notistack"; import { useQuizViewStore } from "@stores/quizView"; import { sendAnswer } from "@api/quizRelase"; -import { useQuizData } from "@contexts/QuizDataContext"; +import { useQuizSettings } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -24,7 +24,7 @@ type VarimgVariantProps = { }; export const VarimgVariant = ({ currentQuestion, variant, index, isSending, setIsSending }: VarimgVariantProps) => { - const { settings, quizId, preview } = useQuizData(); + const { settings, quizId, preview } = useQuizSettings(); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); diff --git a/lib/components/ViewPublicationPage/tools/NextButton.tsx b/lib/components/ViewPublicationPage/tools/NextButton.tsx index f951321..006c68d 100644 --- a/lib/components/ViewPublicationPage/tools/NextButton.tsx +++ b/lib/components/ViewPublicationPage/tools/NextButton.tsx @@ -1,6 +1,6 @@ -import { Button, useTheme } from "@mui/material"; +import { useQuizSettings } from "@contexts/QuizDataContext"; +import { Button } from "@mui/material"; import { quizThemes } from "@utils/themes/Publication/themePublication"; -import { useQuizData } from "@contexts/QuizDataContext"; interface Props { isNextButtonEnabled: boolean; @@ -8,8 +8,8 @@ interface Props { } export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }: Props) { - const theme = useTheme(); - const { settings } = useQuizData(); + const { settings } = useQuizSettings(); + return ( (false); - const isQuizCompleted = useQuizCompletionStatus(quizId); + const { data: quizData } = useQuizData(quizId); const [isFlashEnabled, setIsFlashEnabled] = useState(buttonFlash); const preventQuizAutoShowRef = useRef(false); const preventOpenOnLeaveAttemptRef = useRef(false); @@ -70,6 +70,10 @@ export default function OpenQuizButton({ } if (hideOnMobile && isMobile) return null; + if (!quizData) return null; + + const isQuizCompleted = quizData.settings.cfg.antifraud ? quizData.recentlyCompleted : false; + const showButtonFlash = isQuizCompleted && isFlashEnabled; return ( @@ -108,7 +112,7 @@ export default function OpenQuizButton({ ]} > {buttonText} - {!isQuizCompleted && isFlashEnabled && } + {showButtonFlash && } (initialIsQuizShown); - const isQuizCompleted = useQuizCompletionStatus(quizId); const isMobile = useMediaQuery("(max-width: 600px)"); const preventOpenOnLeaveAttemptRef = useRef(false); @@ -54,6 +54,9 @@ export default function QuizPopup({ [openOnLeaveAttempt] ); + if (!quizData) return null; + + const isQuizCompleted = quizData.settings.cfg.antifraud ? quizData.recentlyCompleted : false; if (isQuizCompleted) return null; if (hideOnMobile && isMobile) return null; diff --git a/src/widgets/shared/useQuizCompletionStatus.ts b/src/widgets/shared/useQuizCompletionStatus.ts deleted file mode 100644 index 986a230..0000000 --- a/src/widgets/shared/useQuizCompletionStatus.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMemo } from "react"; - -export function useQuizCompletionStatus(quizId: string): boolean { - return useMemo(() => { - const sessions = JSON.parse(localStorage.getItem("sessions") || "{}"); - - if (typeof sessions[quizId] === "number" && Date.now() - sessions[quizId] < 86400000) { - return true; - } - - return false; - }, [quizId]); -} diff --git a/src/widgets/side/QuizSideButton.tsx b/src/widgets/side/QuizSideButton.tsx index 1b14685..47c142e 100644 --- a/src/widgets/side/QuizSideButton.tsx +++ b/src/widgets/side/QuizSideButton.tsx @@ -1,3 +1,5 @@ +import { useQuizData } from "@/api/hooks"; +import { SideWidgetComponentProps } from "@/model/widget/side"; import lightTheme from "@/utils/themes/light"; import { Button, Fade, ThemeProvider, useMediaQuery } from "@mui/material"; import { useEffect, useRef, useState } from "react"; @@ -5,8 +7,6 @@ import { createPortal } from "react-dom"; import QuizDialog from "../shared/QuizDialog"; import RunningStripe from "../shared/RunningStripe"; import { useAutoOpenTimer } from "../shared/useAutoOpenTimer"; -import { useQuizCompletionStatus } from "../shared/useQuizCompletionStatus"; -import { SideWidgetComponentProps } from "@/model/widget/side"; const PADDING = 10; const WIDGET_DEFAULT_WIDTH = "600px"; @@ -26,7 +26,7 @@ export default function QuizSideButton({ }: SideWidgetComponentProps) { const [isQuizShown, setIsQuizShown] = useState(false); const isMobile = useMediaQuery("(max-width: 600px)"); - const isQuizCompleted = useQuizCompletionStatus(quizId); + const { data: quizData } = useQuizData(quizId); const [isFlashEnabled, setIsFlashEnabled] = useState(buttonFlash); const isWidgetHidden = useAutoOpenTimer(autoShowWidgetTime); const preventQuizAutoShowRef = useRef(false); @@ -53,6 +53,10 @@ export default function QuizSideButton({ } if (hideOnMobile && isMobile) return null; + if (!quizData) return null; + + const isQuizCompleted = quizData.settings.cfg.antifraud ? quizData.recentlyCompleted : false; + const showButtonFlash = isQuizCompleted && isFlashEnabled; return createPortal( @@ -113,7 +117,7 @@ export default function QuizSideButton({ ]} > Пройти квиз - {!isQuizCompleted && isFlashEnabled && } + {showButtonFlash && } ,