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"; import { statusOfQuiz } from "@/utils/hooks/useQuestionFlowControl"; 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"; }; const urlParams = new URLSearchParams(window.location.search); const paudParam = urlParams.get("_paud"); 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; /* если запросить 0 вопросов - придёт items: null если не запрашивать конфиг - поле конфига вообще не придёт */ interface GetDataProps { quizId: string; limit: number; page: number; needConfig: boolean; } export async function getData({ quizId, limit, page, needConfig }: GetDataProps): Promise<{ data: GetQuizDataResponse | null; isRecentlyCompleted: boolean; error?: AxiosError; }> { const body = { quiz_id: quizId, limit, page, need_config: needConfig, } as any; if (paudParam) body.auditory = Number(paudParam); try { 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: body, } ); const sessions = JSON.parse(localStorage.getItem("sessions") || "{}"); //Тут ещё проверка на антифрод без парса конфига. Нам не интересно время если не нужно запрещать проходить чаще чем в сутки if ( needConfig && data?.settings !== undefined && typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true') ) { // unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше if (Date.now() - sessions[quizId] < 86400000) { return { data, isRecentlyCompleted: true }; } } SESSIONS = headers["x-sessionkey"] ? headers["x-sessionkey"] : SESSIONS; return { data, isRecentlyCompleted: false }; } catch (nativeError) { const error = nativeError as AxiosError; return { data: null, isRecentlyCompleted: false, error: error }; } } export async function getAndParceData(props: GetDataProps) { if (!props.quizId) throw new Error("No quiz id"); const response = await getData(props); const quizDataResponse = response.data; if (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) { 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; } type SendAnswerProps = { questionId: string; body: string | string[]; qid: string; preview?: boolean; }; export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) { if (preview) return; const formData = new FormData(); const answers = [ { question_id: questionId, //Для АИ квизов нельзя слать пустые строки content: statusOfQuiz != "ai" ? body : body.length ? 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", }); }