hide ai
All checks were successful
Deploy / CreateImage (push) Successful in 3m6s
Deploy / DeployService (push) Successful in 21s

This commit is contained in:
Nastya 2025-04-22 22:29:34 +03:00
parent 4190ae767e
commit 1f2880f719
8 changed files with 103 additions and 24 deletions

@ -71,7 +71,7 @@ export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestPara
method: "POST", method: "POST",
}); });
}; };
let page = 0;
export async function getData(quizId: string): Promise<{ export async function getData(quizId: string): Promise<{
data: GetQuizDataResponse | null; data: GetQuizDataResponse | null;
isRecentlyCompleted: boolean; isRecentlyCompleted: boolean;
@ -92,16 +92,18 @@ export async function getData(quizId: string): Promise<{
}, },
data: { data: {
quiz_id: quizId, quiz_id: quizId,
limit: 100, limit: 1,
page: 0, page,
need_config: true, need_config: page === 0,
}, },
} }
); );
console.log(data);
if (data.items.length) page++;
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}"); 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 время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше // unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше
if (Date.now() - sessions[quizId] < 86400000) { if (Date.now() - sessions[quizId] < 86400000) {
return { data, isRecentlyCompleted: true }; 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<QuizSettings> {
let maxRetries = 50;
if (!quizId) throw new Error("No quiz id"); if (!quizId) throw new Error("No quiz id");
const response = await getData(quizId); let lastError: Error | null = null;
const quizDataResponse = response.data; let responseData: any = null;
if (response.error) { // Первый цикл - обработка result вопросов с увеличением page
throw response.error; let resultRetryCount = 0;
} while (resultRetryCount < maxRetries) {
if (!quizDataResponse) { try {
throw new Error("Quiz not found"); 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( const res = JSON.parse(
JSON.stringify({ data: quizSettings }) JSON.stringify({ data: quizSettings })
.replaceAll(/\\" \\"/g, '""') .replaceAll(/\\" \\"/g, '""')
.replaceAll(/" "/g, '""') .replaceAll(/" "/g, '""')
).data as QuizSettings; ).data as QuizSettings;
res.recentlyCompleted = response.isRecentlyCompleted;
res.recentlyCompleted = responseData.isRecentlyCompleted;
return res; return res;
} }

@ -77,12 +77,12 @@ function QuizAnswererInner({
if (error) return <ApologyPage error={error} />; if (error) return <ApologyPage error={error} />;
// if (!data) return <LoadingSkeleton />; // if (!data) return <LoadingSkeleton />;
quizSettings ??= data; quizSettings ??= data;
if (!quizSettings) return <ApologyPage error={new Error("Quiz data is null")} />; if (!quizSettings) return <ApologyPage error={new Error("quiz data is null")} />;
if (quizSettings.questions.length === 1 && quizSettings?.settings.cfg.noStartPage) if (quizSettings.questions.length === 1 && quizSettings?.settings.cfg.noStartPage)
return <ApologyPage error={new Error("Quiz is empty")} />; return <ApologyPage error={new Error("quiz is empty")} />;
// if (quizSettings.questions.length === 1) return <ApologyPage error={new Error("No questions found")} />; // if (quizSettings.questions.length === 1) return <ApologyPage error={new Error("no questions found")} />;
if (!quizId) return <ApologyPage error={new Error("No quiz id")} />; if (!quizId) return <ApologyPage error={new Error("no quiz id")} />;
const quizContainer = ( const quizContainer = (
<Box <Box

@ -38,7 +38,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 }}>
Вопрос {stepNumber} из {questionsAmount} Вопрос {stepNumber} из {questionsAmount}

@ -106,7 +106,7 @@ export default function ViewPublicationPage() {
} }
nextButton={ nextButton={
<NextButton <NextButton
isNextButtonEnabled={isNextButtonEnabled} isNextButtonEnabled={settings.status === "ai" || isNextButtonEnabled}
moveToNextQuestion={() => { moveToNextQuestion={() => {
moveToNextQuestion(); moveToNextQuestion();

@ -1,5 +1,6 @@
import { QuizSettings } from "@model/settingsData"; import { QuizSettings } from "@model/settingsData";
import { createContext, useContext } from "react"; import { createContext, useContext } from "react";
import { AnyTypedQuizQuestion } from "..";
export const QuizSettingsContext = createContext< export const QuizSettingsContext = createContext<
| (QuizSettings & { | (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 = {

@ -9,10 +9,20 @@ 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";
let isgetting = false;
export function useQuestionFlowControl() { export function useQuestionFlowControl() {
//Получаем инфо о квизе и список вопросов. //Получаем инфо о квизе и список вопросов.
const { settings, questions } = useQuizSettings(); const { settings, questions: initialQuestions, quizId } = useQuizSettings();
const [questions, setQuestions] = useState(initialQuestions);
const addQuestion = (question: AnyTypedQuizQuestion) => {
setQuestions((prev) => [...prev, question]);
};
//Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page. //Когда квиз линейный, не ветвящийся, мы идём по вопросам по их порядковому номеру. Это их page.
//За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page //За корректность page отвечает конструктор квизов. Интересный факт, если в конструкторе удалить из середины вопрос, то случится куча запросов изменения вопросов с изменением этого page
const sortedQuestions = useMemo(() => { const sortedQuestions = useMemo(() => {
@ -200,7 +210,12 @@ export function useQuestionFlowControl() {
}, [prevQuestion]); }, [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"); if (!nextQuestion) throw new Error("Next question not found");
// Засчитываем переход с вопроса дальше // Засчитываем переход с вопроса дальше
@ -246,7 +261,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,