Merge branch 'main' into staging
This commit is contained in:
commit
3a8865713a
@ -2,7 +2,7 @@ import useSWR from "swr";
|
|||||||
import { getQuizData } from "./quizRelase";
|
import { getQuizData } from "./quizRelase";
|
||||||
|
|
||||||
export function useQuizData(quizId: string, preview: boolean = false) {
|
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,
|
revalidateOnFocus: false,
|
||||||
revalidateOnReconnect: false,
|
revalidateOnReconnect: false,
|
||||||
shouldRetryOnError: false,
|
shouldRetryOnError: false,
|
||||||
|
@ -72,60 +72,129 @@ export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestPara
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getData(quizId: string): Promise<{
|
// Глобальные переменные для хранения состояния между вызовами
|
||||||
|
let globalStatus: string | null = null;
|
||||||
|
let isFirstRequest = true;
|
||||||
|
|
||||||
|
export async function getData({ quizId, page }: { quizId: string; page?: number }): Promise<{
|
||||||
data: GetQuizDataResponse | null;
|
data: GetQuizDataResponse | null;
|
||||||
isRecentlyCompleted: boolean;
|
isRecentlyCompleted: boolean;
|
||||||
error?: AxiosError;
|
error?: AxiosError;
|
||||||
}> {
|
}> {
|
||||||
try {
|
try {
|
||||||
const { data, headers } = await axios<GetQuizDataResponse>(
|
// Первый запрос: 1 вопрос + конфиг
|
||||||
domain + `/answer/v1.0.0/settings${window.location.search}`,
|
if (isFirstRequest) {
|
||||||
{
|
const { data, headers } = await axios<GetQuizDataResponse>(
|
||||||
method: "POST",
|
domain + `/answer/v1.0.0/settings${window.location.search}`,
|
||||||
headers: {
|
{
|
||||||
"X-Sessionkey": SESSIONS,
|
method: "POST",
|
||||||
"Content-Type": "application/json",
|
headers: {
|
||||||
DeviceType: DeviceType,
|
"X-Sessionkey": SESSIONS,
|
||||||
Device: Device,
|
"Content-Type": "application/json",
|
||||||
OS: OSDevice,
|
DeviceType: DeviceType,
|
||||||
Browser: userAgent,
|
Device: Device,
|
||||||
},
|
OS: OSDevice,
|
||||||
data: {
|
Browser: userAgent,
|
||||||
quiz_id: quizId,
|
},
|
||||||
limit: 100,
|
data: {
|
||||||
page: 0,
|
quiz_id: quizId,
|
||||||
need_config: true,
|
limit: 1,
|
||||||
},
|
page: 0,
|
||||||
}
|
need_config: true,
|
||||||
);
|
},
|
||||||
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
|
}
|
||||||
|
);
|
||||||
|
|
||||||
//Тут ещё проверка на антифрод без парса конфига. Нам не интересно время если не нужно запрещать проходить чаще чем в сутки
|
globalStatus = data.settings.status;
|
||||||
if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) {
|
isFirstRequest = false;
|
||||||
// unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше
|
SESSIONS = headers["x-sessionkey"] || SESSIONS;
|
||||||
if (Date.now() - sessions[quizId] < 86400000) {
|
|
||||||
return { data, isRecentlyCompleted: true };
|
// Проверка антифрода
|
||||||
|
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
|
||||||
|
if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) {
|
||||||
|
if (Date.now() - sessions[quizId] < 86400000) {
|
||||||
|
return { data, isRecentlyCompleted: true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если статус не AI - сразу делаем запрос за всеми вопросами
|
||||||
|
if (globalStatus !== "ai") {
|
||||||
|
const secondResponse = await axios<GetQuizDataResponse>(
|
||||||
|
domain + `/answer/v1.0.0/settings${window.location.search}`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"X-Sessionkey": SESSIONS,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
DeviceType: DeviceType,
|
||||||
|
Device: Device,
|
||||||
|
OS: OSDevice,
|
||||||
|
Browser: userAgent,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
quiz_id: quizId,
|
||||||
|
limit: 100,
|
||||||
|
page: 0,
|
||||||
|
need_config: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
data: { ...data, items: secondResponse.data.items },
|
||||||
|
isRecentlyCompleted: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data, isRecentlyCompleted: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
SESSIONS = headers["x-sessionkey"] ? headers["x-sessionkey"] : SESSIONS;
|
// Последующие запросы
|
||||||
|
const response = await axios<GetQuizDataResponse>(domain + `/answer/v1.0.0/settings${window.location.search}`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"X-Sessionkey": SESSIONS,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
DeviceType: DeviceType,
|
||||||
|
Device: Device,
|
||||||
|
OS: OSDevice,
|
||||||
|
Browser: userAgent,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
quiz_id: quizId,
|
||||||
|
limit: 1,
|
||||||
|
page: page,
|
||||||
|
need_config: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return { data, isRecentlyCompleted: false };
|
return {
|
||||||
} catch (nativeError) {
|
data: response.data,
|
||||||
const error = nativeError as AxiosError;
|
isRecentlyCompleted: false,
|
||||||
|
};
|
||||||
return { data: null, isRecentlyCompleted: false, error: error };
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
data: null,
|
||||||
|
isRecentlyCompleted: false,
|
||||||
|
error: error as AxiosError,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function getQuizData({ quizId, status = "" }: { quizId: string; status?: string }) {
|
||||||
export async function getQuizData(quizId: string) {
|
|
||||||
if (!quizId) throw new Error("No quiz id");
|
if (!quizId) throw new Error("No quiz id");
|
||||||
|
|
||||||
const response = await getData(quizId);
|
const response = await getData({ quizId });
|
||||||
const quizDataResponse = response.data;
|
const quizDataResponse = response.data;
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
throw response.error;
|
const axiosError = response.error as AxiosError;
|
||||||
|
if (axiosError.response?.data) {
|
||||||
|
throw new Error(
|
||||||
|
typeof axiosError.response.data === "string"
|
||||||
|
? axiosError.response.data
|
||||||
|
: JSON.stringify(axiosError.response.data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw axiosError;
|
||||||
}
|
}
|
||||||
if (!quizDataResponse) {
|
if (!quizDataResponse) {
|
||||||
throw new Error("Quiz not found");
|
throw new Error("Quiz not found");
|
||||||
@ -142,6 +211,124 @@ export async function getQuizData(quizId: string) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let page = 1;
|
||||||
|
|
||||||
|
export async function getQuizDataAI(quizId: string) {
|
||||||
|
console.log("[getQuizDataAI] Starting with quizId:", quizId); // Добавлено
|
||||||
|
let maxRetries = 50;
|
||||||
|
|
||||||
|
if (!quizId) {
|
||||||
|
console.error("[getQuizDataAI] Error: No quiz id provided");
|
||||||
|
throw new Error("No quiz id");
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastError: Error | null = null;
|
||||||
|
let responseData: any = null;
|
||||||
|
|
||||||
|
// Первый цикл - обработка result вопросов
|
||||||
|
console.log("[getQuizDataAI] Starting result retries loop"); // Добавлено
|
||||||
|
let resultRetryCount = 0;
|
||||||
|
while (resultRetryCount < maxRetries) {
|
||||||
|
try {
|
||||||
|
console.log(`[getQuizDataAI] Attempt ${resultRetryCount + 1} for result questions, page: ${page}`);
|
||||||
|
const response = await getData({ quizId, page });
|
||||||
|
console.log("[getQuizDataAI] Response from getData:", response);
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
console.error("[getQuizDataAI] Error in response:", response.error);
|
||||||
|
throw response.error;
|
||||||
|
}
|
||||||
|
if (!response.data) {
|
||||||
|
console.error("[getQuizDataAI] Error: Quiz not found");
|
||||||
|
throw new Error("Quiz not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAiResult = response.data.items.some((item) => item.typ === "result");
|
||||||
|
console.log("[getQuizDataAI] Has AI result:", hasAiResult);
|
||||||
|
|
||||||
|
if (hasAiResult) {
|
||||||
|
page++;
|
||||||
|
resultRetryCount++;
|
||||||
|
console.log(`[getQuizDataAI] Found result question, incrementing page to ${page}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = response;
|
||||||
|
console.log("[getQuizDataAI] Found non-result questions, breaking loop");
|
||||||
|
break;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error as Error;
|
||||||
|
resultRetryCount++;
|
||||||
|
console.error(`[getQuizDataAI] Error in attempt ${resultRetryCount}:`, error);
|
||||||
|
|
||||||
|
if (resultRetryCount >= maxRetries) {
|
||||||
|
console.error("[getQuizDataAI] Max retries reached for result questions");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const delay = 1500 * resultRetryCount;
|
||||||
|
console.log(`[getQuizDataAI] Waiting ${delay}ms before next retry`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!responseData) {
|
||||||
|
console.error("[getQuizDataAI] Failed after result retries, throwing error");
|
||||||
|
throw lastError || new Error("Failed to get quiz data after result retries");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Второй цикл - обработка пустого массива
|
||||||
|
console.log("[getQuizDataAI] Starting empty items retry loop"); // Добавлено
|
||||||
|
let isEmpty = !responseData.data?.items.length;
|
||||||
|
let emptyRetryCount = 0;
|
||||||
|
|
||||||
|
while (isEmpty && emptyRetryCount < maxRetries) {
|
||||||
|
try {
|
||||||
|
console.log(`[getQuizDataAI] Empty items retry ${emptyRetryCount + 1}`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
const response = await getData({ quizId, page });
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
console.error("[getQuizDataAI] Error in empty items check:", response.error);
|
||||||
|
throw response.error;
|
||||||
|
}
|
||||||
|
if (!response.data) {
|
||||||
|
console.error("[getQuizDataAI] Error: Quiz not found in empty check");
|
||||||
|
throw new Error("Quiz not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty = !response.data.items.length;
|
||||||
|
console.log("[getQuizDataAI] Is items empty:", isEmpty);
|
||||||
|
|
||||||
|
if (!isEmpty) {
|
||||||
|
responseData = response;
|
||||||
|
console.log("[getQuizDataAI] Found non-empty items, updating responseData");
|
||||||
|
}
|
||||||
|
emptyRetryCount++;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error as Error;
|
||||||
|
emptyRetryCount++;
|
||||||
|
console.error(`[getQuizDataAI] Error in empty check attempt ${emptyRetryCount}:`, error);
|
||||||
|
|
||||||
|
if (emptyRetryCount >= maxRetries) {
|
||||||
|
console.error("[getQuizDataAI] Max empty retries reached");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
console.error("[getQuizDataAI] Items still empty after retries");
|
||||||
|
throw new Error("Items array is empty after maximum retries");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Финальная обработка
|
||||||
|
console.log("[getQuizDataAI] Processing final response data");
|
||||||
|
|
||||||
|
console.log("[getQuizDataAI] Final response before return:", responseData);
|
||||||
|
return responseData.data.items;
|
||||||
|
}
|
||||||
|
|
||||||
type SendAnswerProps = {
|
type SendAnswerProps = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
body: string | string[];
|
body: string | string[];
|
||||||
@ -150,6 +337,8 @@ type SendAnswerProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) {
|
export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) {
|
||||||
|
console.log("qid");
|
||||||
|
console.log(qid);
|
||||||
if (preview) return;
|
if (preview) return;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
|
77
lib/api/useQuizGetNext.ts
Normal file
77
lib/api/useQuizGetNext.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { getQuizDataAI } from "./quizRelase";
|
||||||
|
import { addQuestion, useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
import { AnyTypedQuizQuestion } from "..";
|
||||||
|
|
||||||
|
function qparse(q: { desc: string; id: string; req: boolean; title: string; typ: string }) {
|
||||||
|
return {
|
||||||
|
description: q.desc,
|
||||||
|
id: q.id,
|
||||||
|
required: q.req,
|
||||||
|
title: q.title,
|
||||||
|
type: q.typ,
|
||||||
|
page: 0,
|
||||||
|
content: {
|
||||||
|
answerType: "single",
|
||||||
|
autofill: false,
|
||||||
|
back: "",
|
||||||
|
hint: { text: "", video: "" },
|
||||||
|
id: "",
|
||||||
|
innerName: "",
|
||||||
|
innerNameCheck: false,
|
||||||
|
onlyNumbers: false,
|
||||||
|
originalBack: "",
|
||||||
|
placeholder: "",
|
||||||
|
required: false,
|
||||||
|
rule: {
|
||||||
|
children: [],
|
||||||
|
default: "",
|
||||||
|
main: [],
|
||||||
|
parentId: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useQuizGetNext = () => {
|
||||||
|
const { quizId, settings } = useQuizStore();
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
|
const loadMoreQuestions = async () => {
|
||||||
|
console.log("STATUS loadMoreQuestions");
|
||||||
|
console.log(settings);
|
||||||
|
console.log(settings.status);
|
||||||
|
if (settings.status === "ai") {
|
||||||
|
console.log("STATUS after IF");
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("STATUS after TRY TRY TRY");
|
||||||
|
const data = await getQuizDataAI(quizId);
|
||||||
|
console.log("data");
|
||||||
|
console.log(data);
|
||||||
|
const newQuestion = qparse(data[0]);
|
||||||
|
console.log("newQuestion");
|
||||||
|
console.log(newQuestion);
|
||||||
|
if (newQuestion) {
|
||||||
|
newQuestion.page = currentPage;
|
||||||
|
//@ts-ignore
|
||||||
|
addQuestion(newQuestion as AnyTypedQuizQuestion);
|
||||||
|
setCurrentPage((old) => old++);
|
||||||
|
console.log("newQuestion + page");
|
||||||
|
console.log(newQuestion);
|
||||||
|
return newQuestion;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(err as Error);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { loadMoreQuestions, isLoading, error, currentPage };
|
||||||
|
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,7 +3,6 @@ import { QuizViewContext, createQuizViewStore } from "@/stores/quizView";
|
|||||||
import LoadingSkeleton from "@/ui_kit/LoadingSkeleton";
|
import LoadingSkeleton from "@/ui_kit/LoadingSkeleton";
|
||||||
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
||||||
import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals";
|
import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals";
|
||||||
import { QuizSettingsContext } from "@contexts/QuizDataContext";
|
|
||||||
import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext";
|
import { RootContainerWidthContext } from "@contexts/RootContainerWidthContext";
|
||||||
import type { QuizSettings } from "@model/settingsData";
|
import type { QuizSettings } from "@model/settingsData";
|
||||||
import { Box, CssBaseline, ScopedCssBaseline, ThemeProvider } from "@mui/material";
|
import { Box, CssBaseline, ScopedCssBaseline, ThemeProvider } from "@mui/material";
|
||||||
@ -14,13 +13,14 @@ import { handleComponentError } from "@utils/handleComponentError";
|
|||||||
import lightTheme from "@utils/themes/light";
|
import lightTheme from "@utils/themes/light";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { SnackbarProvider } from "notistack";
|
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 { ErrorBoundary } from "react-error-boundary";
|
||||||
import { ApologyPage } from "./ViewPublicationPage/ApologyPage";
|
import { ApologyPage } from "./ViewPublicationPage/ApologyPage";
|
||||||
import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage";
|
import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage";
|
||||||
import { HelmetProvider } from "react-helmet-async";
|
import { HelmetProvider } from "react-helmet-async";
|
||||||
|
|
||||||
import "moment/dist/locale/ru";
|
import "moment/dist/locale/ru";
|
||||||
|
import { useQuizStore, setQuizData, addquizid } from "@/stores/useQuizStore";
|
||||||
moment.locale("ru");
|
moment.locale("ru");
|
||||||
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
|
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
|
||||||
|
|
||||||
@ -32,7 +32,16 @@ type Props = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
disableGlobalCss?: boolean;
|
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({
|
function QuizAnswererInner({
|
||||||
quizSettings,
|
quizSettings,
|
||||||
quizId,
|
quizId,
|
||||||
@ -47,6 +56,19 @@ function QuizAnswererInner({
|
|||||||
const { data, error, isLoading } = useQuizData(quizId, preview);
|
const { data, error, isLoading } = useQuizData(quizId, preview);
|
||||||
const vkMetrics = useVkMetricsGoals(quizSettings?.settings.cfg.vkMetricsNumber);
|
const vkMetrics = useVkMetricsGoals(quizSettings?.settings.cfg.vkMetricsNumber);
|
||||||
const yandexMetrics = useYandexMetricsGoals(quizSettings?.settings.cfg.yandexMetricsNumber);
|
const yandexMetrics = useYandexMetricsGoals(quizSettings?.settings.cfg.yandexMetricsNumber);
|
||||||
|
const r = useQuizStore();
|
||||||
|
const { settings, questions } = useQuizStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
addquizid(quizId);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(settings);
|
||||||
|
console.log(questions);
|
||||||
|
console.log("r");
|
||||||
|
console.log(r);
|
||||||
|
}, [questions, settings]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -55,6 +77,18 @@ function QuizAnswererInner({
|
|||||||
}, 4000);
|
}, 4000);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// 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(() => {
|
useLayoutEffect(() => {
|
||||||
if (rootContainerRef.current) setRootContainerWidth(rootContainerRef.current.clientWidth);
|
if (rootContainerRef.current) setRootContainerWidth(rootContainerRef.current.clientWidth);
|
||||||
@ -73,15 +107,15 @@ function QuizAnswererInner({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
console.log("settings");
|
||||||
|
console.log(settings);
|
||||||
if (isLoading) return <LoadingSkeleton />;
|
if (isLoading) return <LoadingSkeleton />;
|
||||||
if (error) return <ApologyPage error={error} />;
|
if (error) return <ApologyPage error={error} />;
|
||||||
// if (!data) return <LoadingSkeleton />;
|
|
||||||
quizSettings ??= data;
|
|
||||||
if (!quizSettings) return <ApologyPage error={new Error("quiz data is null")} />;
|
|
||||||
|
|
||||||
if (quizSettings.questions.length === 1 && quizSettings?.settings.cfg.noStartPage)
|
if (Object.keys(settings).length == 0) return <ApologyPage error={new Error("quiz data is null")} />;
|
||||||
return <ApologyPage error={new Error("quiz is empty")} />;
|
if (questions.length === 0) return <ApologyPage error={new Error("No questions found")} />;
|
||||||
// if (quizSettings.questions.length === 1) return <ApologyPage error={new Error("no questions found")} />;
|
|
||||||
|
if (questions.length === 1 && settings.cfg.noStartPage) return <ApologyPage error={new Error("quiz is empty")} />;
|
||||||
if (!quizId) return <ApologyPage error={new Error("no quiz id")} />;
|
if (!quizId) return <ApologyPage error={new Error("no quiz id")} />;
|
||||||
|
|
||||||
const quizContainer = (
|
const quizContainer = (
|
||||||
@ -106,21 +140,19 @@ function QuizAnswererInner({
|
|||||||
return (
|
return (
|
||||||
<QuizViewContext.Provider value={quizViewStore}>
|
<QuizViewContext.Provider value={quizViewStore}>
|
||||||
<RootContainerWidthContext.Provider value={rootContainerWidth}>
|
<RootContainerWidthContext.Provider value={rootContainerWidth}>
|
||||||
<QuizSettingsContext.Provider value={{ ...quizSettings, quizId, preview, changeFaviconAndTitle }}>
|
{disableGlobalCss ? (
|
||||||
{disableGlobalCss ? (
|
<ScopedCssBaseline
|
||||||
<ScopedCssBaseline
|
sx={{
|
||||||
sx={{
|
height: "100%",
|
||||||
height: "100%",
|
width: "100%",
|
||||||
width: "100%",
|
backgroundColor: "transparent",
|
||||||
backgroundColor: "transparent",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{quizContainer}
|
||||||
{quizContainer}
|
</ScopedCssBaseline>
|
||||||
</ScopedCssBaseline>
|
) : (
|
||||||
) : (
|
<CssBaseline>{quizContainer}</CssBaseline>
|
||||||
<CssBaseline>{quizContainer}</CssBaseline>
|
)}
|
||||||
)}
|
|
||||||
</QuizSettingsContext.Provider>
|
|
||||||
</RootContainerWidthContext.Provider>
|
</RootContainerWidthContext.Provider>
|
||||||
</QuizViewContext.Provider>
|
</QuizViewContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,11 @@ type Props = Partial<FallbackProps>;
|
|||||||
|
|
||||||
export const ApologyPage = ({ error }: Props) => {
|
export const ApologyPage = ({ error }: Props) => {
|
||||||
let message = error.message || error.response?.data;
|
let message = error.message || error.response?.data;
|
||||||
|
console.log("message");
|
||||||
|
console.log(message.toLowerCase());
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
console.log("t");
|
||||||
|
console.log(t(message.toLowerCase()));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
@ -8,7 +8,6 @@ import { Inputs } from "@/components/ViewPublicationPage/ContactForm/Inputs/Inpu
|
|||||||
import { ContactTextBlock } from "./ContactTextBlock";
|
import { ContactTextBlock } from "./ContactTextBlock";
|
||||||
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
|
|
||||||
import { sendFC, SendFCParams } from "@api/quizRelase";
|
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 { QuizQuestionResult } from "@model/questionTypes/result";
|
||||||
import type { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
import type { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||||
import { isProduction } from "@/utils/defineDomain";
|
import { isProduction } from "@/utils/defineDomain";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -36,7 +36,7 @@ const isDisableEmail = window.location.pathname.includes("/377c7570-1bee-4320-ac
|
|||||||
|
|
||||||
export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||||
const theme = useTheme();
|
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 [ready, setReady] = useState(false);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Box, InputAdornment, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
import { Box, InputAdornment, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext.ts";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext.ts";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext.ts";
|
|
||||||
import { useIMask, IMask } from "react-imask";
|
import { useIMask, IMask } from "react-imask";
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication.ts";
|
import { quizThemes } from "@utils/themes/Publication/themePublication.ts";
|
||||||
import { ChangeEvent, FC, HTMLInputTypeAttribute, useEffect, useState } from "react";
|
import { ChangeEvent, FC, HTMLInputTypeAttribute, useEffect, useState } from "react";
|
||||||
import { CountrySelector } from "@/components/ViewPublicationPage/ContactForm/CustomInput/CountrySelector/CountrySelector.tsx";
|
import { CountrySelector } from "@/components/ViewPublicationPage/ContactForm/CustomInput/CountrySelector/CountrySelector.tsx";
|
||||||
import { phoneMasksByCountry } from "@utils/phoneMasksByCountry.tsx";
|
import { phoneMasksByCountry } from "@utils/phoneMasksByCountry.tsx";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
type InputProps = {
|
type InputProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -37,7 +37,7 @@ function phoneChange(e: ChangeEvent<HTMLInputElement>, mask: string) {
|
|||||||
export const CustomInput = ({ title, desc, Icon, onChange, onChangePhone, isPhone, type, value }: InputProps) => {
|
export const CustomInput = ({ title, desc, Icon, onChange, onChangePhone, isPhone, type, value }: InputProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useRootContainerSize() < 600;
|
const isMobile = useRootContainerSize() < 600;
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const [mask, setMask] = useState(phoneMasksByCountry["RU"][1]);
|
const [mask, setMask] = useState(phoneMasksByCountry["RU"][1]);
|
||||||
// const { ref } = useIMask({ mask });
|
// const { ref } = useIMask({ mask });
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { useQuizSettings } from "@contexts/QuizDataContext.ts";
|
|
||||||
import NameIcon from "@icons/ContactFormIcon/NameIcon.tsx";
|
import NameIcon from "@icons/ContactFormIcon/NameIcon.tsx";
|
||||||
import EmailIcon from "@icons/ContactFormIcon/EmailIcon.tsx";
|
import EmailIcon from "@icons/ContactFormIcon/EmailIcon.tsx";
|
||||||
import TextIcon from "@icons/ContactFormIcon/TextIcon.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 { CustomInput } from "@/components/ViewPublicationPage/ContactForm/CustomInput/CustomInput.tsx";
|
||||||
import PhoneIcon from "@icons/ContactFormIcon/PhoneIcon.tsx";
|
import PhoneIcon from "@icons/ContactFormIcon/PhoneIcon.tsx";
|
||||||
import PhoneInput from "react-phone-number-input";
|
import PhoneInput from "react-phone-number-input";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type InputsProps = {
|
type InputsProps = {
|
||||||
@ -25,6 +25,9 @@ type InputsProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const iscrutch = "/cc006b40-ccbd-4600-a1d3-f902f85aa0a0";
|
||||||
|
const pathOnly = window.location.pathname;
|
||||||
|
|
||||||
export const Inputs = ({
|
export const Inputs = ({
|
||||||
name,
|
name,
|
||||||
setName,
|
setName,
|
||||||
@ -38,7 +41,7 @@ export const Inputs = ({
|
|||||||
setAdress,
|
setAdress,
|
||||||
crutch,
|
crutch,
|
||||||
}: InputsProps) => {
|
}: InputsProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const FC = settings.cfg.formContact.fields;
|
const FC = settings.cfg.formContact.fields;
|
||||||
|
|
||||||
@ -47,7 +50,11 @@ export const Inputs = ({
|
|||||||
<CustomInput
|
<CustomInput
|
||||||
onChange={({ target }) => setName(target.value)}
|
onChange={({ target }) => setName(target.value)}
|
||||||
id={name}
|
id={name}
|
||||||
title={FC["name"].innerText || `${t("Enter")} ${t("Name").toLowerCase()}`}
|
title={
|
||||||
|
pathOnly === iscrutch
|
||||||
|
? "Введите имя и фамилию"
|
||||||
|
: FC["name"].innerText || `${t("Enter")} ${t("Name").toLowerCase()}`
|
||||||
|
}
|
||||||
desc={FC["name"].text || t("Name")}
|
desc={FC["name"].text || t("Name")}
|
||||||
Icon={NameIcon}
|
Icon={NameIcon}
|
||||||
/>
|
/>
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
|
|
||||||
import Stepper from "@ui_kit/Stepper";
|
import Stepper from "@ui_kit/Stepper";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
type FooterProps = {
|
type FooterProps = {
|
||||||
stepNumber: number | null;
|
stepNumber: number | null;
|
||||||
@ -14,7 +13,7 @@ type FooterProps = {
|
|||||||
|
|
||||||
export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
|
export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { questions, settings } = useQuizSettings();
|
const { questions, settings } = useQuizStore();
|
||||||
const questionsAmount = questions.filter(({ type }) => type !== "result").length;
|
const questionsAmount = questions.filter(({ type }) => type !== "result").length;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
|
|||||||
gap: "10px",
|
gap: "10px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{stepNumber !== null && (
|
{stepNumber !== null && settings.status !== "ai" && (
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
<Typography sx={{ color: theme.palette.text.primary }}>
|
<Typography sx={{ color: theme.palette.text.primary }}>
|
||||||
{t("Step")} {stepNumber} {t("of")} {questionsAmount}
|
{t("Step")} {stepNumber} {t("of")} {questionsAmount}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { IncorrectAnswer } from "@/assets/icons/IncorrectAnswer";
|
import { IncorrectAnswer } from "@/assets/icons/IncorrectAnswer";
|
||||||
import { CorrectAnswer } from "@/assets/icons/CorrectAnswer";
|
import { CorrectAnswer } from "@/assets/icons/CorrectAnswer";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
import { useQuizSettings } from "@/contexts/QuizDataContext";
|
|
||||||
import { useQuizViewStore } from "@/stores/quizView";
|
import { useQuizViewStore } from "@/stores/quizView";
|
||||||
import { AnyTypedQuizQuestion, QuizQuestionVariant } from "@/index";
|
import { AnyTypedQuizQuestion, QuizQuestionVariant } from "@/index";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
export const PointSystemResultList = () => {
|
export const PointSystemResultList = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { questions } = useQuizSettings();
|
const { questions } = useQuizStore();
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import { Varimg } from "./questions/Varimg";
|
|||||||
|
|
||||||
import type { RealTypedQuizQuestion } from "../../model/questionTypes/shared";
|
import type { RealTypedQuizQuestion } from "../../model/questionTypes/shared";
|
||||||
|
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { NameplateLogoFQ } from "@icons/NameplateLogoFQ";
|
import { NameplateLogoFQ } from "@icons/NameplateLogoFQ";
|
||||||
import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
|
import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
|
||||||
import { notReachable } from "@utils/notReachable";
|
import { notReachable } from "@utils/notReachable";
|
||||||
@ -24,6 +23,7 @@ import { quizThemes } from "@utils/themes/Publication/themePublication";
|
|||||||
import { DESIGN_LIST } from "@/utils/designList";
|
import { DESIGN_LIST } from "@/utils/designList";
|
||||||
import { type ReactNode } from "react";
|
import { type ReactNode } from "react";
|
||||||
import { isProduction } from "@/utils/defineDomain";
|
import { isProduction } from "@/utils/defineDomain";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentQuestion: RealTypedQuizQuestion;
|
currentQuestion: RealTypedQuizQuestion;
|
||||||
@ -41,7 +41,7 @@ export const Question = ({
|
|||||||
questionSelect,
|
questionSelect,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { settings, show_badge, quizId } = useQuizSettings();
|
const { settings, show_badge, quizId } = useQuizStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useQuizSettings } from "@/contexts/QuizDataContext";
|
|
||||||
import { AnyTypedQuizQuestion } from "@/model/questionTypes/shared";
|
import { AnyTypedQuizQuestion } from "@/model/questionTypes/shared";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { Box, FormControl, MenuItem, Select as MuiSelect, useTheme } from "@mui/material";
|
import { Box, FormControl, MenuItem, Select as MuiSelect, useTheme } from "@mui/material";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function QuestionSelect({ selectedQuestion, setQuestion }: Props) {
|
export default function QuestionSelect({ selectedQuestion, setQuestion }: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { questions, preview } = useQuizSettings();
|
const { questions, preview } = useQuizStore();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!preview) return null;
|
if (!preview) return null;
|
||||||
@ -38,6 +38,8 @@ export default function QuestionSelect({ selectedQuestion, setQuestion }: Props)
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={selectedQuestion.id}
|
value={selectedQuestion.id}
|
||||||
placeholder={t("Question title")}
|
placeholder={t("Question title")}
|
||||||
|
//(*.*)
|
||||||
|
// placeholder={t("Question title")}
|
||||||
onChange={({ target }) => {
|
onChange={({ target }) => {
|
||||||
setQuestion(target.value);
|
setQuestion(target.value);
|
||||||
}}
|
}}
|
||||||
|
@ -4,7 +4,6 @@ import { Box, Button, Link, Typography, useTheme } from "@mui/material";
|
|||||||
import { useQuizViewStore } from "@/stores/quizView";
|
import { useQuizViewStore } from "@/stores/quizView";
|
||||||
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
|
|
||||||
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
||||||
import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals";
|
import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals";
|
||||||
@ -19,6 +18,7 @@ import { PointSystemResultList } from "./PointSystemResultList";
|
|||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { sendFC, sendResult } from "@/api/quizRelase";
|
import { sendFC, sendResult } from "@/api/quizRelase";
|
||||||
import { isProduction } from "@/utils/defineDomain";
|
import { isProduction } from "@/utils/defineDomain";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type ResultFormProps = {
|
type ResultFormProps = {
|
||||||
@ -29,7 +29,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useRootContainerSize() < 650;
|
const isMobile = useRootContainerSize() < 650;
|
||||||
const isTablet = useRootContainerSize() < 1000;
|
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 setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep);
|
||||||
//Список засчитанных баллов для балловых квизов
|
//Список засчитанных баллов для балловых квизов
|
||||||
const pointsSum = useQuizViewStore((state) => state.pointsSum);
|
const pointsSum = useQuizViewStore((state) => state.pointsSum);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
import { notReachable } from "@utils/notReachable";
|
import { notReachable } from "@utils/notReachable";
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
@ -22,7 +22,7 @@ type LayoutProps = Omit<StartPageDesktopProps, "startpageType">;
|
|||||||
const StandartLayout = ({ alignType, quizHeaderBlock, quizMainBlock, backgroundBlock }: LayoutProps) => {
|
const StandartLayout = ({ alignType, quizHeaderBlock, quizMainBlock, backgroundBlock }: LayoutProps) => {
|
||||||
const size = useRootContainerSize();
|
const size = useRootContainerSize();
|
||||||
const isTablet = size >= 700 && size < 1100;
|
const isTablet = size >= 700 && size < 1100;
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -170,7 +170,7 @@ const ExpandedLayout = ({ alignType, quizHeaderBlock, quizMainBlock, backgroundB
|
|||||||
|
|
||||||
const CenteredLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: LayoutProps) => {
|
const CenteredLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: LayoutProps) => {
|
||||||
const isTablet = useRootContainerSize() < 1100;
|
const isTablet = useRootContainerSize() < 1100;
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
import { notReachable } from "@utils/notReachable";
|
import { notReachable } from "@utils/notReachable";
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
@ -18,7 +18,7 @@ type StartPageMobileProps = {
|
|||||||
type MobileLayoutProps = Omit<StartPageMobileProps, "startpageType">;
|
type MobileLayoutProps = Omit<StartPageMobileProps, "startpageType">;
|
||||||
|
|
||||||
const StandartMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => {
|
const StandartMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -163,7 +163,7 @@ const ExpandedMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock
|
|||||||
);
|
);
|
||||||
|
|
||||||
const CenteredMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => {
|
const CenteredMobileLayout = ({ quizHeaderBlock, quizMainBlock, backgroundBlock }: MobileLayoutProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -2,7 +2,7 @@ import { Box, Button, ButtonBase, Link, Paper, Typography, useTheme } from "@mui
|
|||||||
|
|
||||||
import { QuizPreviewLayoutByType } from "./QuizPreviewLayoutByType";
|
import { QuizPreviewLayoutByType } from "./QuizPreviewLayoutByType";
|
||||||
|
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
|
|
||||||
import { useUADevice } from "@utils/hooks/useUADevice";
|
import { useUADevice } from "@utils/hooks/useUADevice";
|
||||||
@ -20,7 +20,7 @@ import { isProduction } from "@/utils/defineDomain";
|
|||||||
|
|
||||||
export const StartPageViewPublication = () => {
|
export const StartPageViewPublication = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { settings, show_badge, quizId, questions } = useQuizSettings();
|
const { settings, show_badge, quizId, questions } = useQuizStore();
|
||||||
const { isMobileDevice } = useUADevice();
|
const { isMobileDevice } = useUADevice();
|
||||||
const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep);
|
const setCurrentQuizStep = useQuizViewStore((state) => state.setCurrentQuizStep);
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import { extractImageLinksFromQuestion } from "@/utils/extractImageLinks";
|
|||||||
import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics";
|
import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics";
|
||||||
import { useYandexMetrics } from "@/utils/hooks/metrics/useYandexMetrics";
|
import { useYandexMetrics } from "@/utils/hooks/metrics/useYandexMetrics";
|
||||||
import { sendQuestionAnswer } from "@/utils/sendQuestionAnswer";
|
import { sendQuestionAnswer } from "@/utils/sendQuestionAnswer";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { ThemeProvider, Typography } from "@mui/material";
|
import { ThemeProvider, Typography } from "@mui/material";
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
import { useQuestionFlowControl } from "@utils/hooks/useQuestionFlowControl";
|
import { useQuestionFlowControl } from "@utils/hooks/useQuestionFlowControl";
|
||||||
@ -19,9 +18,10 @@ import { StartPageViewPublication } from "./StartPageViewPublication";
|
|||||||
import NextButton from "./tools/NextButton";
|
import NextButton from "./tools/NextButton";
|
||||||
import PrevButton from "./tools/PrevButton";
|
import PrevButton from "./tools/PrevButton";
|
||||||
import unscreen from "@/ui_kit/unscreen";
|
import unscreen from "@/ui_kit/unscreen";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
export default function ViewPublicationPage() {
|
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 answers = useQuizViewStore((state) => state.answers);
|
||||||
const ownVariants = useQuizViewStore((state) => state.ownVariants);
|
const ownVariants = useQuizViewStore((state) => state.ownVariants);
|
||||||
let currentQuizStep = useQuizViewStore((state) => state.currentQuizStep);
|
let currentQuizStep = useQuizViewStore((state) => state.currentQuizStep);
|
||||||
@ -106,16 +106,15 @@ export default function ViewPublicationPage() {
|
|||||||
}
|
}
|
||||||
nextButton={
|
nextButton={
|
||||||
<NextButton
|
<NextButton
|
||||||
isNextButtonEnabled={isNextButtonEnabled}
|
isNextButtonEnabled={settings.status === "ai" || isNextButtonEnabled}
|
||||||
moveToNextQuestion={() => {
|
moveToNextQuestion={async () => {
|
||||||
|
if (!preview) {
|
||||||
|
await sendQuestionAnswer(quizId, currentQuestion, currentAnswer, ownVariants)?.catch((e) => {
|
||||||
|
enqueueSnackbar("Ошибка при отправке ответа");
|
||||||
|
console.error("Error sending answer", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
moveToNextQuestion();
|
moveToNextQuestion();
|
||||||
|
|
||||||
if (preview) return;
|
|
||||||
|
|
||||||
sendQuestionAnswer(quizId, currentQuestion, currentAnswer, ownVariants)?.catch((e) => {
|
|
||||||
enqueueSnackbar("Ошибка при отправке ответа");
|
|
||||||
console.error("Error sending answer", e);
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useQuizViewStore } from "@/stores/quizView";
|
import { useQuizViewStore } from "@/stores/quizView";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import CalendarIcon from "@icons/CalendarIcon";
|
import CalendarIcon from "@icons/CalendarIcon";
|
||||||
import type { QuizQuestionDate } from "@model/questionTypes/date";
|
import type { QuizQuestionDate } from "@model/questionTypes/date";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
@ -13,7 +13,7 @@ type DateProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default ({ currentQuestion }: DateProps) => {
|
export default ({ currentQuestion }: DateProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { useQuizSettings } from "@/contexts/QuizDataContext";
|
|
||||||
import { useQuizViewStore } from "@/stores/quizView";
|
import { useQuizViewStore } from "@/stores/quizView";
|
||||||
import type { QuizQuestionDate } from "@model/questionTypes/date";
|
import type { QuizQuestionDate } from "@model/questionTypes/date";
|
||||||
import { DateCalendar } from "@mui/x-date-pickers";
|
import { DateCalendar } from "@mui/x-date-pickers";
|
||||||
@ -7,6 +6,7 @@ import type { Moment } from "moment";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Box, Paper, TextField, useTheme } from "@mui/material";
|
import { Box, Paper, TextField, useTheme } from "@mui/material";
|
||||||
import { useRootContainerSize } from "@/contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@/contexts/RootContainerWidthContext";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type DateProps = {
|
type DateProps = {
|
||||||
@ -17,7 +17,7 @@ export default ({ currentQuestion }: DateProps) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const today = moment();
|
const today = moment();
|
||||||
const isMobile = useRootContainerSize() < 690;
|
const isMobile = useRootContainerSize() < 690;
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { QuestionVariant } from "@/model/questionTypes/shared";
|
import type { QuestionVariant } from "@/model/questionTypes/shared";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
@ -105,7 +105,7 @@ export const EmojiVariant = ({
|
|||||||
questionLargeCheck,
|
questionLargeCheck,
|
||||||
ownPlaceholder,
|
ownPlaceholder,
|
||||||
}: EmojiVariantProps) => {
|
}: EmojiVariantProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -3,7 +3,6 @@ import { Box, ButtonBase, Skeleton, Typography, useTheme } from "@mui/material";
|
|||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
import { sendAnswer, sendFile } from "@api/quizRelase";
|
import { sendAnswer, sendFile } from "@api/quizRelase";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
|
|
||||||
@ -18,6 +17,7 @@ import UploadIcon from "@icons/UploadIcon";
|
|||||||
|
|
||||||
import type { QuizQuestionFile } from "@model/questionTypes/file";
|
import type { QuizQuestionFile } from "@model/questionTypes/file";
|
||||||
import type { ModalWarningType } from "./index";
|
import type { ModalWarningType } from "./index";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type UploadFileProps = {
|
type UploadFileProps = {
|
||||||
@ -28,7 +28,7 @@ type UploadFileProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, setIsSending }: UploadFileProps) => {
|
export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, setIsSending }: UploadFileProps) => {
|
||||||
const { quizId, preview } = useQuizSettings();
|
const { quizId, preview } = useQuizStore();
|
||||||
const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState<boolean>(false);
|
const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState<boolean>(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Box, IconButton, Typography, useTheme } from "@mui/material";
|
import { Box, IconButton, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { sendAnswer } from "@api/quizRelase";
|
import { sendAnswer } from "@api/quizRelase";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
|
|
||||||
import CloseBold from "@icons/CloseBold";
|
import CloseBold from "@icons/CloseBold";
|
||||||
|
|
||||||
import type { QuizQuestionFile } from "@model/questionTypes/file";
|
import type { QuizQuestionFile } from "@model/questionTypes/file";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type UploadedFileProps = {
|
type UploadedFileProps = {
|
||||||
@ -15,7 +15,7 @@ type UploadedFileProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const UploadedFile = ({ currentQuestion, setIsSending }: UploadedFileProps) => {
|
export const UploadedFile = ({ currentQuestion, setIsSending }: UploadedFileProps) => {
|
||||||
const { quizId, preview } = useQuizSettings();
|
const { quizId, preview } = useQuizStore();
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { CheckboxIcon } from "@/assets/icons/Checkbox";
|
import { CheckboxIcon } from "@/assets/icons/Checkbox";
|
||||||
import type { QuestionVariant, QuestionVariantWithEditedImages } from "@/model/questionTypes/shared";
|
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 { Box, Checkbox, FormControlLabel, Input, Radio, TextareaAutosize, Typography, useTheme } from "@mui/material";
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
import RadioCheck from "@ui_kit/RadioCheck";
|
import RadioCheck from "@ui_kit/RadioCheck";
|
||||||
@ -8,6 +7,7 @@ import RadioIcon from "@ui_kit/RadioIcon";
|
|||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
import { useMemo, type MouseEvent, useRef, useEffect } from "react";
|
import { useMemo, type MouseEvent, useRef, useEffect } from "react";
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type ImagesProps = {
|
type ImagesProps = {
|
||||||
@ -93,7 +93,7 @@ export const ImageVariant = ({
|
|||||||
questionLargeCheck,
|
questionLargeCheck,
|
||||||
ownPlaceholder,
|
ownPlaceholder,
|
||||||
}: ImagesProps) => {
|
}: ImagesProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { deleteAnswer, updateAnswer } = useQuizViewStore((state) => state);
|
const { deleteAnswer, updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import type { QuizQuestionNumber } from "@model/questionTypes/number";
|
import type { QuizQuestionNumber } from "@model/questionTypes/number";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
@ -20,7 +20,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
|||||||
const [reversedInputValue, setReversedInputValue] = useState<string>("0");
|
const [reversedInputValue, setReversedInputValue] = useState<string>("0");
|
||||||
const [reversedMinRange, setReversedMinRange] = useState<string>("0");
|
const [reversedMinRange, setReversedMinRange] = useState<string>("0");
|
||||||
const [reversedMaxRange, setReversedMaxRange] = useState<string>("100000000000");
|
const [reversedMaxRange, setReversedMaxRange] = useState<string>("100000000000");
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Select as SelectComponent } from "@/components/ViewPublicationPage/tools/Select";
|
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 type { QuizQuestionSelect } from "@model/questionTypes/select";
|
||||||
import { Box, Typography, useTheme } from "@mui/material";
|
import { Box, Typography, useTheme } from "@mui/material";
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
@ -10,7 +10,7 @@ type SelectProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Select = ({ currentQuestion }: SelectProps) => {
|
export const Select = ({ currentQuestion }: SelectProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -3,13 +3,13 @@ import { Box, Typography, useTheme } from "@mui/material";
|
|||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
|
|
||||||
import { Answer, useQuizViewStore } from "@stores/quizView";
|
import { Answer, useQuizViewStore } from "@stores/quizView";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
|
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
|
|
||||||
import { useMemo, type ChangeEvent } from "react";
|
import { useMemo, type ChangeEvent } from "react";
|
||||||
import type { QuizQuestionText } from "@model/questionTypes/text";
|
import type { QuizQuestionText } from "@model/questionTypes/text";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
interface TextNormalProps {
|
interface TextNormalProps {
|
||||||
currentQuestion: QuizQuestionText;
|
currentQuestion: QuizQuestionText;
|
||||||
@ -18,7 +18,7 @@ interface TextNormalProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TextNormal = ({ currentQuestion, answer }: TextNormalProps) => {
|
export const TextNormal = ({ currentQuestion, answer }: TextNormalProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const isMobile = useRootContainerSize() < 650;
|
const isMobile = useRootContainerSize() < 650;
|
||||||
const isTablet = useRootContainerSize() < 850;
|
const isTablet = useRootContainerSize() < 850;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { Answer, useQuizViewStore } from "@stores/quizView";
|
import { Answer, useQuizViewStore } from "@stores/quizView";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
|
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
|
|
||||||
import type { ChangeEvent, FC } from "react";
|
import type { ChangeEvent, FC } from "react";
|
||||||
import type { QuizQuestionText } from "@model/questionTypes/text";
|
import type { QuizQuestionText } from "@model/questionTypes/text";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ interface TextSpecialProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TextSpecial = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => {
|
export const TextSpecial = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const isHorizontal = ORIENTATION[Number(stepNumber) - 1].horizontal;
|
const isHorizontal = ORIENTATION[Number(stepNumber) - 1].horizontal;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -129,7 +129,7 @@ export const TextSpecial = ({ currentQuestion, answer, stepNumber }: TextSpecial
|
|||||||
<img
|
<img
|
||||||
key={currentQuestion.id}
|
key={currentQuestion.id}
|
||||||
src={currentQuestion.content.back}
|
src={currentQuestion.content.back}
|
||||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
style={{ width: "100%", height: "100%", objectFit: "contain" }}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
import { Box, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { Answer, useQuizViewStore } from "@stores/quizView";
|
import { Answer, useQuizViewStore } from "@stores/quizView";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "@contexts/RootContainerWidthContext";
|
||||||
|
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
|
|
||||||
import type { ChangeEvent, FC } from "react";
|
import type { ChangeEvent, FC } from "react";
|
||||||
import type { QuizQuestionText } from "@model/questionTypes/text";
|
import type { QuizQuestionText } from "@model/questionTypes/text";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ interface TextSpecialProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TextSpecialHorisontal = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => {
|
export const TextSpecialHorisontal = ({ currentQuestion, answer, stepNumber }: TextSpecialProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { updateAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer } = useQuizViewStore((state) => state);
|
||||||
const isHorizontal = true;
|
const isHorizontal = true;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -61,7 +61,7 @@ export const TextSpecialHorisontal = ({ currentQuestion, answer, stepNumber }: T
|
|||||||
<img
|
<img
|
||||||
key={currentQuestion.id}
|
key={currentQuestion.id}
|
||||||
src={currentQuestion.content.back}
|
src={currentQuestion.content.back}
|
||||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
style={{ width: "100%", height: "100%", objectFit: "contain" }}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -102,7 +102,7 @@ export const TextSpecialHorisontal = ({ currentQuestion, answer, stepNumber }: T
|
|||||||
<img
|
<img
|
||||||
key={currentQuestion.id}
|
key={currentQuestion.id}
|
||||||
src={currentQuestion.content.back}
|
src={currentQuestion.content.back}
|
||||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
style={{ width: "100%", height: "100%", objectFit: "contain" }}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
import { TextNormal } from "./TextNormal";
|
import { TextNormal } from "./TextNormal";
|
||||||
import { TextSpecial } from "./TextSpecial";
|
import { TextSpecial } from "./TextSpecial";
|
||||||
import { TextSpecialHorisontal } from "./TextSpecialHorisontal";
|
import { TextSpecialHorisontal } from "./TextSpecialHorisontal";
|
||||||
|
|
||||||
import type { QuizQuestionText } from "@model/questionTypes/text";
|
import type { QuizQuestionText } from "@model/questionTypes/text";
|
||||||
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
type TextProps = {
|
type TextProps = {
|
||||||
currentQuestion: QuizQuestionText;
|
currentQuestion: QuizQuestionText;
|
||||||
@ -14,11 +14,11 @@ type TextProps = {
|
|||||||
const pathOnly = window.location.pathname;
|
const pathOnly = window.location.pathname;
|
||||||
|
|
||||||
export const Text = ({ currentQuestion, stepNumber }: TextProps) => {
|
export const Text = ({ currentQuestion, stepNumber }: TextProps) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
|
||||||
|
|
||||||
if (pathOnly === "/92ed5e3e-8e6a-491e-87d0-d3197682d0e3")
|
if (pathOnly === "/92ed5e3e-8e6a-491e-87d0-d3197682d0e3" || pathOnly === "/cc006b40-ccbd-4600-a1d3-f902f85aa0a0")
|
||||||
return (
|
return (
|
||||||
<TextSpecialHorisontal
|
<TextSpecialHorisontal
|
||||||
currentQuestion={currentQuestion}
|
currentQuestion={currentQuestion}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { CheckboxIcon } from "@icons/Checkbox";
|
|
||||||
import type { QuestionVariant } from "@model/questionTypes/shared";
|
import type { QuestionVariant } from "@model/questionTypes/shared";
|
||||||
import {
|
import {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
@ -101,7 +100,7 @@ export const VariantItem = ({
|
|||||||
questionLargeCheck: boolean;
|
questionLargeCheck: boolean;
|
||||||
ownPlaceholder: string;
|
ownPlaceholder: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { QuestionVariant, QuestionVariantWithEditedImages } from "@/model/questionTypes/shared";
|
import type { QuestionVariant, QuestionVariantWithEditedImages } from "@/model/questionTypes/shared";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import {
|
import {
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
TextareaAutosize,
|
TextareaAutosize,
|
||||||
@ -104,8 +104,9 @@ export const VarimgVariant = ({
|
|||||||
answer,
|
answer,
|
||||||
}: VarimgVariantProps) => {
|
}: VarimgVariantProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const { settings } = useQuizStore();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { settings } = useQuizSettings();
|
|
||||||
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
const { updateAnswer, deleteAnswer } = useQuizViewStore((state) => state);
|
||||||
|
|
||||||
const sendVariant = async (event: MouseEvent<HTMLLabelElement>) => {
|
const sendVariant = async (event: MouseEvent<HTMLLabelElement>) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -9,7 +9,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }: Props) {
|
export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }: Props) {
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -25,7 +25,7 @@ export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }:
|
|||||||
}}
|
}}
|
||||||
onClick={moveToNextQuestion}
|
onClick={moveToNextQuestion}
|
||||||
>
|
>
|
||||||
{t("Next")} →
|
далее →{/* {t("Next")} → (*.*) */}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Button, useTheme } from "@mui/material";
|
import { Button, useTheme } from "@mui/material";
|
||||||
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
|
import { useRootContainerSize } from "../../../contexts/RootContainerWidthContext";
|
||||||
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
import { quizThemes } from "@utils/themes/Publication/themePublication";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -11,7 +11,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function PrevButton({ isPreviousButtonEnabled, moveToPrevQuestion }: Props) {
|
export default function PrevButton({ isPreviousButtonEnabled, moveToPrevQuestion }: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { settings } = useQuizSettings();
|
const { settings } = useQuizStore();
|
||||||
const isMobileMini = useRootContainerSize() < 382;
|
const isMobileMini = useRootContainerSize() < 382;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
@ -37,7 +37,8 @@ export default function PrevButton({ isPreviousButtonEnabled, moveToPrevQuestion
|
|||||||
}}
|
}}
|
||||||
onClick={moveToPrevQuestion}
|
onClick={moveToPrevQuestion}
|
||||||
>
|
>
|
||||||
{isMobileMini ? "←" : `← ${t("Prev")}`}
|
{isMobileMini ? "←" : `← назад`}
|
||||||
|
{/* {isMobileMini ? "←" : `← ${t("Prev")}`} (*.*) */}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import { QuizSettings } from "@model/settingsData";
|
|
||||||
import { createContext, useContext } from "react";
|
|
||||||
|
|
||||||
export const QuizSettingsContext = createContext<
|
|
||||||
| (QuizSettings & {
|
|
||||||
quizId: string;
|
|
||||||
preview: boolean;
|
|
||||||
changeFaviconAndTitle: boolean;
|
|
||||||
})
|
|
||||||
| null
|
|
||||||
>(null);
|
|
||||||
|
|
||||||
export const useQuizSettings = () => {
|
|
||||||
const quizSettings = useContext(QuizSettingsContext);
|
|
||||||
if (quizSettings === null) throw new Error("QuizSettings context is null");
|
|
||||||
|
|
||||||
return quizSettings;
|
|
||||||
};
|
|
@ -12,6 +12,7 @@ export interface GetQuizDataResponse {
|
|||||||
due: number;
|
due: number;
|
||||||
delay: number;
|
delay: number;
|
||||||
pausable: boolean;
|
pausable: boolean;
|
||||||
|
status: "start" | "stop" | "ai";
|
||||||
};
|
};
|
||||||
items: {
|
items: {
|
||||||
id: number;
|
id: number;
|
||||||
@ -49,6 +50,7 @@ export function parseQuizData(quizDataResponse: GetQuizDataResponse): Omit<QuizS
|
|||||||
due: quizDataResponse.settings.due,
|
due: quizDataResponse.settings.due,
|
||||||
delay: quizDataResponse.settings.delay,
|
delay: quizDataResponse.settings.delay,
|
||||||
pausable: quizDataResponse.settings.pausable,
|
pausable: quizDataResponse.settings.pausable,
|
||||||
|
status: quizDataResponse.settings.status,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { cnt: quizDataResponse.cnt, settings, questions: items, show_badge: quizDataResponse.show_badge };
|
return { cnt: quizDataResponse.cnt, settings, questions: items, show_badge: quizDataResponse.show_badge };
|
||||||
|
@ -51,6 +51,7 @@ export type QuizSettingsConfig = {
|
|||||||
delay: number;
|
delay: number;
|
||||||
pausable: boolean;
|
pausable: boolean;
|
||||||
cfg: QuizConfig;
|
cfg: QuizConfig;
|
||||||
|
status: "start" | "stop" | "ai";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QuizSettings = {
|
export type QuizSettings = {
|
||||||
|
39
lib/stores/useQuizStore.ts
Normal file
39
lib/stores/useQuizStore.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { produce } from "immer";
|
||||||
|
import { QuizSettings, QuizSettingsConfig } from "@model/settingsData";
|
||||||
|
import { AnyTypedQuizQuestion } from "..";
|
||||||
|
|
||||||
|
export type QuizStore = QuizSettings & {
|
||||||
|
quizId: string;
|
||||||
|
preview: boolean;
|
||||||
|
changeFaviconAndTitle: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useQuizStore = create<QuizStore>(() => ({
|
||||||
|
settings: {} as QuizSettingsConfig,
|
||||||
|
questions: [],
|
||||||
|
quizId: "",
|
||||||
|
preview: false,
|
||||||
|
changeFaviconAndTitle: false,
|
||||||
|
cnt: 0,
|
||||||
|
recentlyCompleted: false,
|
||||||
|
show_badge: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const setQuizData = (data: QuizSettings) => {
|
||||||
|
console.log("zusstand");
|
||||||
|
console.log(data);
|
||||||
|
useQuizStore.setState((state: QuizStore) => ({ ...state, ...data }));
|
||||||
|
};
|
||||||
|
export const addQuestion = (newQuestion: AnyTypedQuizQuestion) =>
|
||||||
|
useQuizStore.setState(
|
||||||
|
produce((state: QuizStore) => {
|
||||||
|
state.questions.push(newQuestion);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
export const addquizid = (id: string) =>
|
||||||
|
useQuizStore.setState(
|
||||||
|
produce((state: QuizStore) => {
|
||||||
|
state.quizId = id;
|
||||||
|
})
|
||||||
|
);
|
@ -1,18 +1,31 @@
|
|||||||
import { useCallback, useDebugValue, useMemo, useState } from "react";
|
import { useCallback, useDebugValue, useEffect, useMemo, useState } from "react";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
import { isResultQuestionEmpty } from "@/components/ViewPublicationPage/tools/checkEmptyData";
|
import { isResultQuestionEmpty } from "@/components/ViewPublicationPage/tools/checkEmptyData";
|
||||||
import { useQuizSettings } from "@contexts/QuizDataContext";
|
import { useQuizStore } from "@/stores/useQuizStore";
|
||||||
|
|
||||||
import { useQuizViewStore } from "@stores/quizView";
|
import { useQuizViewStore } from "@stores/quizView";
|
||||||
|
|
||||||
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
import { useVkMetricsGoals } from "@/utils/hooks/metrics/useVkMetricsGoals";
|
||||||
import { useYandexMetricsGoals } from "@/utils/hooks/metrics/useYandexMetricsGoals";
|
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() {
|
export function useQuestionFlowControl() {
|
||||||
//Получаем инфо о квизе и список вопросов.
|
//Получаем инфо о квизе и список вопросов.
|
||||||
const { settings, questions } = useQuizSettings();
|
const { loadMoreQuestions } = useQuizGetNext();
|
||||||
|
const { settings, questions, quizId, cnt } = useQuizStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("useQuestionFlowControl useEffect");
|
||||||
|
console.log(questions);
|
||||||
|
}, [questions]);
|
||||||
|
console.log(questions);
|
||||||
|
|
||||||
//Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page.
|
//Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page.
|
||||||
//За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page
|
//За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page
|
||||||
const sortedQuestions = useMemo(() => {
|
const sortedQuestions = useMemo(() => {
|
||||||
@ -20,6 +33,7 @@ export function useQuestionFlowControl() {
|
|||||||
}, [questions]);
|
}, [questions]);
|
||||||
//React сам будет менять визуал - главное говорить из какого вопроса ему брать инфо. Изменение этой переменной меняет визуал.
|
//React сам будет менять визуал - главное говорить из какого вопроса ему брать инфо. Изменение этой переменной меняет визуал.
|
||||||
const [currentQuestionId, setCurrentQuestionId] = useState<string | null>(getFirstQuestionId);
|
const [currentQuestionId, setCurrentQuestionId] = useState<string | null>(getFirstQuestionId);
|
||||||
|
const [headAI, setHeadAI] = useState(0);
|
||||||
//Список ответов на вопрос. Мы записываем ответы локально, параллельно отправляя на бек информацию о ответах
|
//Список ответов на вопрос. Мы записываем ответы локально, параллельно отправляя на бек информацию о ответах
|
||||||
const answers = useQuizViewStore((state) => state.answers);
|
const answers = useQuizViewStore((state) => state.answers);
|
||||||
//Список засчитанных баллов для балловых квизов
|
//Список засчитанных баллов для балловых квизов
|
||||||
@ -33,7 +47,10 @@ export function useQuestionFlowControl() {
|
|||||||
//Изменение стейта (переменной currentQuestionId) ведёт к пересчёту что же за объект сейчас используется. Мы каждый раз просто ищем в списке
|
//Изменение стейта (переменной currentQuestionId) ведёт к пересчёту что же за объект сейчас используется. Мы каждый раз просто ищем в списке
|
||||||
const currentQuestion = sortedQuestions.find((question) => question.id === currentQuestionId) ?? sortedQuestions[0];
|
const currentQuestion = sortedQuestions.find((question) => question.id === currentQuestionId) ?? sortedQuestions[0];
|
||||||
|
|
||||||
// console.log(currentQuestion)
|
console.log("currentQuestion");
|
||||||
|
console.log(currentQuestion);
|
||||||
|
console.log("filted");
|
||||||
|
console.log(sortedQuestions.find((question) => question.id === currentQuestionId));
|
||||||
|
|
||||||
//Индекс текущего вопроса только если квиз линейный
|
//Индекс текущего вопроса только если квиз линейный
|
||||||
const linearQuestionIndex = //: number | null
|
const linearQuestionIndex = //: number | null
|
||||||
@ -113,7 +130,7 @@ export function useQuestionFlowControl() {
|
|||||||
return nextQuestionIdPointsLogic();
|
return nextQuestionIdPointsLogic();
|
||||||
}
|
}
|
||||||
return nextQuestionIdMainLogic();
|
return nextQuestionIdMainLogic();
|
||||||
}, [nextQuestionIdMainLogic, nextQuestionIdPointsLogic, settings.cfg.score]);
|
}, [nextQuestionIdMainLogic, nextQuestionIdPointsLogic, settings.cfg.score, questions]);
|
||||||
|
|
||||||
//Поиск предыдущго вопроса либо по индексу либо по id родителя
|
//Поиск предыдущго вопроса либо по индексу либо по id родителя
|
||||||
const prevQuestion =
|
const prevQuestion =
|
||||||
@ -196,21 +213,51 @@ export function useQuestionFlowControl() {
|
|||||||
const moveToPrevQuestion = useCallback(() => {
|
const moveToPrevQuestion = useCallback(() => {
|
||||||
if (!prevQuestion) throw new Error("Previous question not found");
|
if (!prevQuestion) throw new Error("Previous question not found");
|
||||||
|
|
||||||
|
if (settings.status === "ai" && headAI > 0) setHeadAI((old) => old--);
|
||||||
setCurrentQuestionId(prevQuestion.id);
|
setCurrentQuestionId(prevQuestion.id);
|
||||||
}, [prevQuestion]);
|
}, [prevQuestion]);
|
||||||
|
|
||||||
//рычаг управления из визуала в эту функцию
|
//рычаг управления из визуала в эту функцию
|
||||||
const moveToNextQuestion = useCallback(() => {
|
const moveToNextQuestion = useCallback(async () => {
|
||||||
if (!nextQuestion) throw new Error("Next question not found");
|
// Если есть следующий вопрос в уже загруженных - используем его
|
||||||
|
|
||||||
// Засчитываем переход с вопроса дальше
|
if (nextQuestion) {
|
||||||
vkMetrics.questionPassed(currentQuestion.id);
|
vkMetrics.questionPassed(currentQuestion.id);
|
||||||
yandexMetrics.questionPassed(currentQuestion.id);
|
yandexMetrics.questionPassed(currentQuestion.id);
|
||||||
|
|
||||||
if (nextQuestion.type === "result") return showResult();
|
if (nextQuestion.type === "result") return showResult();
|
||||||
|
setCurrentQuestionId(nextQuestion.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentQuestionId(nextQuestion.id);
|
// Если следующего нет - загружаем новый
|
||||||
}, [currentQuestion.id, nextQuestion, showResult, vkMetrics, yandexMetrics]);
|
try {
|
||||||
|
const newQuestion = await loadMoreQuestions();
|
||||||
|
console.log("Ффункция некст вопрос получила его с бека: ");
|
||||||
|
console.log(newQuestion);
|
||||||
|
if (newQuestion) {
|
||||||
|
vkMetrics.questionPassed(currentQuestion.id);
|
||||||
|
yandexMetrics.questionPassed(currentQuestion.id);
|
||||||
|
console.log("МЫ ПАЛУЧИЛИ НОВЫЙ ВОПРОС");
|
||||||
|
console.log(newQuestion);
|
||||||
|
console.log("typeof newQuestion.id");
|
||||||
|
console.log(typeof newQuestion.id);
|
||||||
|
setCurrentQuestionId(newQuestion.id);
|
||||||
|
setHeadAI((old) => old++);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
enqueueSnackbar("Ошибка загрузки следующего вопроса");
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
currentQuestion.id,
|
||||||
|
nextQuestion,
|
||||||
|
showResult,
|
||||||
|
vkMetrics,
|
||||||
|
yandexMetrics,
|
||||||
|
linearQuestionIndex,
|
||||||
|
loadMoreQuestions,
|
||||||
|
questions,
|
||||||
|
]);
|
||||||
|
|
||||||
//рычаг управления из визуала в эту функцию
|
//рычаг управления из визуала в эту функцию
|
||||||
const setQuestion = useCallback(
|
const setQuestion = useCallback(
|
||||||
@ -234,6 +281,10 @@ export function useQuestionFlowControl() {
|
|||||||
return hasAnswer;
|
return hasAnswer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(linearQuestionIndex);
|
||||||
|
console.log(questions.length);
|
||||||
|
console.log(cnt);
|
||||||
|
if (linearQuestionIndex !== null && questions.length < cnt) return true;
|
||||||
return Boolean(nextQuestion);
|
return Boolean(nextQuestion);
|
||||||
}, [answers, currentQuestion, nextQuestion]);
|
}, [answers, currentQuestion, nextQuestion]);
|
||||||
|
|
||||||
@ -246,7 +297,8 @@ export function useQuestionFlowControl() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
currentQuestion,
|
currentQuestion,
|
||||||
currentQuestionStepNumber: linearQuestionIndex === null ? null : linearQuestionIndex + 1,
|
currentQuestionStepNumber:
|
||||||
|
settings.status === "ai" ? null : linearQuestionIndex === null ? null : linearQuestionIndex + 1,
|
||||||
nextQuestion,
|
nextQuestion,
|
||||||
isNextButtonEnabled,
|
isNextButtonEnabled,
|
||||||
isPreviousButtonEnabled,
|
isPreviousButtonEnabled,
|
||||||
|
@ -4,7 +4,7 @@ import { OwnVariant, QuestionAnswer, createQuizViewStore } from "@/stores/quizVi
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { notReachable } from "./notReachable";
|
import { notReachable } from "./notReachable";
|
||||||
|
|
||||||
export function sendQuestionAnswer(
|
export async function sendQuestionAnswer(
|
||||||
quizId: string,
|
quizId: string,
|
||||||
question: RealTypedQuizQuestion,
|
question: RealTypedQuizQuestion,
|
||||||
questionAnswer: QuestionAnswer | undefined,
|
questionAnswer: QuestionAnswer | undefined,
|
||||||
|
@ -52,5 +52,6 @@
|
|||||||
"familiarized": "acknowledged",
|
"familiarized": "acknowledged",
|
||||||
"and": "and",
|
"and": "and",
|
||||||
"Get results": "Get results",
|
"Get results": "Get results",
|
||||||
"Data sent successfully": "Data sent successfully"
|
"Data sent successfully": "Data sent successfully",
|
||||||
|
"Step": "Step"
|
||||||
}
|
}
|
||||||
|
@ -52,5 +52,6 @@
|
|||||||
"familiarized": "ознакомлен",
|
"familiarized": "ознакомлен",
|
||||||
"and": "и",
|
"and": "и",
|
||||||
"Get results": "Получить результаты",
|
"Get results": "Получить результаты",
|
||||||
"Data sent successfully": "Данные успешно отправлены"
|
"Data sent successfully": "Данные успешно отправлены",
|
||||||
|
"Step": "Шаг"
|
||||||
}
|
}
|
||||||
|
@ -52,5 +52,6 @@
|
|||||||
"familiarized": "tanishdim",
|
"familiarized": "tanishdim",
|
||||||
"and": "va",
|
"and": "va",
|
||||||
"Get results": "Natijalarni olish",
|
"Get results": "Natijalarni olish",
|
||||||
"Data sent successfully": "Ma'lumotlar muvaffaqiyatli yuborildi"
|
"Data sent successfully": "Ma'lumotlar muvaffaqiyatli yuborildi",
|
||||||
|
"Step": "Qadam"
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,18 @@ i18n
|
|||||||
lookupFromPathIndex: 0,
|
lookupFromPathIndex: 0,
|
||||||
caches: [], // Не использовать localStorage
|
caches: [], // Не использовать localStorage
|
||||||
},
|
},
|
||||||
|
parseMissingKeyHandler: (key) => {
|
||||||
|
console.warn("Missing translation:", key);
|
||||||
|
return key; // Вернёт ключ вместо ошибки
|
||||||
|
},
|
||||||
|
missingKeyHandler: (lngs, ns, key) => {
|
||||||
|
console.error("🚨 Missing i18n key:", {
|
||||||
|
key,
|
||||||
|
languages: lngs,
|
||||||
|
namespace: ns,
|
||||||
|
stack: new Error().stack, // Выведет стек вызовов
|
||||||
|
});
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//console.log("i18n инициализирован! Текущий язык:", i18n.language);
|
//console.log("i18n инициализирован! Текущий язык:", i18n.language);
|
||||||
|
Loading…
Reference in New Issue
Block a user