import { GetQuizDataResponse, parseQuizData } from "@model/api/getQuizData"; import axios from "axios"; import MobileDetect from "mobile-detect"; import device from "current-device"; import type { AxiosError } from "axios"; import { replaceSpacesToEmptyLines } from "../components/ViewPublicationPage/tools/replaceSpacesToEmptyLines"; import { QuizSettings } from "@model/settingsData"; import * as Bowser from "bowser"; import { domain } from "../utils/defineDomain"; let SESSIONS = ""; const md = new MobileDetect(window.navigator.userAgent); const userAgent = navigator.userAgent; //операционная система let OSDevice: string | undefined; if (userAgent.toLowerCase().includes("linux")) { OSDevice = "Linux"; } if (userAgent.toLowerCase().includes("windows")) { OSDevice = "Windows"; } if (/iPad|iPhone|iPod/.test(userAgent)) { OSDevice = "IOS"; } if (userAgent.toLowerCase().includes("macintosh")) { OSDevice = "Mac OS"; } if (OSDevice === undefined) { OSDevice = userAgent; } //браузер let browserUser: string; if (Bowser.name === "Chrome") { browserUser = "Chrome"; } else if (Bowser.name === "Firefox") { browserUser = "Firefox"; } else if (Bowser.name === "Safari") { browserUser = "Safari"; } else if (Bowser.name === "Yandex Browser") { browserUser = "Yandex Browser"; } else { browserUser = userAgent; } const DeviceType = device.type; let Device = md.mobile(); if (Device === null) { Device = userAgent; } type PublicationMakeRequestParams = { url: string; body: FormData; method: "POST"; }; export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestParams) => { return axios(url, { data: body, headers: { "X-Sessionkey": SESSIONS, "Content-Type": "multipart/form-data", DeviceType: DeviceType, Device: Device, OS: OSDevice, Browser: browserUser, }, method: "POST", }); }; // Глобальные переменные для хранения состояния между вызовами let globalStatus: string | null = null; let isFirstRequest = true; export async function getData({ quizId, page }: { quizId: string; page?: number }): Promise<{ data: GetQuizDataResponse | null; isRecentlyCompleted: boolean; error?: AxiosError; }> { try { // Первый запрос: 1 вопрос + конфиг if (isFirstRequest) { const { data, headers } = await axios( 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: 0, need_config: true, }, } ); globalStatus = data.settings.status; isFirstRequest = false; SESSIONS = headers["x-sessionkey"] || SESSIONS; // Проверка антифрода 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( 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 }; } // Последующие запросы const response = await axios(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: response.data, isRecentlyCompleted: false, }; } catch (error) { return { data: null, isRecentlyCompleted: false, error: error as AxiosError, }; } } export async function getQuizData({ quizId, status = "" }: { quizId: string; status?: string }) { if (!quizId) throw new Error("No quiz id"); const response = await getData({ quizId }); const quizDataResponse = response.data; if (response.error) { throw response.error; } if (!quizDataResponse) { throw new Error("Quiz not found"); } const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse)); const res = JSON.parse( JSON.stringify({ data: quizSettings }) .replaceAll(/\\" \\"/g, '""') .replaceAll(/" "/g, '""') ).data as QuizSettings; res.recentlyCompleted = response.isRecentlyCompleted; return res; } let page = 1; export async function getQuizDataAI(quizId: string) { 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 = { questionId: string; body: string | string[]; qid: string; preview?: boolean; }; export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) { console.log("qid"); console.log(qid); if (preview) return; const formData = new FormData(); const answers = [ { question_id: questionId, content: body, //тут массив с ответом }, ]; formData.append("answers", JSON.stringify(answers)); formData.append("qid", qid); return publicationMakeRequest({ url: domain + `/answer/v1.0.0/answer`, body: formData, method: "POST", }); } //body ={file, filename} type SendFileParams = { questionId: string; body: { name: string; file: File; preview: boolean; }; qid: string; }; type Answer = { question_id: string; content: string; }; export function sendFile({ questionId, body, qid }: SendFileParams) { if (body.preview) return; const formData = new FormData(); const file = new File([body.file], body.file.name.replace(/\s/g, "_")); const nameImage = body.name.replace(/\s/g, "_"); const answers: Answer[] = [ { question_id: questionId, content: "file:" + nameImage, }, ]; formData.append("answers", JSON.stringify(answers)); formData.append(nameImage, file); formData.append("qid", qid); return publicationMakeRequest({ url: domain + `/answer/v1.0.0/answer`, body: formData, method: "POST", }); } //форма контактов export type SendFCParams = { questionId: string; body: { name?: string; email?: string; phone?: string; address?: string; customs?: Record; }; qid: string; preview: boolean; }; export function sendFC({ questionId, body, qid, preview }: SendFCParams) { if (preview) return; const formData = new FormData(); // const keysBody = Object.keys(body) // const content:any = {} // fields.forEach((key) => { // if (keysBody.includes(key)) content[key] = body.key // }) const answers = [ { question_id: questionId, content: JSON.stringify(body), result: true, qid, }, ]; formData.append("answers", JSON.stringify(answers)); formData.append("qid", qid); return publicationMakeRequest({ url: domain + `/answer/v1.0.0/answer`, body: formData, method: "POST", }); } //форма контактов export type SendResultParams = { questionId: string; pointsSum: number; qid: string; preview: boolean; }; export function sendResult({ questionId, pointsSum, qid, preview }: SendResultParams) { if (preview) return; const formData = new FormData(); // const keysBody = Object.keys(body) // const content:any = {} // fields.forEach((key) => { // if (keysBody.includes(key)) content[key] = body.key // }) const answers = [ { question_id: questionId, content: pointsSum.toString(), result: false, qid, }, ]; formData.append("answers", JSON.stringify(answers)); formData.append("qid", qid); return publicationMakeRequest({ url: domain + `/answer/v1.0.0/answer`, body: formData, method: "POST", }); }