From 1f2880f719b12c776a80e2cee445c068ab1f50c6 Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 22 Apr 2025 22:29:34 +0300 Subject: [PATCH 1/3] hide ai --- lib/api/quizRelase.ts | 89 +++++++++++++++---- lib/components/QuizAnswerer.tsx | 8 +- lib/components/ViewPublicationPage/Footer.tsx | 2 +- .../ViewPublicationPage.tsx | 2 +- lib/contexts/QuizDataContext.ts | 1 + lib/model/api/getQuizData.ts | 2 + lib/model/settingsData.ts | 1 + lib/utils/hooks/useQuestionFlowControl.ts | 22 ++++- 8 files changed, 103 insertions(+), 24 deletions(-) diff --git a/lib/api/quizRelase.ts b/lib/api/quizRelase.ts index e8ba0ca..de0e77e 100644 --- a/lib/api/quizRelase.ts +++ b/lib/api/quizRelase.ts @@ -71,7 +71,7 @@ export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestPara method: "POST", }); }; - +let page = 0; export async function getData(quizId: string): Promise<{ data: GetQuizDataResponse | null; isRecentlyCompleted: boolean; @@ -92,16 +92,18 @@ export async function getData(quizId: string): Promise<{ }, data: { quiz_id: quizId, - limit: 100, - page: 0, - need_config: true, + limit: 1, + page, + need_config: page === 0, }, } ); + console.log(data); + if (data.items.length) page++; const sessions = JSON.parse(localStorage.getItem("sessions") || "{}"); //Тут ещё проверка на антифрод без парса конфига. Нам не интересно время если не нужно запрещать проходить чаще чем в сутки - if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) { + if (!page && typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) { // unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше if (Date.now() - sessions[quizId] < 86400000) { return { data, isRecentlyCompleted: true }; @@ -118,27 +120,84 @@ export async function getData(quizId: string): Promise<{ } } -export async function getQuizData(quizId: string) { +export async function getQuizData(quizId: string, status?: string): Promise { + let maxRetries = 50; if (!quizId) throw new Error("No quiz id"); - const response = await getData(quizId); - const quizDataResponse = response.data; + let lastError: Error | null = null; + let responseData: any = null; - if (response.error) { - throw response.error; - } - if (!quizDataResponse) { - throw new Error("Quiz not found"); + // Первый цикл - обработка result вопросов с увеличением page + let resultRetryCount = 0; + while (resultRetryCount < maxRetries) { + try { + const response = await getData(quizId); + console.log("ф-я аналитики", response); + + if (response.error) throw response.error; + if (!response.data) throw new Error("Quiz not found"); + + const hasAiResult = response.data.items.some((item) => item.typ === "result" && status === "ai"); + + if (hasAiResult) { + page++; // Увеличиваем страницу + resultRetryCount++; + continue; + } + + // Если result вопросов нет, сохраняем данные для второго цикла + responseData = response; + break; + } catch (error) { + lastError = error as Error; + resultRetryCount++; + if (resultRetryCount >= maxRetries) break; + await new Promise((resolve) => setTimeout(resolve, 1000 * resultRetryCount)); + } } - const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse)); + if (!responseData) { + throw lastError || new Error("Failed to get quiz data after result retries"); + } + + // Второй цикл - обработка пустого массива items (без изменения page) + let isEmpty = !responseData.data?.items.length; + let emptyRetryCount = 0; + while (isEmpty && emptyRetryCount < maxRetries) { + try { + await new Promise((resolve) => setTimeout(resolve, 1000)); + const response = await getData(quizId); + + if (response.error) throw response.error; + if (!response.data) throw new Error("Quiz not found"); + + isEmpty = !response.data.items.length; + if (!isEmpty) { + responseData = response; // Обновляем данные + } + emptyRetryCount++; + } catch (error) { + lastError = error as Error; + emptyRetryCount++; + if (emptyRetryCount >= maxRetries) break; + } + } + + if (isEmpty) { + throw new Error("Items array is empty after maximum retries"); + } + + // Финальная обработка успешного ответа + const quizSettings = replaceSpacesToEmptyLines(parseQuizData(responseData.data)); const res = JSON.parse( JSON.stringify({ data: quizSettings }) .replaceAll(/\\" \\"/g, '""') .replaceAll(/" "/g, '""') ).data as QuizSettings; - res.recentlyCompleted = response.isRecentlyCompleted; + + res.recentlyCompleted = responseData.isRecentlyCompleted; + return res; } diff --git a/lib/components/QuizAnswerer.tsx b/lib/components/QuizAnswerer.tsx index 451a1b3..c733d39 100644 --- a/lib/components/QuizAnswerer.tsx +++ b/lib/components/QuizAnswerer.tsx @@ -77,12 +77,12 @@ function QuizAnswererInner({ if (error) return ; // if (!data) return ; quizSettings ??= data; - if (!quizSettings) return ; + if (!quizSettings) return ; if (quizSettings.questions.length === 1 && quizSettings?.settings.cfg.noStartPage) - return ; - // if (quizSettings.questions.length === 1) return ; - if (!quizId) return ; + return ; + // if (quizSettings.questions.length === 1) return ; + if (!quizId) return ; const quizContainer = ( { gap: "10px", }} > - {stepNumber !== null && ( + {stepNumber !== null && settings.status !== "ai" && ( Вопрос {stepNumber} из {questionsAmount} diff --git a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx index 6d71ce7..bfa819a 100644 --- a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx +++ b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx @@ -106,7 +106,7 @@ export default function ViewPublicationPage() { } nextButton={ { moveToNextQuestion(); diff --git a/lib/contexts/QuizDataContext.ts b/lib/contexts/QuizDataContext.ts index 95d39fe..a2c3261 100644 --- a/lib/contexts/QuizDataContext.ts +++ b/lib/contexts/QuizDataContext.ts @@ -1,5 +1,6 @@ import { QuizSettings } from "@model/settingsData"; import { createContext, useContext } from "react"; +import { AnyTypedQuizQuestion } from ".."; export const QuizSettingsContext = createContext< | (QuizSettings & { diff --git a/lib/model/api/getQuizData.ts b/lib/model/api/getQuizData.ts index 21f685c..384ef1b 100644 --- a/lib/model/api/getQuizData.ts +++ b/lib/model/api/getQuizData.ts @@ -12,6 +12,7 @@ export interface GetQuizDataResponse { due: number; delay: number; pausable: boolean; + status: "start" | "stop" | "ai"; }; items: { id: number; @@ -49,6 +50,7 @@ export function parseQuizData(quizDataResponse: GetQuizDataResponse): Omit { + setQuestions((prev) => [...prev, question]); + }; + //Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page. //За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page const sortedQuestions = useMemo(() => { @@ -200,7 +210,12 @@ export function useQuestionFlowControl() { }, [prevQuestion]); //рычаг управления из визуала в эту функцию - const moveToNextQuestion = useCallback(() => { + const moveToNextQuestion = useCallback(async () => { + if (isgetting) return; + isgetting = true; + const data = await getQuizData(quizId, settings.status); + addQuestion(data.questions[0]); + isgetting = false; if (!nextQuestion) throw new Error("Next question not found"); // Засчитываем переход с вопроса дальше @@ -246,7 +261,8 @@ export function useQuestionFlowControl() { return { currentQuestion, - currentQuestionStepNumber: linearQuestionIndex === null ? null : linearQuestionIndex + 1, + currentQuestionStepNumber: + settings.status === "ai" ? null : linearQuestionIndex === null ? null : linearQuestionIndex + 1, nextQuestion, isNextButtonEnabled, isPreviousButtonEnabled, From 03c1cec48fa07d47af69f9c00cc799a2f4d644bd Mon Sep 17 00:00:00 2001 From: Nastya Date: Wed, 30 Apr 2025 20:59:50 +0300 Subject: [PATCH 2/3] init --- lib/api/hooks.ts | 2 +- lib/api/quizRelase.ts | 11 +++- lib/api/useQuizGetNext.ts | 32 ++++++++++ lib/components/QuizAnswerer.tsx | 58 +++++++++++++++--- .../ViewPublicationPage/ApologyPage.tsx | 1 + lib/components/ViewPublicationPage/Footer.tsx | 4 +- lib/contexts/QuizDataContext.ts | 19 +++--- lib/utils/hooks/useQuestionFlowControl.ts | 61 +++++++++++++------ 8 files changed, 144 insertions(+), 44 deletions(-) create mode 100644 lib/api/useQuizGetNext.ts diff --git a/lib/api/hooks.ts b/lib/api/hooks.ts index e54c8c1..5550583 100644 --- a/lib/api/hooks.ts +++ b/lib/api/hooks.ts @@ -2,7 +2,7 @@ import useSWR from "swr"; import { getQuizData } from "./quizRelase"; export function useQuizData(quizId: string, preview: boolean = false) { - return useSWR(preview ? null : ["quizData", quizId], (params) => getQuizData(params[1]), { + return useSWR(preview ? null : ["quizData", quizId], (params) => getQuizData({ quizId: params[1] }), { revalidateOnFocus: false, revalidateOnReconnect: false, shouldRetryOnError: false, diff --git a/lib/api/quizRelase.ts b/lib/api/quizRelase.ts index de0e77e..fbc61ba 100644 --- a/lib/api/quizRelase.ts +++ b/lib/api/quizRelase.ts @@ -120,7 +120,15 @@ export async function getData(quizId: string): Promise<{ } } -export async function getQuizData(quizId: string, status?: string): Promise { +export async function getQuizData({ + quizId, + status, + type = "", +}: { + quizId: string; + status?: string; + type?: string; +}): Promise { let maxRetries = 50; if (!quizId) throw new Error("No quiz id"); @@ -197,7 +205,6 @@ export async function getQuizData(quizId: string, status?: string): Promise { + const { addQuestion, quizId, settings } = useQuizSettings(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [currentPage, setCurrentPage] = useState(1); + + const loadMoreQuestions = async () => { + setIsLoading(true); + setError(null); + + try { + const data = await getQuizData({ quizId, type: settings.cfg.type || "", status: settings.status }); + const newQuestion = data?.questions[0]; + if (newQuestion) { + newQuestion.page = currentPage; + addQuestion(newQuestion); + setCurrentPage((old) => old++); + return newQuestion; + } + } catch (err) { + setError(err as Error); + } finally { + setIsLoading(false); + } + }; + + return { loadMoreQuestions, isLoading, error, currentPage }; +}; diff --git a/lib/components/QuizAnswerer.tsx b/lib/components/QuizAnswerer.tsx index c733d39..8525307 100644 --- a/lib/components/QuizAnswerer.tsx +++ b/lib/components/QuizAnswerer.tsx @@ -3,7 +3,7 @@ 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 { QuizSettingsContext, QuizSettingsContextValue } from "@contexts/QuizDataContext"; import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext"; import type { QuizSettings } from "@model/settingsData"; import { Box, CssBaseline, ScopedCssBaseline, ThemeProvider } from "@mui/material"; @@ -14,13 +14,15 @@ import { handleComponentError } from "@utils/handleComponentError"; import lightTheme from "@utils/themes/light"; import moment from "moment"; import { SnackbarProvider } from "notistack"; -import { startTransition, useEffect, useLayoutEffect, useRef, useState } from "react"; +import { startTransition, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { ErrorBoundary } from "react-error-boundary"; import { ApologyPage } from "./ViewPublicationPage/ApologyPage"; import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage"; import { HelmetProvider } from "react-helmet-async"; import "moment/dist/locale/ru"; +import { AnyTypedQuizQuestion } from ".."; +import { produce } from "immer"; moment.locale("ru"); const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText; @@ -32,7 +34,16 @@ type Props = { className?: string; disableGlobalCss?: boolean; }; - +function isQuizSettingsValid(data: any): data is QuizSettings { + return ( + data && + Array.isArray(data.questions) && + data.settings && + typeof data.cnt === "number" && + typeof data.recentlyCompleted === "boolean" && + typeof data.show_badge === "boolean" + ); +} function QuizAnswererInner({ quizSettings, quizId, @@ -47,6 +58,14 @@ function QuizAnswererInner({ const { data, error, isLoading } = useQuizData(quizId, preview); const vkMetrics = useVkMetricsGoals(quizSettings?.settings.cfg.vkMetricsNumber); const yandexMetrics = useYandexMetricsGoals(quizSettings?.settings.cfg.yandexMetricsNumber); + const [localQuizSettings, setLocalQuizSettings] = useState(quizSettings); + + // Добавляем эффект для обновления localQuizSettings при получении новых данных + useEffect(() => { + if (data && !quizSettings) { + setLocalQuizSettings(data); + } + }, [data, quizSettings]); useEffect(() => { setTimeout(() => { @@ -73,15 +92,36 @@ function QuizAnswererInner({ }; }, []); + const finalQuizSettings = quizSettings || localQuizSettings; + + const contextValue = useMemo( + () => ({ + ...(finalQuizSettings as QuizSettings), + quizId, + preview, + changeFaviconAndTitle, + addQuestion: (newQuestion: AnyTypedQuizQuestion) => { + setLocalQuizSettings((prev) => { + if (!prev) return prev; + + return produce(prev, (draft) => { + draft.questions.push(newQuestion); + }); + }); + }, + }), + [quizId, preview, changeFaviconAndTitle, finalQuizSettings] + ); + if (isLoading) return ; if (error) return ; - // if (!data) return ; - quizSettings ??= data; - if (!quizSettings) return ; - if (quizSettings.questions.length === 1 && quizSettings?.settings.cfg.noStartPage) + if (!finalQuizSettings) return ; + if (!finalQuizSettings.questions || finalQuizSettings.questions.length === 0) + return ; + + if (finalQuizSettings.questions.length === 1 && finalQuizSettings?.settings.cfg.noStartPage) return ; - // if (quizSettings.questions.length === 1) return ; if (!quizId) return ; const quizContainer = ( @@ -106,7 +146,7 @@ function QuizAnswererInner({ return ( - + {disableGlobalCss ? ( ; export const ApologyPage = ({ error }: Props) => { + console.log(error); let message = "Что-то пошло не так"; if (error.response?.data === "quiz is inactive") message = "Квиз не активирован"; diff --git a/lib/components/ViewPublicationPage/Footer.tsx b/lib/components/ViewPublicationPage/Footer.tsx index c2be2c6..8d7c8b0 100644 --- a/lib/components/ViewPublicationPage/Footer.tsx +++ b/lib/components/ViewPublicationPage/Footer.tsx @@ -13,7 +13,7 @@ type FooterProps = { export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { const theme = useTheme(); - const { questions, settings } = useQuizSettings(); + const { questions, settings, cnt } = useQuizSettings(); const questionsAmount = questions.filter(({ type }) => type !== "result").length; return ( @@ -41,7 +41,7 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { {stepNumber !== null && settings.status !== "ai" && ( - Вопрос {stepNumber} из {questionsAmount} + Вопрос {stepNumber} из {cnt} (null); +export type QuizSettingsContextValue = QuizSettings & { + quizId: string; + preview: boolean; + changeFaviconAndTitle: boolean; + addQuestion: (newQuestion: AnyTypedQuizQuestion) => void; +}; + +export const QuizSettingsContext = createContext(null); export const useQuizSettings = () => { const quizSettings = useContext(QuizSettingsContext); if (quizSettings === null) throw new Error("QuizSettings context is null"); - return quizSettings; }; diff --git a/lib/utils/hooks/useQuestionFlowControl.ts b/lib/utils/hooks/useQuestionFlowControl.ts index 18cc9fe..fccb8e9 100644 --- a/lib/utils/hooks/useQuestionFlowControl.ts +++ b/lib/utils/hooks/useQuestionFlowControl.ts @@ -11,17 +11,16 @@ import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals"; import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals"; import { AnyTypedQuizQuestion } from "@/index"; import { getQuizData } from "@/api/quizRelase"; +import { useQuizGetNext } from "@/api/useQuizGetNext"; let isgetting = false; export function useQuestionFlowControl() { //Получаем инфо о квизе и список вопросов. - const { settings, questions: initialQuestions, quizId } = useQuizSettings(); - const [questions, setQuestions] = useState(initialQuestions); + const { loadMoreQuestions } = useQuizGetNext(); + const { settings, questions, quizId, cnt } = useQuizSettings(); - const addQuestion = (question: AnyTypedQuizQuestion) => { - setQuestions((prev) => [...prev, question]); - }; + console.log(questions); //Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page. //За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page @@ -43,7 +42,7 @@ export function useQuestionFlowControl() { //Изменение стейта (переменной currentQuestionId) ведёт к пересчёту что же за объект сейчас используется. Мы каждый раз просто ищем в списке const currentQuestion = sortedQuestions.find((question) => question.id === currentQuestionId) ?? sortedQuestions[0]; - // console.log(currentQuestion) + console.log(currentQuestion); //Индекс текущего вопроса только если квиз линейный const linearQuestionIndex = //: number | null @@ -123,7 +122,7 @@ export function useQuestionFlowControl() { return nextQuestionIdPointsLogic(); } return nextQuestionIdMainLogic(); - }, [nextQuestionIdMainLogic, nextQuestionIdPointsLogic, settings.cfg.score]); + }, [nextQuestionIdMainLogic, nextQuestionIdPointsLogic, settings.cfg.score, questions]); //Поиск предыдущго вопроса либо по индексу либо по id родителя const prevQuestion = @@ -211,21 +210,39 @@ export function useQuestionFlowControl() { //рычаг управления из визуала в эту функцию const moveToNextQuestion = useCallback(async () => { - if (isgetting) return; - isgetting = true; - const data = await getQuizData(quizId, settings.status); - addQuestion(data.questions[0]); - isgetting = false; - if (!nextQuestion) throw new Error("Next question not found"); + // Если есть следующий вопрос в уже загруженных - используем его + if (nextQuestion) { + vkMetrics.questionPassed(currentQuestion.id); + yandexMetrics.questionPassed(currentQuestion.id); - // Засчитываем переход с вопроса дальше - vkMetrics.questionPassed(currentQuestion.id); - yandexMetrics.questionPassed(currentQuestion.id); + if (nextQuestion.type === "result") return showResult(); + setCurrentQuestionId(nextQuestion.id); + return; + } - if (nextQuestion.type === "result") return showResult(); - - setCurrentQuestionId(nextQuestion.id); - }, [currentQuestion.id, nextQuestion, showResult, vkMetrics, yandexMetrics]); + // Если следующего нет - загружаем новый + try { + const newQuestion = await loadMoreQuestions(); + if (newQuestion) { + vkMetrics.questionPassed(currentQuestion.id); + yandexMetrics.questionPassed(currentQuestion.id); + console.log("МЫ ПАЛУЧИЛИ НОВЫЙ ВОПРОС"); + console.log(newQuestion); + setCurrentQuestionId(newQuestion.id); + } + } catch (error) { + enqueueSnackbar("Ошибка загрузки следующего вопроса"); + } + }, [ + currentQuestion.id, + nextQuestion, + showResult, + vkMetrics, + yandexMetrics, + linearQuestionIndex, + loadMoreQuestions, + questions, + ]); //рычаг управления из визуала в эту функцию const setQuestion = useCallback( @@ -249,6 +266,10 @@ export function useQuestionFlowControl() { return hasAnswer; } + console.log(linearQuestionIndex); + console.log(questions.length); + console.log(cnt); + if (linearQuestionIndex !== null && questions.length < cnt) return true; return Boolean(nextQuestion); }, [answers, currentQuestion, nextQuestion]); From 6ef147fa4a45a30f1ec78d6a9bef4bbd7cfaedf5 Mon Sep 17 00:00:00 2001 From: Nastya Date: Thu, 1 May 2025 16:15:54 +0300 Subject: [PATCH 3/3] zustand --- lib/api/hooks.ts | 2 +- lib/api/quizRelase.ts | 60 +++++++----- lib/api/useQuizGetNext.ts | 36 ++++---- lib/components/QuizAnswerer.tsx | 92 +++++++++---------- .../ContactForm/ContactForm.tsx | 4 +- .../ContactForm/CustomInput/CustomInput.tsx | 4 +- .../ContactForm/Inputs/Inputs.tsx | 4 +- lib/components/ViewPublicationPage/Footer.tsx | 7 +- .../PointSystemResultList.tsx | 4 +- .../ViewPublicationPage/Question.tsx | 4 +- .../ViewPublicationPage/QuestionSelect.tsx | 4 +- .../ViewPublicationPage/ResultForm.tsx | 4 +- .../StartPageDesktop.tsx | 6 +- .../StartPageMobile.tsx | 6 +- .../StartPageViewPublication/index.tsx | 4 +- .../ViewPublicationPage.tsx | 4 +- .../questions/Date/DatePicker.tsx | 4 +- .../questions/Date/DateRange.tsx | 4 +- .../questions/Emoji/EmojiVariant.tsx | 4 +- .../questions/File/UploadFile.tsx | 4 +- .../questions/File/UploadedFile.tsx | 4 +- .../questions/Images/ImageVariant.tsx | 4 +- .../questions/Number/index.tsx | 4 +- .../questions/Select/index.tsx | 4 +- .../questions/Text/TextNormal.tsx | 4 +- .../questions/Text/TextSpecial.tsx | 4 +- .../questions/Text/TextSpecialHorisontal.tsx | 4 +- .../questions/Text/index.tsx | 4 +- .../questions/Variant/VariantItem.tsx | 5 +- .../questions/Varimg/VarimgVariant.tsx | 4 +- .../ViewPublicationPage/tools/NextButton.tsx | 4 +- .../ViewPublicationPage/tools/PrevButton.tsx | 4 +- lib/contexts/QuizDataContext.ts | 18 ---- lib/stores/useQuizStore.ts | 39 ++++++++ lib/utils/hooks/useQuestionFlowControl.ts | 5 +- 35 files changed, 202 insertions(+), 170 deletions(-) delete mode 100644 lib/contexts/QuizDataContext.ts create mode 100644 lib/stores/useQuizStore.ts diff --git a/lib/api/hooks.ts b/lib/api/hooks.ts index 5550583..e54c8c1 100644 --- a/lib/api/hooks.ts +++ b/lib/api/hooks.ts @@ -2,7 +2,7 @@ import useSWR from "swr"; import { getQuizData } from "./quizRelase"; export function useQuizData(quizId: string, preview: boolean = false) { - return useSWR(preview ? null : ["quizData", quizId], (params) => getQuizData({ quizId: params[1] }), { + return useSWR(preview ? null : ["quizData", quizId], (params) => getQuizData(params[1]), { revalidateOnFocus: false, revalidateOnReconnect: false, shouldRetryOnError: false, diff --git a/lib/api/quizRelase.ts b/lib/api/quizRelase.ts index fbc61ba..cd2f05a 100644 --- a/lib/api/quizRelase.ts +++ b/lib/api/quizRelase.ts @@ -71,8 +71,8 @@ export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestPara method: "POST", }); }; -let page = 0; -export async function getData(quizId: string): Promise<{ + +export async function getData({ quizId, page, status }: { quizId: string; page?: number; status?: string }): Promise<{ data: GetQuizDataResponse | null; isRecentlyCompleted: boolean; error?: AxiosError; @@ -92,18 +92,16 @@ export async function getData(quizId: string): Promise<{ }, data: { quiz_id: quizId, - limit: 1, - page, - need_config: page === 0, + limit: status === "ai" ? 1 : 100, + page: status === "ai" ? page : 0, + need_config: true, }, } ); - console.log(data); - if (data.items.length) page++; const sessions = JSON.parse(localStorage.getItem("sessions") || "{}"); //Тут ещё проверка на антифрод без парса конфига. Нам не интересно время если не нужно запрещать проходить чаще чем в сутки - if (!page && typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) { + if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) { // unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше if (Date.now() - sessions[quizId] < 86400000) { return { data, isRecentlyCompleted: true }; @@ -120,15 +118,32 @@ export async function getData(quizId: string): Promise<{ } } -export async function getQuizData({ - quizId, - status, - type = "", -}: { - quizId: string; - status?: string; - type?: string; -}): Promise { +export async function getQuizData(quizId: string) { + if (!quizId) throw new Error("No quiz id"); + + const response = await getData({ quizId }); + const quizDataResponse = response.data; + + if (response.error) { + throw response.error; + } + if (!quizDataResponse) { + throw new Error("Quiz not found"); + } + + const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse)); + + const res = JSON.parse( + JSON.stringify({ data: quizSettings }) + .replaceAll(/\\" \\"/g, '""') + .replaceAll(/" "/g, '""') + ).data as QuizSettings; + res.recentlyCompleted = response.isRecentlyCompleted; + return res; +} + +let page = 1; +export async function getQuizDataAI(quizId: string) { let maxRetries = 50; if (!quizId) throw new Error("No quiz id"); @@ -139,13 +154,13 @@ export async function getQuizData({ let resultRetryCount = 0; while (resultRetryCount < maxRetries) { try { - const response = await getData(quizId); + const response = await getData({ quizId, page, status: "ai" }); console.log("ф-я аналитики", response); if (response.error) throw response.error; if (!response.data) throw new Error("Quiz not found"); - const hasAiResult = response.data.items.some((item) => item.typ === "result" && status === "ai"); + const hasAiResult = response.data.items.some((item) => item.typ === "result"); if (hasAiResult) { page++; // Увеличиваем страницу @@ -160,7 +175,7 @@ export async function getQuizData({ lastError = error as Error; resultRetryCount++; if (resultRetryCount >= maxRetries) break; - await new Promise((resolve) => setTimeout(resolve, 1000 * resultRetryCount)); + await new Promise((resolve) => setTimeout(resolve, 1500 * resultRetryCount)); } } @@ -174,7 +189,7 @@ export async function getQuizData({ while (isEmpty && emptyRetryCount < maxRetries) { try { await new Promise((resolve) => setTimeout(resolve, 1000)); - const response = await getData(quizId); + const response = await getData({ quizId, page, status: "ai" }); if (response.error) throw response.error; if (!response.data) throw new Error("Quiz not found"); @@ -205,6 +220,7 @@ export async function getQuizData({ ).data as QuizSettings; res.recentlyCompleted = responseData.isRecentlyCompleted; + return res; } @@ -216,6 +232,8 @@ type SendAnswerProps = { }; export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) { + console.log("qid"); + console.log(qid); if (preview) return; const formData = new FormData(); diff --git a/lib/api/useQuizGetNext.ts b/lib/api/useQuizGetNext.ts index 7f93a0a..4e287f2 100644 --- a/lib/api/useQuizGetNext.ts +++ b/lib/api/useQuizGetNext.ts @@ -1,30 +1,32 @@ -import { useQuizSettings } from "@/contexts/QuizDataContext"; import { useState } from "react"; -import { getQuizData } from "./quizRelase"; +import { getQuizDataAI } from "./quizRelase"; +import { addQuestion, useQuizStore } from "@/stores/useQuizStore"; export const useQuizGetNext = () => { - const { addQuestion, quizId, settings } = useQuizSettings(); + const { quizId, settings } = useQuizStore(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const loadMoreQuestions = async () => { - setIsLoading(true); - setError(null); + if (settings.status === "ai") { + setIsLoading(true); + setError(null); - try { - const data = await getQuizData({ quizId, type: settings.cfg.type || "", status: settings.status }); - const newQuestion = data?.questions[0]; - if (newQuestion) { - newQuestion.page = currentPage; - addQuestion(newQuestion); - setCurrentPage((old) => old++); - return newQuestion; + try { + const data = await getQuizDataAI(quizId); + const newQuestion = data?.questions[0]; + if (newQuestion) { + newQuestion.page = currentPage; + addQuestion(newQuestion); + setCurrentPage((old) => old++); + return newQuestion; + } + } catch (err) { + setError(err as Error); + } finally { + setIsLoading(false); } - } catch (err) { - setError(err as Error); - } finally { - setIsLoading(false); } }; diff --git a/lib/components/QuizAnswerer.tsx b/lib/components/QuizAnswerer.tsx index 8525307..7e8216b 100644 --- a/lib/components/QuizAnswerer.tsx +++ b/lib/components/QuizAnswerer.tsx @@ -3,7 +3,6 @@ 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, QuizSettingsContextValue } from "@contexts/QuizDataContext"; import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext"; import type { QuizSettings } from "@model/settingsData"; import { Box, CssBaseline, ScopedCssBaseline, ThemeProvider } from "@mui/material"; @@ -21,8 +20,7 @@ import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage"; import { HelmetProvider } from "react-helmet-async"; import "moment/dist/locale/ru"; -import { AnyTypedQuizQuestion } from ".."; -import { produce } from "immer"; +import { useQuizStore, setQuizData, addquizid } from "@/stores/useQuizStore"; moment.locale("ru"); const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText; @@ -58,14 +56,19 @@ function QuizAnswererInner({ const { data, error, isLoading } = useQuizData(quizId, preview); const vkMetrics = useVkMetricsGoals(quizSettings?.settings.cfg.vkMetricsNumber); const yandexMetrics = useYandexMetricsGoals(quizSettings?.settings.cfg.yandexMetricsNumber); - const [localQuizSettings, setLocalQuizSettings] = useState(quizSettings); + const r = useQuizStore(); + const { settings, questions } = useQuizStore(); - // Добавляем эффект для обновления localQuizSettings при получении новых данных useEffect(() => { - if (data && !quizSettings) { - setLocalQuizSettings(data); - } - }, [data, quizSettings]); + addquizid(quizId); + }, []); + + useEffect(() => { + console.log(settings); + console.log(questions); + console.log("r"); + console.log(r); + }, [questions, settings]); useEffect(() => { setTimeout(() => { @@ -74,6 +77,18 @@ function QuizAnswererInner({ }, 4000); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + console.log("got data"); + console.log(quizSettings); + console.log(data); + const quiz = quizSettings || data; + console.log("quiz"); + console.log(quiz); + if (quiz !== undefined) { + console.log("is not undefined"); + setQuizData(quiz); + } + }, [quizSettings, data]); useLayoutEffect(() => { if (rootContainerRef.current) setRootContainerWidth(rootContainerRef.current.clientWidth); @@ -92,36 +107,15 @@ function QuizAnswererInner({ }; }, []); - const finalQuizSettings = quizSettings || localQuizSettings; - - const contextValue = useMemo( - () => ({ - ...(finalQuizSettings as QuizSettings), - quizId, - preview, - changeFaviconAndTitle, - addQuestion: (newQuestion: AnyTypedQuizQuestion) => { - setLocalQuizSettings((prev) => { - if (!prev) return prev; - - return produce(prev, (draft) => { - draft.questions.push(newQuestion); - }); - }); - }, - }), - [quizId, preview, changeFaviconAndTitle, finalQuizSettings] - ); - + console.log("settings"); + console.log(settings); if (isLoading) return ; if (error) return ; - if (!finalQuizSettings) return ; - if (!finalQuizSettings.questions || finalQuizSettings.questions.length === 0) - return ; + if (Object.keys(settings).length == 0) return ; + if (questions.length === 0) return ; - if (finalQuizSettings.questions.length === 1 && finalQuizSettings?.settings.cfg.noStartPage) - return ; + if (questions.length === 1 && settings.cfg.noStartPage) return ; if (!quizId) return ; const quizContainer = ( @@ -146,21 +140,19 @@ function QuizAnswererInner({ return ( - - {disableGlobalCss ? ( - - {quizContainer} - - ) : ( - {quizContainer} - )} - + {disableGlobalCss ? ( + + {quizContainer} + + ) : ( + {quizContainer} + )} ); diff --git a/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx b/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx index c57d4c9..45baddb 100644 --- a/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/ContactForm.tsx @@ -8,7 +8,6 @@ import { Inputs } from "@/components/ViewPublicationPage/ContactForm/Inputs/Inpu import { ContactTextBlock } from "./ContactTextBlock"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { sendFC, SendFCParams } from "@api/quizRelase"; @@ -25,6 +24,7 @@ import type { FormContactFieldData, FormContactFieldName } from "@model/settings import type { QuizQuestionResult } from "@model/questionTypes/result"; import type { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; import { isProduction } from "@/utils/defineDomain"; +import { useQuizStore } from "@/stores/useQuizStore"; type Props = { currentQuestion: AnyTypedQuizQuestion; @@ -35,7 +35,7 @@ const isDisableEmail = window.location.pathname.includes("/377c7570-1bee-4320-ac export const ContactForm = ({ currentQuestion, onShowResult }: Props) => { const theme = useTheme(); - const { settings, questions, quizId, show_badge, preview } = useQuizSettings(); + const { settings, questions, quizId, show_badge, preview } = useQuizStore(); 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 de71e9e..6d5cb6a 100644 --- a/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx @@ -1,11 +1,11 @@ import { Box, InputAdornment, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext.ts"; -import { useQuizSettings } from "@contexts/QuizDataContext.ts"; import { useIMask, IMask } from "react-imask"; import { quizThemes } from "@utils/themes/Publication/themePublication.ts"; import { ChangeEvent, FC, HTMLInputTypeAttribute, useEffect, useState } from "react"; import { CountrySelector } from "@/components/ViewPublicationPage/ContactForm/CustomInput/CountrySelector/CountrySelector.tsx"; import { phoneMasksByCountry } from "@utils/phoneMasksByCountry.tsx"; +import { useQuizStore } from "@/stores/useQuizStore"; type InputProps = { title: string; @@ -37,7 +37,7 @@ function phoneChange(e: ChangeEvent, mask: string) { export const CustomInput = ({ title, desc, Icon, onChange, onChangePhone, isPhone, type, value }: InputProps) => { const theme = useTheme(); const isMobile = useRootContainerSize() < 600; - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const [mask, setMask] = useState(phoneMasksByCountry["RU"][1]); // const { ref } = useIMask({ mask }); diff --git a/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx b/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx index 19f9437..d332251 100644 --- a/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx +++ b/lib/components/ViewPublicationPage/ContactForm/Inputs/Inputs.tsx @@ -1,4 +1,3 @@ -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"; @@ -7,6 +6,7 @@ import { Dispatch, SetStateAction } from "react"; import { CustomInput } from "@/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx"; import PhoneIcon from "@icons/ContactFormIcon/PhoneIcon.tsx"; import PhoneInput from "react-phone-number-input"; +import { useQuizStore } from "@/stores/useQuizStore"; type InputsProps = { name: string; @@ -37,7 +37,7 @@ export const Inputs = ({ setAdress, crutch, }: InputsProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 8d7c8b0..b0915b3 100644 --- a/lib/components/ViewPublicationPage/Footer.tsx +++ b/lib/components/ViewPublicationPage/Footer.tsx @@ -1,9 +1,8 @@ import { ReactNode } from "react"; import { Box, Typography, useTheme } from "@mui/material"; -import { useQuizSettings } from "@contexts/QuizDataContext"; - import Stepper from "@ui_kit/Stepper"; +import { useQuizStore } from "@/stores/useQuizStore"; type FooterProps = { stepNumber: number | null; @@ -13,7 +12,7 @@ type FooterProps = { export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { const theme = useTheme(); - const { questions, settings, cnt } = useQuizSettings(); + const { questions, settings } = useQuizStore(); const questionsAmount = questions.filter(({ type }) => type !== "result").length; return ( @@ -41,7 +40,7 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { {stepNumber !== null && settings.status !== "ai" && ( - Вопрос {stepNumber} из {cnt} + Вопрос {stepNumber} из {questionsAmount} { const theme = useTheme(); - const { questions } = useQuizSettings(); + const { questions } = useQuizStore(); const answers = useQuizViewStore((state) => state.answers); const questionsWothoutResult = questions.filter( diff --git a/lib/components/ViewPublicationPage/Question.tsx b/lib/components/ViewPublicationPage/Question.tsx index 0be947f..eb45fa3 100644 --- a/lib/components/ViewPublicationPage/Question.tsx +++ b/lib/components/ViewPublicationPage/Question.tsx @@ -15,7 +15,6 @@ import { Varimg } from "./questions/Varimg"; import type { RealTypedQuizQuestion } from "../../model/questionTypes/shared"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { NameplateLogoFQ } from "@icons/NameplateLogoFQ"; import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark"; import { notReachable } from "@utils/notReachable"; @@ -24,6 +23,7 @@ import { quizThemes } from "@utils/themes/Publication/themePublication"; import { DESIGN_LIST } from "@/utils/designList"; import { type ReactNode } from "react"; import { isProduction } from "@/utils/defineDomain"; +import { useQuizStore } from "@/stores/useQuizStore"; type Props = { currentQuestion: RealTypedQuizQuestion; @@ -41,7 +41,7 @@ export const Question = ({ questionSelect, }: Props) => { const theme = useTheme(); - const { settings, show_badge, quizId } = useQuizSettings(); + const { settings, show_badge, quizId } = useQuizStore(); return ( { const theme = useTheme(); const isMobile = useRootContainerSize() < 650; const isTablet = useRootContainerSize() < 1000; - const { settings, show_badge, quizId, questions, preview } = useQuizSettings(); + const { settings, show_badge, quizId, questions, preview } = useQuizStore(); const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep); //Список засчитанных баллов для балловых квизов const pointsSum = useQuizViewStore((state) => state.pointsSum); diff --git a/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx b/lib/components/ViewPublicationPage/StartPageViewPublication/StartPageDesktop.tsx index 514dbce..6e8d3b6 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 { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; 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 } = useQuizSettings(); + const { settings } = useQuizStore(); return ( { const isTablet = useRootContainerSize() < 1100; - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); return ( ; const StandartMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); return ( { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); return ( { const theme = useTheme(); - const { settings, show_badge, quizId, questions } = useQuizSettings(); + const { settings, show_badge, quizId, questions } = useQuizStore(); const { isMobileDevice } = useUADevice(); const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep); diff --git a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx index bfa819a..393b691 100644 --- a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx +++ b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx @@ -3,7 +3,6 @@ import { extractImageLinksFromQuestion } from "@/utils/extractImageLinks"; import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics"; import { useYandexMetrics } from "@/utils/hooks/metrics/useYandexMetrics"; import { sendQuestionAnswer } from "@/utils/sendQuestionAnswer"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { ThemeProvider, Typography } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import { useQuestionFlowControl } from "@utils/hooks/useQuestionFlowControl"; @@ -19,9 +18,10 @@ import { StartPageViewPublication } from "./StartPageViewPublication"; import NextButton from "./tools/NextButton"; import PrevButton from "./tools/PrevButton"; import unscreen from "@/ui_kit/unscreen"; +import { useQuizStore } from "@/stores/useQuizStore"; export default function ViewPublicationPage() { - const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle, questions } = useQuizSettings(); + const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle } = useQuizStore(); const answers = useQuizViewStore((state) => state.answers); const ownVariants = useQuizViewStore((state) => state.ownVariants); let currentQuizStep = useQuizViewStore((state) => state.currentQuizStep); diff --git a/lib/components/ViewPublicationPage/questions/Date/DatePicker.tsx b/lib/components/ViewPublicationPage/questions/Date/DatePicker.tsx index 7a42ae0..a388055 100644 --- a/lib/components/ViewPublicationPage/questions/Date/DatePicker.tsx +++ b/lib/components/ViewPublicationPage/questions/Date/DatePicker.tsx @@ -1,5 +1,5 @@ import { useQuizViewStore } from "@/stores/quizView"; -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import CalendarIcon from "@icons/CalendarIcon"; import type { QuizQuestionDate } from "@model/questionTypes/date"; import { Box, Typography, useTheme } from "@mui/material"; @@ -13,7 +13,7 @@ type DateProps = { }; export default ({ currentQuestion }: DateProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const answers = useQuizViewStore((state) => state.answers); const { updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Date/DateRange.tsx b/lib/components/ViewPublicationPage/questions/Date/DateRange.tsx index ff2462b..8a72b7d 100644 --- a/lib/components/ViewPublicationPage/questions/Date/DateRange.tsx +++ b/lib/components/ViewPublicationPage/questions/Date/DateRange.tsx @@ -1,4 +1,3 @@ -import { useQuizSettings } from "@/contexts/QuizDataContext"; import { useQuizViewStore } from "@/stores/quizView"; import type { QuizQuestionDate } from "@model/questionTypes/date"; import { DateCalendar } from "@mui/x-date-pickers"; @@ -7,6 +6,7 @@ import type { Moment } from "moment"; import moment from "moment"; import { Box, Paper, TextField, useTheme } from "@mui/material"; import { useRootContainerSize } from "@/contexts/RootContainerWidthContext"; +import { useQuizStore } from "@/stores/useQuizStore"; type DateProps = { currentQuestion: QuizQuestionDate; @@ -16,7 +16,7 @@ export default ({ currentQuestion }: DateProps) => { const theme = useTheme(); const today = moment(); const isMobile = useRootContainerSize() < 690; - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { updateAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); diff --git a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx index 2b4e869..92d40f8 100644 --- a/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Emoji/EmojiVariant.tsx @@ -1,5 +1,5 @@ import type { QuestionVariant } from "@/model/questionTypes/shared"; -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import { Box, Checkbox, @@ -104,7 +104,7 @@ export const EmojiVariant = ({ questionLargeCheck, ownPlaceholder, }: EmojiVariantProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 2ec4a28..2f13445 100644 --- a/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx +++ b/lib/components/ViewPublicationPage/questions/File/UploadFile.tsx @@ -3,7 +3,6 @@ import { Box, ButtonBase, Skeleton, Typography, useTheme } from "@mui/material"; import { enqueueSnackbar } from "notistack"; import { sendAnswer, sendFile } from "@api/quizRelase"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { useQuizViewStore } from "@stores/quizView"; @@ -18,6 +17,7 @@ import UploadIcon from "@icons/UploadIcon"; import type { QuizQuestionFile } from "@model/questionTypes/file"; import type { ModalWarningType } from "./index"; +import { useQuizStore } from "@/stores/useQuizStore"; type UploadFileProps = { currentQuestion: QuizQuestionFile; @@ -27,7 +27,7 @@ type UploadFileProps = { }; export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, setIsSending }: UploadFileProps) => { - const { quizId, preview } = useQuizSettings(); + const { quizId, preview } = useQuizStore(); 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 ca6b63a..01b13d4 100644 --- a/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx +++ b/lib/components/ViewPublicationPage/questions/File/UploadedFile.tsx @@ -1,12 +1,12 @@ import { Box, IconButton, Typography, useTheme } from "@mui/material"; import { sendAnswer } from "@api/quizRelase"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useQuizViewStore } from "@stores/quizView"; import CloseBold from "@icons/CloseBold"; import type { QuizQuestionFile } from "@model/questionTypes/file"; +import { useQuizStore } from "@/stores/useQuizStore"; type UploadedFileProps = { currentQuestion: QuizQuestionFile; @@ -14,7 +14,7 @@ type UploadedFileProps = { }; export const UploadedFile = ({ currentQuestion, setIsSending }: UploadedFileProps) => { - const { quizId, preview } = useQuizSettings(); + const { quizId, preview } = useQuizStore(); 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 57b5f03..82336e7 100644 --- a/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Images/ImageVariant.tsx @@ -1,6 +1,5 @@ import { CheckboxIcon } from "@/assets/icons/Checkbox"; import type { QuestionVariant, QuestionVariantWithEditedImages } from "@/model/questionTypes/shared"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { Box, Checkbox, FormControlLabel, Input, Radio, TextareaAutosize, Typography, useTheme } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; import RadioCheck from "@ui_kit/RadioCheck"; @@ -8,6 +7,7 @@ import RadioIcon from "@ui_kit/RadioIcon"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import { useMemo, type MouseEvent, useRef, useEffect } from "react"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; +import { useQuizStore } from "@/stores/useQuizStore"; type ImagesProps = { questionId: string; @@ -92,7 +92,7 @@ export const ImageVariant = ({ questionLargeCheck, ownPlaceholder, }: ImagesProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { deleteAnswer, updateAnswer } = useQuizViewStore((state) => state); const theme = useTheme(); const answers = useQuizViewStore((state) => state.answers); diff --git a/lib/components/ViewPublicationPage/questions/Number/index.tsx b/lib/components/ViewPublicationPage/questions/Number/index.tsx index fc403c5..acdadd7 100644 --- a/lib/components/ViewPublicationPage/questions/Number/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Number/index.tsx @@ -1,4 +1,4 @@ -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import type { QuizQuestionNumber } from "@model/questionTypes/number"; import { Box, Typography, useTheme } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; @@ -20,7 +20,7 @@ export const Number = ({ currentQuestion }: NumberProps) => { const [reversedInputValue, setReversedInputValue] = useState("0"); const [reversedMinRange, setReversedMinRange] = useState("0"); const [reversedMaxRange, setReversedMaxRange] = useState("100000000000"); - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 e624e7a..437e4f3 100644 --- a/lib/components/ViewPublicationPage/questions/Select/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Select/index.tsx @@ -1,5 +1,5 @@ import { Select as SelectComponent } from "@/components/ViewPublicationPage/tools/Select"; -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import type { QuizQuestionSelect } from "@model/questionTypes/select"; import { Box, Typography, useTheme } from "@mui/material"; import { useQuizViewStore } from "@stores/quizView"; @@ -10,7 +10,7 @@ type SelectProps = { }; export const Select = ({ currentQuestion }: SelectProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 21d08cc..9f40523 100644 --- a/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/TextNormal.tsx @@ -3,13 +3,13 @@ import { Box, Typography, useTheme } from "@mui/material"; import CustomTextField from "@ui_kit/CustomTextField"; import { Answer, useQuizViewStore } from "@stores/quizView"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import { useMemo, type ChangeEvent } from "react"; import type { QuizQuestionText } from "@model/questionTypes/text"; +import { useQuizStore } from "@/stores/useQuizStore"; interface TextNormalProps { currentQuestion: QuizQuestionText; @@ -18,7 +18,7 @@ interface TextNormalProps { } export const TextNormal = ({ currentQuestion, answer }: TextNormalProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { updateAnswer } = useQuizViewStore((state) => state); const isMobile = useRootContainerSize() < 650; const isTablet = useRootContainerSize() < 850; diff --git a/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx b/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx index c58bf26..5710a2d 100644 --- a/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/TextSpecial.tsx @@ -1,13 +1,13 @@ import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material"; import { Answer, useQuizViewStore } from "@stores/quizView"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import type { ChangeEvent, FC } from "react"; import type { QuizQuestionText } from "@model/questionTypes/text"; +import { useQuizStore } from "@/stores/useQuizStore"; const TextField = MuiTextField as unknown as FC; // temporary fix ts(2590) @@ -45,7 +45,7 @@ interface TextSpecialProps { } export const TextSpecial = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { updateAnswer } = useQuizViewStore((state) => state); const isHorizontal = ORIENTATION[Number(stepNumber) - 1].horizontal; const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Text/TextSpecialHorisontal.tsx b/lib/components/ViewPublicationPage/questions/Text/TextSpecialHorisontal.tsx index 7171a81..2d06c2b 100644 --- a/lib/components/ViewPublicationPage/questions/Text/TextSpecialHorisontal.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/TextSpecialHorisontal.tsx @@ -1,13 +1,13 @@ import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material"; import { Answer, useQuizViewStore } from "@stores/quizView"; -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useRootContainerSize } from "@contexts/RootContainerWidthContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import type { ChangeEvent, FC } from "react"; import type { QuizQuestionText } from "@model/questionTypes/text"; +import { useQuizStore } from "@/stores/useQuizStore"; const TextField = MuiTextField as unknown as FC; // temporary fix ts(2590) @@ -18,7 +18,7 @@ interface TextSpecialProps { } export const TextSpecialHorisontal = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { updateAnswer } = useQuizViewStore((state) => state); const isHorizontal = true; const theme = useTheme(); diff --git a/lib/components/ViewPublicationPage/questions/Text/index.tsx b/lib/components/ViewPublicationPage/questions/Text/index.tsx index f0bc528..cabe54d 100644 --- a/lib/components/ViewPublicationPage/questions/Text/index.tsx +++ b/lib/components/ViewPublicationPage/questions/Text/index.tsx @@ -1,10 +1,10 @@ -import { useQuizSettings } from "@contexts/QuizDataContext"; import { useQuizViewStore } from "@stores/quizView"; import { TextNormal } from "./TextNormal"; import { TextSpecial } from "./TextSpecial"; import { TextSpecialHorisontal } from "./TextSpecialHorisontal"; import type { QuizQuestionText } from "@model/questionTypes/text"; +import { useQuizStore } from "@/stores/useQuizStore"; type TextProps = { currentQuestion: QuizQuestionText; @@ -14,7 +14,7 @@ type TextProps = { const pathOnly = window.location.pathname; export const Text = ({ currentQuestion, stepNumber }: TextProps) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 565490a..3cf2511 100644 --- a/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx +++ b/lib/components/ViewPublicationPage/questions/Variant/VariantItem.tsx @@ -1,5 +1,4 @@ -import { useQuizSettings } from "@contexts/QuizDataContext"; -import { CheckboxIcon } from "@icons/Checkbox"; +import { useQuizStore } from "@/stores/useQuizStore"; import type { QuestionVariant } from "@model/questionTypes/shared"; import { Checkbox, @@ -99,7 +98,7 @@ export const VariantItem = ({ questionLargeCheck: boolean; ownPlaceholder: string; }) => { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); 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 d77fadf..f382c37 100644 --- a/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx +++ b/lib/components/ViewPublicationPage/questions/Varimg/VarimgVariant.tsx @@ -1,5 +1,5 @@ import type { QuestionVariant, QuestionVariantWithEditedImages } from "@/model/questionTypes/shared"; -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import { FormControlLabel, TextareaAutosize, @@ -104,7 +104,7 @@ export const VarimgVariant = ({ }: VarimgVariantProps) => { const theme = useTheme(); - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state); const sendVariant = async (event: MouseEvent) => { diff --git a/lib/components/ViewPublicationPage/tools/NextButton.tsx b/lib/components/ViewPublicationPage/tools/NextButton.tsx index 006c68d..9a2cf7d 100644 --- a/lib/components/ViewPublicationPage/tools/NextButton.tsx +++ b/lib/components/ViewPublicationPage/tools/NextButton.tsx @@ -1,4 +1,4 @@ -import { useQuizSettings } from "@contexts/QuizDataContext"; +import { useQuizStore } from "@/stores/useQuizStore"; import { Button } from "@mui/material"; import { quizThemes } from "@utils/themes/Publication/themePublication"; @@ -8,7 +8,7 @@ interface Props { } export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }: Props) { - const { settings } = useQuizSettings(); + const { settings } = useQuizStore(); return (