From f6d4dfe826d2f0feffaa6b8bd5a5bb6ccc49988f Mon Sep 17 00:00:00 2001
From: nflnkr <105123049+nflnkr@users.noreply.github.com>
Date: Fri, 2 Feb 2024 17:35:02 +0300
Subject: [PATCH] refator datafetching minor fixes
---
package.json | 1 +
src/App.tsx | 17 +-
...{ContextProviders.tsx => QuizAnswerer.tsx} | 23 +-
src/WidgetApp.tsx | 17 +-
src/model/api/getQuizData.ts | 6 +-
src/model/settingsData.ts | 3 +-
src/pages/ViewPublicationPage/ContactForm.tsx | 22 +-
src/pages/ViewPublicationPage/Footer.tsx | 39 +-
src/pages/ViewPublicationPage/Question.tsx | 13 +-
src/pages/ViewPublicationPage/ResultForm.tsx | 15 +-
.../StartPageViewPublication.tsx | 12 +-
.../ViewPublicationPage.tsx | 53 +-
.../ViewPublicationPage/questions/Date.tsx | 172 +++--
.../ViewPublicationPage/questions/Emoji.tsx | 262 ++++----
.../ViewPublicationPage/questions/File.tsx | 595 +++++++++---------
.../ViewPublicationPage/questions/Images.tsx | 260 ++++----
.../ViewPublicationPage/questions/Number.tsx | 6 +-
.../ViewPublicationPage/questions/Rating.tsx | 222 ++++---
.../ViewPublicationPage/questions/Select.tsx | 114 ++--
.../ViewPublicationPage/questions/Text.tsx | 94 ++-
.../ViewPublicationPage/questions/Variant.tsx | 18 +-
.../ViewPublicationPage/questions/Varimg.tsx | 7 +-
.../ViewPublicationPage/questions/gag.png | Bin 6050 -> 0 bytes
src/pages/ViewPublicationPage/tools/File.tsx | 96 +--
src/stores/quizData/actions.ts | 12 -
src/stores/quizData/hooks.ts | 0
src/stores/quizData/store.ts | 29 -
src/utils/handleComponentError.ts | 43 ++
src/utils/hooks/useGetSettings.ts | 56 --
src/utils/hooks/useQuizData.ts | 34 +
yarn.lock | 7 +
31 files changed, 1082 insertions(+), 1166 deletions(-)
rename src/{ContextProviders.tsx => QuizAnswerer.tsx} (58%)
delete mode 100644 src/pages/ViewPublicationPage/questions/gag.png
delete mode 100644 src/stores/quizData/actions.ts
delete mode 100644 src/stores/quizData/hooks.ts
delete mode 100644 src/stores/quizData/store.ts
create mode 100644 src/utils/handleComponentError.ts
delete mode 100644 src/utils/hooks/useGetSettings.ts
create mode 100644 src/utils/hooks/useQuizData.ts
diff --git a/package.json b/package.json
index 8d65845..5c14905 100755
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"notistack": "^3.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-error-boundary": "^4.0.12",
"react-router-dom": "^6.21.3",
"swr": "^2.2.4",
"typescript": "^5.2.2",
diff --git a/src/App.tsx b/src/App.tsx
index 398a58d..5e2e7ad 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,8 +1,7 @@
import { Box } from "@mui/material";
-import ContextProviders from "./ContextProviders";
-import { QuizIdContext } from "./contexts/QuizIdContext";
import { useParams } from "react-router-dom";
-import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
+import QuizAnswerer from "./QuizAnswerer";
+import { QuizIdContext } from "./contexts/QuizIdContext";
const defaultQuizId = "ef836ff8-35b1-4031-9acf-af5766bac2b2";
@@ -12,13 +11,11 @@ export default function App() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/ContextProviders.tsx b/src/QuizAnswerer.tsx
similarity index 58%
rename from src/ContextProviders.tsx
rename to src/QuizAnswerer.tsx
index ea17a51..3d3e935 100644
--- a/src/ContextProviders.tsx
+++ b/src/QuizAnswerer.tsx
@@ -2,20 +2,22 @@ import { CssBaseline, ThemeProvider } from "@mui/material";
import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
import { ruRU } from '@mui/x-date-pickers/locales';
+import LoadingSkeleton from "@ui_kit/LoadingSkeleton";
+import { handleComponentError } from "@utils/handleComponentError";
import moment from "moment";
import { SnackbarProvider } from 'notistack';
+import { Suspense } from "react";
+import { ErrorBoundary } from "react-error-boundary";
import { SWRConfig } from "swr";
+import { ApologyPage } from "./pages/ViewPublicationPage/ApologyPage";
+import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
import lightTheme from "./utils/themes/light";
moment.locale("ru");
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
-interface Props {
- children: JSX.Element;
-}
-
-export default function ContextProviders({ children }: Props) {
+export default function QuizAnswerer() {
return (
- {children}
+ }
+ onError={handleComponentError}
+ >
+ }>
+
+
+
);
-}
+}
diff --git a/src/WidgetApp.tsx b/src/WidgetApp.tsx
index f13c684..a6c7215 100644
--- a/src/WidgetApp.tsx
+++ b/src/WidgetApp.tsx
@@ -1,7 +1,6 @@
import { Box } from "@mui/material";
-import ContextProviders from "./ContextProviders";
+import QuizAnswerer from "./QuizAnswerer";
import { QuizIdContext } from "./contexts/QuizIdContext";
-import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
interface Props {
@@ -12,14 +11,12 @@ export default function WidgetApp({ quizId }: Props) {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/model/api/getQuizData.ts b/src/model/api/getQuizData.ts
index 9fab68d..96c44fd 100644
--- a/src/model/api/getQuizData.ts
+++ b/src/model/api/getQuizData.ts
@@ -24,8 +24,8 @@ export interface GetQuizDataResponse {
}[];
}
-export function parseQuizData(quizDataResponse: GetQuizDataResponse, quizId: string): QuizSettings {
- const items: QuizSettings["items"] = quizDataResponse.items.map((item) => {
+export function parseQuizData(quizDataResponse: GetQuizDataResponse, quizId: string): Omit {
+ const items: QuizSettings["questions"] = quizDataResponse.items.map((item) => {
const content = JSON.parse(item.c);
return {
@@ -51,5 +51,5 @@ export function parseQuizData(quizDataResponse: GetQuizDataResponse, quizId: str
pausable: quizDataResponse.settings.pausable
};
- return { cnt: quizDataResponse.cnt, settings, items };
+ return { cnt: quizDataResponse.cnt, settings, questions: items };
}
diff --git a/src/model/settingsData.ts b/src/model/settingsData.ts
index 29d7fb1..bfbbd1d 100644
--- a/src/model/settingsData.ts
+++ b/src/model/settingsData.ts
@@ -30,7 +30,7 @@ export type FCField = {
};
export type QuizSettings = {
- items: AnyTypedQuizQuestion[];
+ questions: AnyTypedQuizQuestion[];
settings: {
qid: string;
fp: boolean;
@@ -43,6 +43,7 @@ export type QuizSettings = {
cfg: QuizConfig;
};
cnt: number;
+ recentlyCompleted: boolean;
};
export interface QuizConfig {
diff --git a/src/pages/ViewPublicationPage/ContactForm.tsx b/src/pages/ViewPublicationPage/ContactForm.tsx
index 572b991..321423a 100644
--- a/src/pages/ViewPublicationPage/ContactForm.tsx
+++ b/src/pages/ViewPublicationPage/ContactForm.tsx
@@ -1,22 +1,21 @@
import AddressIcon from "@icons/ContactFormIcon/AddressIcon";
-import NameIcon from "@icons/ContactFormIcon/NameIcon";
import EmailIcon from "@icons/ContactFormIcon/EmailIcon";
+import NameIcon from "@icons/ContactFormIcon/NameIcon";
import PhoneIcon from "@icons/ContactFormIcon/PhoneIcon";
import TextIcon from "@icons/ContactFormIcon/TextIcon";
import { Box, Button, InputAdornment, Link, TextField as MuiTextField, TextFieldProps, Typography, useMediaQuery, useTheme } from "@mui/material";
-
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import { FC, useRef, useState } from "react";
import { sendFC } from "@api/quizRelase";
import { NameplateLogo } from "@icons/NameplateLogo";
import { QuizQuestionResult } from "@model/questionTypes/result";
-import { quizThemes } from "@utils/themes/Publication/themePublication";
+import { useQuizData } from "@utils/hooks/useQuizData";
import { enqueueSnackbar } from "notistack";
import { ApologyPage } from "./ApologyPage";
import { checkEmptyData } from "./tools/checkEmptyData";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { quizThemes } from "@utils/themes/Publication/themePublication";
const TextField = MuiTextField as unknown as FC; // temporary fix ts(2590)
@@ -74,7 +73,7 @@ export const ContactForm = ({
setShowResultForm,
}: ContactFormProps) => {
const theme = useTheme();
- const { settings, items } = useQuestionsStore();
+ const { settings, questions } = useQuizData();
const [ready, setReady] = useState(false);
const [name, setName] = useState("");
@@ -93,7 +92,7 @@ export const ContactForm = ({
};
//@ts-ignore
- const resultQuestion: QuizQuestionResult = items.find((question) => {
+ const resultQuestion: QuizQuestionResult = questions.find((question) => {
if (settings?.cfg.haveRoot) {
//ветвимся
return (
@@ -110,8 +109,6 @@ export const ContactForm = ({
});
const inputHC = async () => {
- if (!settings) return;
-
//@ts-ignore
const FC = settings?.cfg.formContact.fields || settings?.cfg.formContact;
const body = {};
@@ -157,7 +154,6 @@ export const ContactForm = ({
}
let isWide = Object.keys(filteredFC).length > 2;
- if (!settings) throw new Error("settings is null");
if (!resultQuestion)
return (
@@ -360,15 +356,13 @@ export const ContactForm = ({
@@ -393,7 +387,7 @@ const Inputs = ({
adress,
setAdress,
}: any) => {
- const { settings } = useQuestionsStore();
+ const { settings } = useQuizData();
// @ts-ignore
const FC = settings?.cfg.formContact.fields || settings?.cfg.formContact;
diff --git a/src/pages/ViewPublicationPage/Footer.tsx b/src/pages/ViewPublicationPage/Footer.tsx
index 9dd9f3c..34866ca 100644
--- a/src/pages/ViewPublicationPage/Footer.tsx
+++ b/src/pages/ViewPublicationPage/Footer.tsx
@@ -1,16 +1,14 @@
import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material";
import { useCallback, useMemo, useState } from "react";
-import { getQuestionById } from "@stores/quizData/actions";
-
import { enqueueSnackbar } from "notistack";
import type { AnyTypedQuizQuestion, QuizQuestionBase } from "../../model/questionTypes/shared";
import { checkEmptyData } from "./tools/checkEmptyData";
import type { QuizQuestionResult } from "@model/questionTypes/result";
-import { useQuestionsStore } from "@stores/quizData/store";
import { useQuizViewStore } from "@stores/quizView/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
type FooterProps = {
setCurrentQuestion: (step: AnyTypedQuizQuestion) => void;
@@ -22,13 +20,13 @@ type FooterProps = {
export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setShowResultForm }: FooterProps) => {
const theme = useTheme();
- const { settings, items } = useQuestionsStore();
+ const { settings, questions } = useQuizData();
const answers = useQuizViewStore(state => state.answers);
const [stepNumber, setStepNumber] = useState(1);
const isMobileMini = useMediaQuery(theme.breakpoints.down(382));
- const isLinear = !items.some(({ content }) => content.rule.parentId === "root");
+ const isLinear = !questions.some(({ content }) => content.rule.parentId === "root");
const getNextQuestionId = useCallback(() => {
console.log("Смотрим какой вопрос будет дальше. Что у нас сегодня вкусненького? Щя покажу от какого вопроса мы ищем следующий шаг");
@@ -86,27 +84,27 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
}
//ничё не нашли, ищем резулт
console.log("ничё не нашли, ищем резулт ");
- return items.find(q => {
+ return questions.find(q => {
console.log('q.type === "result"', q.type === "result");
console.log('q.content.rule.parentId', q.content.rule.parentId);
console.log('question.content.id', question.content.id);
return q.type === "result" && q.content.rule.parentId === question.content.id;
})?.id;
- }, [answers, items, question]);
+ }, [answers, questions, question]);
const isPreviousButtonDisabled = useMemo(() => {
// Логика для аргумента disabled у кнопки "Назад"
if (isLinear) {
- const questionIndex = items.findIndex(({ id }) => id === question.id);
+ const questionIndex = questions.findIndex(({ id }) => id === question.id);
- const previousQuestion = items[questionIndex - 1];
+ const previousQuestion = questions[questionIndex - 1];
return previousQuestion ? false : true;
} else {
return question?.content.rule.parentId === "root" ? true : false;
}
- }, [items, isLinear, question?.content.rule.parentId, question.id]);
+ }, [questions, isLinear, question?.content.rule.parentId, question.id]);
const isNextButtonDisabled = useMemo(() => {
// Логика для аргумента disabled у кнопки "Далее"
@@ -128,7 +126,8 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
if (nextQuestionId) {
return false;
} else {
- const nextQuestion = getQuestionById(question.content.rule.default);
+ const questionId = question.content.rule.default;
+ const nextQuestion = questions.find(q => q.id === questionId || q.content.id === questionId) || null;
if (nextQuestion?.type) {
return false;
@@ -137,7 +136,6 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
}, [answers, getNextQuestionId, isLinear, question.content, question.id]);
const showResult = (nextQuestion: QuizQuestionResult) => {
- if (!settings) return;
if (!nextQuestion) return;
const isEmpty = checkEmptyData({ resultData: nextQuestion });
@@ -168,9 +166,9 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
if (isLinear) {
setStepNumber(q => q - 1);
- const questionIndex = items.findIndex(({ id }) => id === question.id);
+ const questionIndex = questions.findIndex(({ id }) => id === question.id);
- const previousQuestion = items[questionIndex - 1];
+ const previousQuestion = questions[questionIndex - 1];
if (previousQuestion) {
setCurrentQuestion(previousQuestion);
@@ -180,7 +178,8 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
}
if (question?.content.rule.parentId !== "root") {
- const parent = getQuestionById(question?.content.rule.parentId);
+ const questionId = question?.content.rule.parentId;
+ const parent = questions.find(q => q.id === questionId || q.content.id === questionId) || null;
if (parent?.type) {
setCurrentQuestion(parent);
} else {
@@ -195,14 +194,14 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
if (isLinear) {
setStepNumber(q => q + 1);
- const questionIndex = items.findIndex(({ id }) => id === question.id);
- const nextQuestion = items[questionIndex + 1];
+ const questionIndex = questions.findIndex(({ id }) => id === question.id);
+ const nextQuestion = questions[questionIndex + 1];
if (nextQuestion && nextQuestion.type !== "result") {
setCurrentQuestion(nextQuestion);
} else {
//@ts-ignore
- showResult(items.find(q => q.content.rule.parentId === "line"));
+ showResult(questions.find(q => q.content.rule.parentId === "line"));
}
return;
@@ -211,7 +210,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
const nextQuestionId = getNextQuestionId();
if (nextQuestionId) {
- const nextQuestion = getQuestionById(nextQuestionId);
+ const nextQuestion = questions.find(q => q.id === nextQuestionId || q.content.id === nextQuestionId) || null;
if (nextQuestion?.type && nextQuestion.type === "result") {
showResult(nextQuestion);
@@ -278,7 +277,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
Из
- {items.filter(q => q.type !== "result").length}
+ {questions.filter(q => q.type !== "result").length}
}
diff --git a/src/pages/ViewPublicationPage/Question.tsx b/src/pages/ViewPublicationPage/Question.tsx
index 03f43ac..d3fe759 100644
--- a/src/pages/ViewPublicationPage/Question.tsx
+++ b/src/pages/ViewPublicationPage/Question.tsx
@@ -1,8 +1,6 @@
import { Box, useMediaQuery, useTheme } from "@mui/material";
import { useEffect, useState } from "react";
-import { getQuestionById } from "@stores/quizData/actions";
-
import { ContactForm } from "./ContactForm";
import { Footer } from "./Footer";
import { ResultForm } from "./ResultForm";
@@ -23,23 +21,22 @@ import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
import { NameplateLogoFQ } from "@icons/NameplateLogoFQ";
import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
import { QuizQuestionResult } from "@model/questionTypes/result";
-import { useQuestionsStore } from "@stores/quizData/store";
import { notReachable } from "@utils/notReachable";
import { quizThemes } from "@utils/themes/Publication/themePublication";
+import { useQuizData } from "@utils/hooks/useQuizData";
export const Question = () => {
const theme = useTheme();
- const settings = useQuestionsStore(state => state.settings);
- const questions = useQuestionsStore(state => state.items);
+ const { settings, questions } = useQuizData();
const [currentQuestion, setCurrentQuestion] = useState();
const [showContactForm, setShowContactForm] = useState(false);
const [showResultForm, setShowResultForm] = useState(false);
const isMobile = useMediaQuery(theme.breakpoints.down(650));
useEffect(() => {
-
if (settings?.cfg.haveRoot) {//ветвимся
- const nextQuestion = getQuestionById(settings?.cfg.haveRoot || "");
+ const questionId = settings?.cfg.haveRoot || "";
+ const nextQuestion = questions.find(q => q.id === questionId || q.content.id === questionId) || null;
if (nextQuestion?.type) {
setCurrentQuestion(nextQuestion);
@@ -49,10 +46,8 @@ export const Question = () => {
} else {//идём прямо
setCurrentQuestion(questions[0]);
}
-
}, []);
- if (!settings) throw new Error("settings is null");
if (!currentQuestion || currentQuestion.type === "result") return "не смог отобразить вопрос";
return (
diff --git a/src/pages/ViewPublicationPage/ResultForm.tsx b/src/pages/ViewPublicationPage/ResultForm.tsx
index 6666bd4..335d9f3 100644
--- a/src/pages/ViewPublicationPage/ResultForm.tsx
+++ b/src/pages/ViewPublicationPage/ResultForm.tsx
@@ -9,10 +9,10 @@ import {
import { NameplateLogo } from "@icons/NameplateLogo";
import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe";
-import { useQuestionsStore } from "@stores/quizData/store";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import { useCallback, useEffect, useMemo } from "react";
import type { QuizQuestionResult } from "../../model/questionTypes/result";
+import { useQuizData } from "@utils/hooks/useQuizData";
type ResultFormProps = {
@@ -29,34 +29,33 @@ export const ResultForm = ({
}: ResultFormProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
- const { settings, items } = useQuestionsStore();
- if (!settings) throw new Error("settings is null");
+ const { settings, questions } = useQuizData();
const resultQuestion = useMemo(() => {
if (settings?.cfg.haveRoot) {
//ищём для ветвления
- return (items.find(
+ return (questions.find(
(question): question is QuizQuestionResult =>
question.type === "result" &&
question.content.rule.parentId === currentQuestion.content.id
- ) || items.find(
+ ) || questions.find(
(question): question is QuizQuestionResult =>
question.type === "result" &&
question.content.rule.parentId === "line"
));
} else {
- return items.find(
+ return questions.find(
(question): question is QuizQuestionResult =>
question.type === "result" &&
question.content.rule.parentId === "line"
);
}
- }, [currentQuestion.content.id, items, settings?.cfg.haveRoot]);
+ }, [currentQuestion.content.id, questions, settings?.cfg.haveRoot]);
const followNextForm = useCallback(() => {
setShowResultForm(false);
setShowContactForm(true);
- },[setShowContactForm, setShowResultForm]);
+ }, [setShowContactForm, setShowResultForm]);
useEffect(() => {
if (!resultQuestion) {
diff --git a/src/pages/ViewPublicationPage/StartPageViewPublication.tsx b/src/pages/ViewPublicationPage/StartPageViewPublication.tsx
index 9546093..b80dba8 100644
--- a/src/pages/ViewPublicationPage/StartPageViewPublication.tsx
+++ b/src/pages/ViewPublicationPage/StartPageViewPublication.tsx
@@ -1,12 +1,12 @@
import { Box, Button, ButtonBase, Link, Paper, Typography, useMediaQuery, useTheme } from "@mui/material";
-import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe";
-import { notReachable } from "../../utils/notReachable";
import { useUADevice } from "../../utils/hooks/useUADevice";
+import { notReachable } from "../../utils/notReachable";
+import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe";
import { NameplateLogo } from "@icons/NameplateLogo";
-import { quizThemes } from "@utils/themes/Publication/themePublication";
import { QuizStartpageAlignType, QuizStartpageType } from "@model/settingsData";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
+import { quizThemes } from "@utils/themes/Publication/themePublication";
interface Props {
@@ -15,12 +15,10 @@ interface Props {
export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
const theme = useTheme();
- const { settings } = useQuestionsStore();
+ const { settings } = useQuizData();
const { isMobileDevice } = useUADevice();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
- if (!settings) throw new Error("settings is null");
-
const handleCopyNumber = () => {
navigator.clipboard.writeText(settings.cfg.info.phonenumber);
};
diff --git a/src/pages/ViewPublicationPage/ViewPublicationPage.tsx b/src/pages/ViewPublicationPage/ViewPublicationPage.tsx
index 16ba51e..d2a9a0c 100644
--- a/src/pages/ViewPublicationPage/ViewPublicationPage.tsx
+++ b/src/pages/ViewPublicationPage/ViewPublicationPage.tsx
@@ -1,55 +1,33 @@
-import { getData } from "@api/quizRelase";
-import { QuizSettings } from "@model/settingsData";
import { Box, ThemeProvider } from "@mui/material";
-import { setQuizData } from "@stores/quizData/actions";
-import { useQuestionsStore } from "@stores/quizData/store";
-import LoadingSkeleton from "@ui_kit/LoadingSkeleton";
+import { useQuizData } from "@utils/hooks/useQuizData";
import { quizThemes } from "@utils/themes/Publication/themePublication";
-import { enqueueSnackbar } from "notistack";
import { useEffect, useState } from "react";
-import useSWR from "swr";
import { ApologyPage } from "./ApologyPage";
import { Question } from "./Question";
import { StartPageViewPublication } from "./StartPageViewPublication";
-import { parseQuizData } from "@model/api/getQuizData";
-import { replaceSpacesToEmptyLines } from "./tools/replaceSpacesToEmptyLines";
-import { useQuizId } from "../../contexts/QuizIdContext";
-
export const ViewPage = () => {
- const quizId = useQuizId();
- const { isLoading, error } = useSWR(["quizData", quizId], params => getQuizData(params[1]), {
- onSuccess: setQuizData,
- });
- const { settings, items, recentlyСompleted } = useQuestionsStore();
+ const { settings, questions, recentlyCompleted } = useQuizData();
const [visualStartPage, setVisualStartPage] = useState();
- useEffect(() => {//установка фавиконки
- if (!settings) return;
-
+ useEffect(() => {
const link = document.querySelector('link[rel="icon"]');
if (link && settings.cfg.startpage.favIcon) {
link.setAttribute("href", settings?.cfg.startpage.favIcon);
}
- //установка заголовка страницы
+
document.title = settings.name;
setVisualStartPage(!settings.cfg.noStartPage);
}, [settings]);
- const questionsCount = items.filter(({ type }) => type !== null && type !== "result").length;
-
- if (error) {
- console.log(error);
- return ;
- }
- if (isLoading || !settings) return ;
+ const questionsCount = questions.filter(({ type }) => type !== null && type !== "result").length;
if (questionsCount === 0) return ;
return (
- {recentlyСompleted ? (
+ {recentlyCompleted ? (
) : (
@@ -62,21 +40,4 @@ export const ViewPage = () => {
)}
);
-};
-
-async function getQuizData(quizId: string) {
- const response = await getData(quizId);
- const quizDataResponse = response.data;
-
- if (response.error) {
- enqueueSnackbar(response.error);
- throw new Error(response.error);
- }
- if (!quizDataResponse) {
- throw new Error("Quiz not found");
- }
-
- const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse, quizId));
-
- return JSON.parse(JSON.stringify({ data: quizSettings }).replaceAll(/\\" \\"/g, '""').replaceAll(/" "/g, '""')).data as QuizSettings & { recentlyСompleted: boolean; };
-}
+};
diff --git a/src/pages/ViewPublicationPage/questions/Date.tsx b/src/pages/ViewPublicationPage/questions/Date.tsx
index 6f80cd2..a85f769 100644
--- a/src/pages/ViewPublicationPage/questions/Date.tsx
+++ b/src/pages/ViewPublicationPage/questions/Date.tsx
@@ -8,103 +8,101 @@ import type { QuizQuestionDate } from "../../../model/questionTypes/date";
import CalendarIcon from "@icons/CalendarIcon";
import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
-
+
import { quizThemes } from "@utils/themes/Publication/themePublication";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
type DateProps = {
- currentQuestion: QuizQuestionDate;
+ currentQuestion: QuizQuestionDate;
};
export const Date = ({ currentQuestion }: DateProps) => {
- const theme = useTheme();
+ const theme = useTheme();
- const { settings } = useQuestionsStore();
- const { answers } = useQuizViewStore();
- const answer = answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- )?.answer as string;
- const currentAnswer = moment(answer) || moment();
-
- if (!settings) throw new Error("settings is null");
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const answer = answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ )?.answer as string;
+ const currentAnswer = moment(answer) || moment();
- return (
-
-
- {currentQuestion.title}
-
-
- (
-
+
+ {currentQuestion.title}
+
+
- ),
- }}
- value={ currentAnswer }
- onChange={async (date) => {
- console.log(date)
- if (!date) {
- return;
- }
+ >
+ (
+
+ ),
+ }}
+ value={currentAnswer}
+ onChange={async (date) => {
+ console.log(date);
+ if (!date) {
+ return;
+ }
- try {
- await sendAnswer({
- questionId: currentQuestion.id,
- body: moment(date).format("YYYY.MM.DD"),
- qid: settings.qid,
- });
+ try {
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: moment(date).format("YYYY.MM.DD"),
+ qid: settings.qid,
+ });
- updateAnswer(
- currentQuestion.id,
- date
- );
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан");
- }
- }}
- slotProps={{
- openPickerButton: {
- sx: {
- p: 0,
- },
- "data-cy": "open-datepicker",
- },
- layout: {
- sx: { backgroundColor: theme.palette.background.default },
- },
- }}
- sx={{
- "& .MuiInputBase-root": {
- backgroundColor: quizThemes[settings.cfg.theme].isLight
- ? "white"
- : theme.palette.background.default,
- borderRadius: "10px",
- maxWidth: "250px",
- pr: "22px",
- "& input": {
- py: "11px",
- pl: "20px",
- lineHeight: "19px",
- },
- "& fieldset": {
- borderColor: "#9A9AAF",
- },
- },
- }}
- />
-
-
- );
+ updateAnswer(
+ currentQuestion.id,
+ date
+ );
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ }}
+ slotProps={{
+ openPickerButton: {
+ sx: {
+ p: 0,
+ },
+ "data-cy": "open-datepicker",
+ },
+ layout: {
+ sx: { backgroundColor: theme.palette.background.default },
+ },
+ }}
+ sx={{
+ "& .MuiInputBase-root": {
+ backgroundColor: quizThemes[settings.cfg.theme].isLight
+ ? "white"
+ : theme.palette.background.default,
+ borderRadius: "10px",
+ maxWidth: "250px",
+ pr: "22px",
+ "& input": {
+ py: "11px",
+ pl: "20px",
+ lineHeight: "19px",
+ },
+ "& fieldset": {
+ borderColor: "#9A9AAF",
+ },
+ },
+ }}
+ />
+
+
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Emoji.tsx b/src/pages/ViewPublicationPage/questions/Emoji.tsx
index dd8f12b..b6ba3eb 100644
--- a/src/pages/ViewPublicationPage/questions/Emoji.tsx
+++ b/src/pages/ViewPublicationPage/questions/Emoji.tsx
@@ -14,148 +14,146 @@ import RadioCheck from "@ui_kit/RadioCheck";
import RadioIcon from "@ui_kit/RadioIcon";
import { sendAnswer } from "@api/quizRelase";
-
+
import { enqueueSnackbar } from "notistack";
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
type EmojiProps = {
- currentQuestion: QuizQuestionEmoji;
+ currentQuestion: QuizQuestionEmoji;
};
export const Emoji = ({ currentQuestion }: EmojiProps) => {
- const theme = useTheme();
-
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
- const { answer } =
- answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- ) ?? {};
+ const theme = useTheme();
- if (!settings) throw new Error("settings is null");
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const { answer } =
+ answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ ) ?? {};
return (
-
- {currentQuestion.title}
- answer === id
- )}
- onChange={({ target }) =>{
- updateAnswer(
- currentQuestion.id,
- currentQuestion.content.variants[Number(target.value)].answer
- )
- }
- }
- sx={{
- display: "flex",
- flexWrap: "wrap",
- flexDirection: "row",
- justifyContent: "space-between",
- marginTop: "20px",
- }}
- >
-
- {currentQuestion.content.variants.map((variant, index) => (
-
-
-
- {variant.extendedText && (
-
- {variant.extendedText}
-
- )}
-
-
- {
- event.preventDefault();
-
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: currentQuestion.content.variants[index].extendedText + " " + currentQuestion.content.variants[index].answer,
- qid: settings.qid
- })
-
- updateAnswer(
+
+ {currentQuestion.title}
+ answer === id
+ )}
+ onChange={({ target }) => {
+ updateAnswer(
currentQuestion.id,
- currentQuestion.content.variants[index].id
- );
-
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
-
-
-
- if (answer === currentQuestion.content.variants[index].id) {
- deleteAnswer(currentQuestion.id);
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: "",
- qid: settings.qid
- })
-
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
- }
- }}
-
- control={
- } icon={} />
- }
- label={
-
- {variant.answer}
-
- }
- />
-
- ))}
-
-
-
+ currentQuestion.content.variants[Number(target.value)].answer
+ );
+ }
+ }
+ sx={{
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginTop: "20px",
+ }}
+ >
+
+ {currentQuestion.content.variants.map((variant, index) => (
+
+
+
+ {variant.extendedText && (
+
+ {variant.extendedText}
+
+ )}
+
+
+ {
+ event.preventDefault();
+
+ try {
+
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: currentQuestion.content.variants[index].extendedText + " " + currentQuestion.content.variants[index].answer,
+ qid: settings.qid
+ });
+
+ updateAnswer(
+ currentQuestion.id,
+ currentQuestion.content.variants[index].id
+ );
+
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+
+
+
+ if (answer === currentQuestion.content.variants[index].id) {
+ deleteAnswer(currentQuestion.id);
+ try {
+
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: "",
+ qid: settings.qid
+ });
+
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ }
+ }}
+
+ control={
+ } icon={} />
+ }
+ label={
+
+ {variant.answer}
+
+ }
+ />
+
+ ))}
+
+
+
);
-
+
};
diff --git a/src/pages/ViewPublicationPage/questions/File.tsx b/src/pages/ViewPublicationPage/questions/File.tsx
index cc4a53d..5336533 100644
--- a/src/pages/ViewPublicationPage/questions/File.tsx
+++ b/src/pages/ViewPublicationPage/questions/File.tsx
@@ -1,12 +1,11 @@
import {
- Box,
- Typography,
- ButtonBase,
- useTheme,
- IconButton, useMediaQuery, Modal,
+ Box,
+ Typography,
+ ButtonBase,
+ useTheme,
+ IconButton, useMediaQuery, Modal,
} from "@mui/material";
import { useQuizViewStore, updateAnswer } from "@stores/quizView/store";
-import { UPLOAD_FILE_TYPES_MAP } from "../tools/File";
import UploadIcon from "@icons/UploadIcon";
import CloseBold from "@icons/CloseBold";
@@ -17,328 +16,326 @@ import type { DragEvent } from "react";
import type { UploadFileType } from "@model/questionTypes/file";
import { enqueueSnackbar } from "notistack";
import { sendAnswer, sendFile } from "@api/quizRelase";
-import { useQuestionsStore } from "@stores/quizData/store"
import Info from "@icons/Info";
+import { useQuizData } from "@utils/hooks/useQuizData";
type FileProps = {
- currentQuestion: QuizQuestionFile;
+ currentQuestion: QuizQuestionFile;
};
-const CurrentModal = ({ status }: { status: "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | "" }) => {
- switch (status) {
- case 'errorType':
- return (<>
- Выбран некорректный тип файла
- >)
- case 'errorSize':
- return (<>
- Файл слишком большой. Максимальный размер 50 МБ
- >)
- default:
- return (<>
- Допустимые расширения файлов:
- {
- //@ts-ignore
- ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}
- >)
- }
-}
+const CurrentModal = ({ status }: { status: "errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | ""; }) => {
+ switch (status) {
+ case 'errorType':
+ return (<>
+ Выбран некорректный тип файла
+ >);
+ case 'errorSize':
+ return (<>
+ Файл слишком большой. Максимальный размер 50 МБ
+ >);
+ default:
+ return (<>
+ Допустимые расширения файлов:
+ {
+ //@ts-ignore
+ ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}
+ >);
+ }
+};
const ACCEPT_SEND_FILE_TYPES_MAP = {
- picture: [
- ".jpeg",
- ".jpg",
- ".png",
- ".ico",
- ".gif",
- ".tiff",
- ".webp",
- ".eps",
- ".svg"
- ],
- video: [
- ".mp4",
- ".mov",
- ".wmv",
- ".avi",
- ".avchd",
- ".flv",
- ".f4v",
- ".swf",
- ".mkv",
- ".webm",
- ".mpeg-2"
- ],
- audio: [
- ".aac",
- ".aiff",
- ".dsd",
- ".flac",
- ".mp3",
- ".mqa",
- ".ogg",
- ".wav",
- ".wma"
- ],
- document: [
- ".doc",
- ".docx",
- ".dotx",
- ".rtf",
- ".odt",
- ".pdf",
- ".txt",
- ".xls",
- ".ppt",
- ".xlsx",
- ".pptx",
- ".pages",
- ],
+ picture: [
+ ".jpeg",
+ ".jpg",
+ ".png",
+ ".ico",
+ ".gif",
+ ".tiff",
+ ".webp",
+ ".eps",
+ ".svg"
+ ],
+ video: [
+ ".mp4",
+ ".mov",
+ ".wmv",
+ ".avi",
+ ".avchd",
+ ".flv",
+ ".f4v",
+ ".swf",
+ ".mkv",
+ ".webm",
+ ".mpeg-2"
+ ],
+ audio: [
+ ".aac",
+ ".aiff",
+ ".dsd",
+ ".flac",
+ ".mp3",
+ ".mqa",
+ ".ogg",
+ ".wav",
+ ".wma"
+ ],
+ document: [
+ ".doc",
+ ".docx",
+ ".dotx",
+ ".rtf",
+ ".odt",
+ ".pdf",
+ ".txt",
+ ".xls",
+ ".ppt",
+ ".xlsx",
+ ".pptx",
+ ".pages",
+ ],
-}
+};
const UPLOAD_FILE_DESCRIPTIONS_MAP: Record<
- UploadFileType,
- { title: string; description: string }
+ UploadFileType,
+ { title: string; description: string; }
> = {
- picture: {
- title: "Добавить изображение",
- description: "Принимает изображения",
- },
- video: {
- title: "Добавить видео",
- description: "Принимает .mp4 и .mov формат — максимум 100мб",
- },
- audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
- document: { title: "Добавить документ", description: "Принимает документы" },
+ picture: {
+ title: "Добавить изображение",
+ description: "Принимает изображения",
+ },
+ video: {
+ title: "Добавить видео",
+ description: "Принимает .mp4 и .mov формат — максимум 100мб",
+ },
+ audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
+ document: { title: "Добавить документ", description: "Принимает документы" },
} as const;
export const File = ({ currentQuestion }: FileProps) => {
- const theme = useTheme();
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
+ const theme = useTheme();
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
- const [statusModal, setStatusModal] = useState<"errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | "">("")
+ const [statusModal, setStatusModal] = useState<"errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | "">("");
- const answer = answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- )?.answer as string;
- const isMobile = useMediaQuery(theme.breakpoints.down(500));
- const uploadFile = async ({ target }: ChangeEvent) => {
- if (!settings) return;
-
- const file = target.files?.[0];
- if (file) {
- if (file.size <= 52428800) {
- //проверяем на соответствие
- console.log(file.name.toLowerCase())
- if (ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].find((ednding => {
- console.log(ednding)
- console.log(file.name.toLowerCase().endsWith(ednding))
- return file.name.toLowerCase().endsWith(ednding)
- }))) {
+ const answer = answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ )?.answer as string;
+ const isMobile = useMediaQuery(theme.breakpoints.down(500));
+ const uploadFile = async ({ target }: ChangeEvent) => {
+ const file = target.files?.[0];
+ if (file) {
+ if (file.size <= 52428800) {
+ //проверяем на соответствие
+ console.log(file.name.toLowerCase());
+ if (ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].find((ednding => {
+ console.log(ednding);
+ console.log(file.name.toLowerCase().endsWith(ednding));
+ return file.name.toLowerCase().endsWith(ednding);
+ }))) {
- //Нужный формат
- console.log(file)
- try {
+ //Нужный формат
+ console.log(file);
+ try {
- const data = await sendFile({
- questionId: currentQuestion.id,
- body: {
- file: file,
- name: file.name
- },
- qid: settings.qid
- })
- console.log(data)
+ const data = await sendFile({
+ questionId: currentQuestion.id,
+ body: {
+ file: file,
+ name: file.name
+ },
+ qid: settings.qid
+ });
+ console.log(data);
- await sendAnswer({
- questionId: currentQuestion.id,
- //@ts-ignore
- body: `https://storage.yandexcloud.net/squizanswer/${settings.qid}/${currentQuestion.id}/${data.data.fileIDMap[currentQuestion.id]}`,
- //@ts-ignore
- qid: settings.qid
- })
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ //@ts-ignore
+ body: `https://storage.yandexcloud.net/squizanswer/${settings.qid}/${currentQuestion.id}/${data.data.fileIDMap[currentQuestion.id]}`,
+ //@ts-ignore
+ qid: settings.qid
+ });
- updateAnswer(
- currentQuestion.id,
- `${file.name}|${URL.createObjectURL(file)}`
- );
+ updateAnswer(
+ currentQuestion.id,
+ `${file.name}|${URL.createObjectURL(file)}`
+ );
- } catch (e) {
- console.log(e)
- enqueueSnackbar("ответ не был засчитан")
- }
+ } catch (e) {
+ console.log(e);
+ enqueueSnackbar("ответ не был засчитан");
+ }
- } else {
+ } else {
+
+ //неподходящий формат
+ setStatusModal("errorType");
+ }
+ } else {
+
+ setStatusModal("errorSize");
+ }
- //неподходящий формат
- setStatusModal("errorType")
}
- } else {
+ };
- setStatusModal("errorSize")
- }
-
- }
- };
-
- return (
- <>
-
- {currentQuestion.title}
-
- {answer?.split("|")[0] && (
-
- Вы загрузили:
-
-
- {answer?.split("|")[0]}
- {
- updateAnswer(currentQuestion.id, "");
- }}
- >
-
-
-
-
- )}
-
- {!answer?.split("|")[0] && (
-
-
-
+ return (
+ <>
+
+ {currentQuestion.title}
) =>
- event.preventDefault()
- }
- sx={{
- width: "100%",
- height: isMobile ? undefined : "120px",
- display: "flex",
- gap: "50px",
- justifyContent: "flex-start",
- alignItems: "center",
- padding: "33px 44px 33px 55px",
- backgroundColor: theme.palette.background.default,
- border: `1px solid #9A9AAF`,
- // border: `1px solid ${theme.palette.grey2.main}`,
- borderRadius: "8px",
- }}
+ sx={{
+ display: "flex",
+ flexDirection: "column",
+ width: "100%",
+ marginTop: "20px",
+ maxWidth: answer?.split("|")[0] ? "640px" : "600px",
+ }}
>
-
-
-
- {
- UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
- .title
- }
-
-
- {
- UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
- .description
- }
-
-
+ {answer?.split("|")[0] && (
+
+ Вы загрузили:
+
+
+ {answer?.split("|")[0]}
+ {
+ updateAnswer(currentQuestion.id, "");
+ }}
+ >
+
+
+
+
+ )}
+
+ {!answer?.split("|")[0] && (
+
+
+
+ ) =>
+ event.preventDefault()
+ }
+ sx={{
+ width: "100%",
+ height: isMobile ? undefined : "120px",
+ display: "flex",
+ gap: "50px",
+ justifyContent: "flex-start",
+ alignItems: "center",
+ padding: "33px 44px 33px 55px",
+ backgroundColor: theme.palette.background.default,
+ border: `1px solid #9A9AAF`,
+ // border: `1px solid ${theme.palette.grey2.main}`,
+ borderRadius: "8px",
+ }}
+ >
+
+
+
+ {
+ UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
+ .title
+ }
+
+
+ {
+ UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
+ .description
+ }
+
+
+
+
+ setStatusModal(currentQuestion.content.type)} />
+
+ )}
+ {answer && currentQuestion.content.type === "picture" && (
+
+ )}
+ {answer && currentQuestion.content.type === "video" && (
+
+ )}
-
- setStatusModal(currentQuestion.content.type)} />
- )}
- {answer && currentQuestion.content.type === "picture" && (
-
- )}
- {answer && currentQuestion.content.type === "video" && (
-
- )}
-
-
- setStatusModal("")}
- >
-
-
-
-
- >
- );
+ setStatusModal("")}
+ >
+
+
+
+
+ >
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Images.tsx b/src/pages/ViewPublicationPage/questions/Images.tsx
index cb7530a..6d0483c 100644
--- a/src/pages/ViewPublicationPage/questions/Images.tsx
+++ b/src/pages/ViewPublicationPage/questions/Images.tsx
@@ -1,11 +1,11 @@
import {
- Box,
- Typography,
- RadioGroup,
- FormControlLabel,
- Radio,
- useTheme,
- useMediaQuery,
+ Box,
+ Typography,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ useTheme,
+ useMediaQuery,
} from "@mui/material";
import { useQuizViewStore, updateAnswer, deleteAnswer } from "@stores/quizView/store";
@@ -15,138 +15,136 @@ import RadioIcon from "@ui_kit/RadioIcon";
import type { QuizQuestionImages } from "../../../model/questionTypes/images";
import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
-import { useQuestionsStore } from "@stores/quizData/store"
+import { useQuizData } from "@utils/hooks/useQuizData";
type ImagesProps = {
- currentQuestion: QuizQuestionImages;
+ currentQuestion: QuizQuestionImages;
};
export const Images = ({ currentQuestion }: ImagesProps) => {
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
- const theme = useTheme();
- const { answer } =
- answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- ) ?? {};
- const isTablet = useMediaQuery(theme.breakpoints.down(1000));
- const isMobile = useMediaQuery(theme.breakpoints.down(500));
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const theme = useTheme();
+ const { answer } =
+ answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ ) ?? {};
+ const isTablet = useMediaQuery(theme.breakpoints.down(1000));
+ const isMobile = useMediaQuery(theme.breakpoints.down(500));
- if (!settings) throw new Error("settings is null");
-
- return (
-
- {currentQuestion.title}
- answer === id
- )}
- sx={{
- display: "flex",
- flexWrap: "wrap",
- flexDirection: "row",
- justifyContent: "space-between",
- marginTop: "20px",
- }}
- >
-
- {currentQuestion.content.variants.map((variant, index) => (
- {
- event.preventDefault();
-
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: `${currentQuestion.content.variants[index].answer}
`,
- qid: settings.qid
- })
-
- updateAnswer(
- currentQuestion.id,
- currentQuestion.content.variants[index].id
- );
-
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
-
-
- if (answer === currentQuestion.content.variants[index].id) {
- deleteAnswer(currentQuestion.id);
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: "",
- qid: settings.qid
- })
-
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
- }
- }}
- >
-
-
- {variant.extendedText && (
-
- )}
-
-
-
+ {currentQuestion.title}
+ answer === id
+ )}
sx={{
- textAlign: "center",
- color: theme.palette.text.primary,
- marginTop: "10px",
- marginLeft: 0,
- padding: "10px",
- "& .MuiFormControlLabel-label": {
- wordBreak: "break-word",
- },
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginTop: "20px",
}}
- value={index}
- control={
- } icon={} />
- }
- label={variant.answer}
- />
-
- ))}
+ >
+
+ {currentQuestion.content.variants.map((variant, index) => (
+ {
+ event.preventDefault();
+
+ try {
+
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: `${currentQuestion.content.variants[index].answer}
`,
+ qid: settings.qid
+ });
+
+ updateAnswer(
+ currentQuestion.id,
+ currentQuestion.content.variants[index].id
+ );
+
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+
+
+ if (answer === currentQuestion.content.variants[index].id) {
+ deleteAnswer(currentQuestion.id);
+ try {
+
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: "",
+ qid: settings.qid
+ });
+
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ }
+ }}
+ >
+
+
+ {variant.extendedText && (
+
+ )}
+
+
+ } icon={} />
+ }
+ label={variant.answer}
+ />
+
+ ))}
+
+
-
-
- );
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Number.tsx b/src/pages/ViewPublicationPage/questions/Number.tsx
index e8d1025..1c1c920 100644
--- a/src/pages/ViewPublicationPage/questions/Number.tsx
+++ b/src/pages/ViewPublicationPage/questions/Number.tsx
@@ -12,14 +12,14 @@ import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
import { quizThemes } from "@utils/themes/Publication/themePublication";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
type NumberProps = {
currentQuestion: QuizQuestionNumber;
};
export const Number = ({ currentQuestion }: NumberProps) => {
- const { settings } = useQuestionsStore();
+ const { settings } = useQuizData();
const [inputValue, setInputValue] = useState("0");
const [minRange, setMinRange] = useState("0");
const [maxRange, setMaxRange] = useState("100000000000");
@@ -105,8 +105,6 @@ export const Number = ({ currentQuestion }: NumberProps) => {
}
}, []);
- if (!settings) throw new Error("settings is null");
-
return (
diff --git a/src/pages/ViewPublicationPage/questions/Rating.tsx b/src/pages/ViewPublicationPage/questions/Rating.tsx
index b22562b..bf89ab6 100644
--- a/src/pages/ViewPublicationPage/questions/Rating.tsx
+++ b/src/pages/ViewPublicationPage/questions/Rating.tsx
@@ -1,9 +1,9 @@
import {
- Box,
- Typography,
- Rating as RatingComponent,
- useTheme,
- useMediaQuery
+ Box,
+ Typography,
+ Rating as RatingComponent,
+ useTheme,
+ useMediaQuery
} from "@mui/material";
import { useQuizViewStore, updateAnswer } from "@stores/quizView/store";
@@ -19,127 +19,125 @@ import StarIconMini from "@icons/questionsPage/StarIconMini";
import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
type RatingProps = {
- currentQuestion: QuizQuestionRating;
+ currentQuestion: QuizQuestionRating;
};
const buttonRatingForm = [
- {
- name: "star",
- icon: (color: string) => ,
- },
- {
- name: "trophie",
- icon: (color: string) => ,
- },
- {
- name: "flag",
- icon: (color: string) => ,
- },
- {
- name: "heart",
- icon: (color: string) => ,
- },
- {
- name: "like",
- icon: (color: string) => ,
- },
- {
- name: "bubble",
- icon: (color: string) => ,
- },
- {
- name: "hashtag",
- icon: (color: string) => ,
- },
+ {
+ name: "star",
+ icon: (color: string) => ,
+ },
+ {
+ name: "trophie",
+ icon: (color: string) => ,
+ },
+ {
+ name: "flag",
+ icon: (color: string) => ,
+ },
+ {
+ name: "heart",
+ icon: (color: string) => ,
+ },
+ {
+ name: "like",
+ icon: (color: string) => ,
+ },
+ {
+ name: "bubble",
+ icon: (color: string) => ,
+ },
+ {
+ name: "hashtag",
+ icon: (color: string) => ,
+ },
];
export const Rating = ({ currentQuestion }: RatingProps) => {
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
- const theme = useTheme();
- const isMobile = useMediaQuery(theme.breakpoints.down(650));
- const { answer } =
- answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- ) ?? {};
- const form = buttonRatingForm.find(
- ({ name }) => name === currentQuestion.content.form
- );
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down(650));
+ const { answer } =
+ answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ ) ?? {};
+ const form = buttonRatingForm.find(
+ ({ name }) => name === currentQuestion.content.form
+ );
- if (!settings) throw new Error("settings is null");
-
- return (
-
- {currentQuestion.title}
-
-
- {
+ return (
+
+ {currentQuestion.title}
+
+
+ {
- try {
+ try {
- await sendAnswer({
- questionId: currentQuestion.id,
- body: String(value) + " из " + currentQuestion.content.steps,
- qid: settings.qid
- })
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: String(value) + " из " + currentQuestion.content.steps,
+ qid: settings.qid
+ });
- updateAnswer(currentQuestion.id, String(value))
+ updateAnswer(currentQuestion.id, String(value));
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
- }}
- sx={{
- height: "50px",
- gap: isMobile ? undefined : "15px",
- justifyContent: isMobile ? "space-between" : undefined,
- width: isMobile ? "100%" : undefined
- }}
- max={currentQuestion.content.steps}
- icon={form?.icon(theme.palette.primary.main)}
- emptyIcon={form?.icon("#9A9AAF")}
- />
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ }}
+ sx={{
+ height: "50px",
+ gap: isMobile ? undefined : "15px",
+ justifyContent: isMobile ? "space-between" : undefined,
+ width: isMobile ? "100%" : undefined
+ }}
+ max={currentQuestion.content.steps}
+ icon={form?.icon(theme.palette.primary.main)}
+ emptyIcon={form?.icon("#9A9AAF")}
+ />
+
+
+
+ {currentQuestion.content.ratingNegativeDescription}
+
+
+ {currentQuestion.content.ratingPositiveDescription}
+
+
+
-
-
- {currentQuestion.content.ratingNegativeDescription}
-
-
- {currentQuestion.content.ratingPositiveDescription}
-
-
-
-
- );
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Select.tsx b/src/pages/ViewPublicationPage/questions/Select.tsx
index f990c5b..14abd5b 100644
--- a/src/pages/ViewPublicationPage/questions/Select.tsx
+++ b/src/pages/ViewPublicationPage/questions/Select.tsx
@@ -7,75 +7,73 @@ import { useQuizViewStore, updateAnswer, deleteAnswer } from "@stores/quizView/s
import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
+import { useQuizData } from "@utils/hooks/useQuizData";
-import { useQuestionsStore } from "@stores/quizData/store"
type SelectProps = {
- currentQuestion: QuizQuestionSelect;
+ currentQuestion: QuizQuestionSelect;
};
export const Select = ({ currentQuestion }: SelectProps) => {
- const theme = useTheme();
+ const theme = useTheme();
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
- const { answer } =
- answers.find(
- ({ questionId }) => questionId === currentQuestion.id
- ) ?? {};
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const { answer } =
+ answers.find(
+ ({ questionId }) => questionId === currentQuestion.id
+ ) ?? {};
- if (!settings) throw new Error("settings is null");
+ return (
+
+ {currentQuestion.title}
+
+ answer)}
+ colorMain={theme.palette.primary.main}
+ onChange={async (_, value) => {
+ if (value < 0) {
+ deleteAnswer(currentQuestion.id);
+ try {
- return (
-
- {currentQuestion.title}
-
- answer)}
- colorMain={theme.palette.primary.main}
- onChange={async(_, value) => {
- if (value < 0) {
- deleteAnswer(currentQuestion.id);
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: "",
- qid: settings.qid
- })
-
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
- return;
- }
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: "",
+ qid: settings.qid
+ });
- try {
-
- await sendAnswer({
- questionId: currentQuestion.id,
- body: String(currentQuestion.content.variants[Number(value)].answer),
- qid: settings.qid
- })
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ return;
+ }
- updateAnswer(currentQuestion.id, String(value));
+ try {
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: String(currentQuestion.content.variants[Number(value)].answer),
+ qid: settings.qid
+ });
+
+ updateAnswer(currentQuestion.id, String(value));
+
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
- }}
- />
-
-
- );
+ }}
+ />
+
+
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Text.tsx b/src/pages/ViewPublicationPage/questions/Text.tsx
index 5609f07..e934418 100644
--- a/src/pages/ViewPublicationPage/questions/Text.tsx
+++ b/src/pages/ViewPublicationPage/questions/Text.tsx
@@ -6,63 +6,61 @@ import { useQuizViewStore, updateAnswer } from "@stores/quizView/store";
import type { QuizQuestionText } from "../../../model/questionTypes/text";
import { enqueueSnackbar } from "notistack";
-import { useQuestionsStore } from "@stores/quizData/store"
import { sendAnswer } from "@api/quizRelase";
import { useDebouncedCallback } from "use-debounce";
+import { useQuizData } from "@utils/hooks/useQuizData";
type TextProps = {
- currentQuestion: QuizQuestionText;
+ currentQuestion: QuizQuestionText;
};
export const Text = ({ currentQuestion }: TextProps) => {
- const theme = useTheme();
- const { settings } = useQuestionsStore()
- const { answers } = useQuizViewStore();
- const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
+ const theme = useTheme();
+ const { settings } = useQuizData();
+ const { answers } = useQuizViewStore();
+ const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.id) ?? {};
- const inputHC = useDebouncedCallback(async (text) => {
- if (!settings) return;
-
- try {
+ const inputHC = useDebouncedCallback(async (text) => {
+ try {
- await sendAnswer({
- questionId: currentQuestion.id,
- body: text,
- qid: settings.qid
- })
+ await sendAnswer({
+ questionId: currentQuestion.id,
+ body: text,
+ qid: settings.qid
+ });
- } catch (e) {
- enqueueSnackbar("ответ не был засчитан")
- }
- }, 400);
- return (
-
- {currentQuestion.title}
-
- {
- updateAnswer(currentQuestion.id, target.value)
- inputHC(target.value)
- }
- }
- sx={{
- "&:focus-visible": {
- borderColor: theme.palette.primary.main
- }
- }}
- />
-
-
- );
+ } catch (e) {
+ enqueueSnackbar("ответ не был засчитан");
+ }
+ }, 400);
+ return (
+
+ {currentQuestion.title}
+
+ {
+ updateAnswer(currentQuestion.id, target.value);
+ inputHC(target.value);
+ }
+ }
+ sx={{
+ "&:focus-visible": {
+ borderColor: theme.palette.primary.main
+ }
+ }}
+ />
+
+
+ );
};
diff --git a/src/pages/ViewPublicationPage/questions/Variant.tsx b/src/pages/ViewPublicationPage/questions/Variant.tsx
index a552c01..fee885a 100644
--- a/src/pages/ViewPublicationPage/questions/Variant.tsx
+++ b/src/pages/ViewPublicationPage/questions/Variant.tsx
@@ -29,7 +29,7 @@ import { quizThemes } from "@utils/themes/Publication/themePublication";
import { enqueueSnackbar } from "notistack";
import type { QuestionVariant } from "../../../model/questionTypes/shared";
import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
-import { useQuestionsStore } from "@stores/quizData/store";
+import { useQuizData } from "@utils/hooks/useQuizData";
const TextField = MuiTextField as unknown as FC;
@@ -135,11 +135,9 @@ const VariantItem = ({
index,
own = false,
}: VariantItemProps) => {
- const { settings } = useQuestionsStore()
+ const { settings } = useQuizData();
const theme = useTheme();
- if (!settings) throw new Error("settings is null");
-
return (
item !== variantId)
: [...currentAnswer, variantId],
qid: settings.qid
- })
+ });
updateAnswer(
currentQuestion.id,
@@ -205,7 +203,7 @@ const VariantItem = ({
);
} catch (e) {
- enqueueSnackbar("ответ не был засчитан")
+ enqueueSnackbar("ответ не был засчитан");
}
@@ -218,12 +216,12 @@ const VariantItem = ({
questionId: currentQuestion.id,
body: currentQuestion.content.variants[index].answer,
qid: settings.qid
- })
+ });
updateAnswer(currentQuestion.id, variantId);
} catch (e) {
- enqueueSnackbar("ответ не был засчитан")
+ enqueueSnackbar("ответ не был засчитан");
}
if (answer === variantId) {
@@ -233,10 +231,10 @@ const VariantItem = ({
questionId: currentQuestion.id,
body: "",
qid: settings.qid
- })
+ });
} catch (e) {
- enqueueSnackbar("ответ не был засчитан")
+ enqueueSnackbar("ответ не был засчитан");
}
deleteAnswer(currentQuestion.id);
}
diff --git a/src/pages/ViewPublicationPage/questions/Varimg.tsx b/src/pages/ViewPublicationPage/questions/Varimg.tsx
index 0a16837..ec8c79b 100644
--- a/src/pages/ViewPublicationPage/questions/Varimg.tsx
+++ b/src/pages/ViewPublicationPage/questions/Varimg.tsx
@@ -7,8 +7,6 @@ import {
useTheme,
useMediaQuery
} from "@mui/material";
-
-import { useQuestionsStore } from "@stores/quizData/store";
import { useQuizViewStore, updateAnswer, deleteAnswer } from "@stores/quizView/store";
import RadioCheck from "@ui_kit/RadioCheck";
@@ -19,13 +17,14 @@ import { enqueueSnackbar } from "notistack";
import { sendAnswer } from "@api/quizRelase";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import BlankImage from "@icons/BlankImage";
+import { useQuizData } from "@utils/hooks/useQuizData";
type VarimgProps = {
currentQuestion: QuizQuestionVarImg;
};
export const Varimg = ({ currentQuestion }: VarimgProps) => {
- const { settings } = useQuestionsStore();
+ const { settings } = useQuizData();
const { answers } = useQuizViewStore();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
@@ -38,8 +37,6 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
({ id }) => answer === id
);
- if (!settings) throw new Error("settings is null");
-
return (
{currentQuestion.title}
diff --git a/src/pages/ViewPublicationPage/questions/gag.png b/src/pages/ViewPublicationPage/questions/gag.png
deleted file mode 100644
index 5bb379f7a237fbc170956968171a7bbd6f7ac5ba..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 6050
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
OLk#t<>Xzc{!~X}8 = {
- picture: "image/*",
- video: "video/*",
- audio: "audio/*",
- document:
- ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf",
+const UPLOAD_FILE_TYPES_MAP: Record = {
+ picture: "image/*",
+ video: "video/*",
+ audio: "audio/*",
+ document:
+ ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf",
} as const;
interface Props {
- question: QuizQuestionFile;
+ question: QuizQuestionFile;
}
export default function File({ question }: Props) {
- const fileInputRef = useRef(null);
- const [file, setFile] = useState(null);
- const [acceptedType, setAcceptedType] = useState(
- UPLOAD_FILE_TYPES_MAP.picture
- );
+ const fileInputRef = useRef(null);
+ const [file, setFile] = useState(null);
+ const [acceptedType, setAcceptedType] = useState(
+ UPLOAD_FILE_TYPES_MAP.picture
+ );
- useEffect(() => {
- setAcceptedType(UPLOAD_FILE_TYPES_MAP[question.content.type]);
- }, [question.content.type]);
+ useEffect(() => {
+ setAcceptedType(UPLOAD_FILE_TYPES_MAP[question.content.type]);
+ }, [question.content.type]);
- function handleFileChange(event: ChangeEvent) {
- if (!event.target.files?.[0]) return setFile(null);
- setFile(event.target.files[0]);
- }
+ function handleFileChange(event: ChangeEvent) {
+ if (!event.target.files?.[0]) return setFile(null);
+ setFile(event.target.files[0]);
+ }
- return (
-
- {question.title}
-
- {file && Выбран файл: {file.name}}
-
- );
+ return (
+
+ {question.title}
+
+ {file && Выбран файл: {file.name}}
+
+ );
}
diff --git a/src/stores/quizData/actions.ts b/src/stores/quizData/actions.ts
deleted file mode 100644
index 17f826a..0000000
--- a/src/stores/quizData/actions.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
-import { useQuestionsStore } from "./store";
-import { QuizSettings } from "@model/settingsData";
-
-
-export const getQuestionById = (questionId: string | null): AnyTypedQuizQuestion | null => {
- if (questionId === null) return null;
-
- return useQuestionsStore.getState().items.find(q => q.id === questionId || q.content.id === questionId) || null;
-};
-
-export const setQuizData = (quizData: QuizSettings) => useQuestionsStore.setState(quizData);
diff --git a/src/stores/quizData/hooks.ts b/src/stores/quizData/hooks.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/src/stores/quizData/store.ts b/src/stores/quizData/store.ts
deleted file mode 100644
index 88f530b..0000000
--- a/src/stores/quizData/store.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { QuizSettings } from "@model/settingsData";
-import { create } from "zustand";
-import { devtools } from "zustand/middleware";
-
-
-type QuizDataStore = {
- settings: QuizSettings["settings"] | null;
- items: QuizSettings["items"];
- cnt: QuizSettings["cnt"];
- recentlyСompleted: boolean;
-};
-
-const initialState: QuizDataStore = {
- settings: null,
- items: [],
- cnt: 0,
- recentlyСompleted: false,
-};
-
-export const useQuestionsStore = create()(
- devtools(
- () => initialState,
- {
- name: "QuizDataStore",
- enabled: import.meta.env.DEV,
- trace: import.meta.env.DEV,
- }
- )
-);
diff --git a/src/utils/handleComponentError.ts b/src/utils/handleComponentError.ts
new file mode 100644
index 0000000..8d21fd7
--- /dev/null
+++ b/src/utils/handleComponentError.ts
@@ -0,0 +1,43 @@
+import { ErrorInfo } from "react";
+
+
+interface ComponentError {
+ timestamp: number;
+ message: string;
+ callStack: string | undefined;
+ componentStack: string | null | undefined;
+}
+
+export function handleComponentError(error: Error, info: ErrorInfo) {
+ const componentError: ComponentError = {
+ timestamp: Math.floor(Date.now() / 1000),
+ message: error.message,
+ callStack: error.stack,
+ componentStack: info.componentStack,
+ };
+
+ queueErrorRequest(componentError);
+}
+
+let errorsQueue: ComponentError[] = [];
+let timeoutId: ReturnType;
+
+function queueErrorRequest(error: ComponentError) {
+ errorsQueue.push(error);
+
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(() => {
+ sendErrorsToServer();
+ }, 1000);
+}
+
+async function sendErrorsToServer() {
+ // makeRequest({
+ // url: "",
+ // method: "POST",
+ // body: errorsQueue,
+ // useToken: true,
+ // });
+ console.log(`Fake-sending ${errorsQueue.length} errors to server`, errorsQueue);
+ errorsQueue = [];
+}
diff --git a/src/utils/hooks/useGetSettings.ts b/src/utils/hooks/useGetSettings.ts
deleted file mode 100644
index 822cd40..0000000
--- a/src/utils/hooks/useGetSettings.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { useEffect, useLayoutEffect, useRef, useState } from "react"
-import { useQuestionsStore } from "@stores/quizData/store";
-
-import { getData } from "@api/quizRelase"
-
-interface SettingsGetter {
- quizId: string
-}
-
-export function useGetSettings(quizId: string) {
-
- const [fetchState, setFetchState] = useState<"fetching" | "idle" | "all fetched">("idle")
-
- useEffect(() => {
- async function get() {
- const data = await getData(quizId)
- //@ts-ignore
- const settings = data.settings
- const parseData = {
- settings: {
- fp: settings.fp,
- rep: settings.rep,
- name: settings.name,
- cfg: JSON.parse(settings?.cfg),
- lim: settings.lim,
- due: settings.due,
- delay: settings.delay,
- pausable: settings.pausable
- },
- //@ts-ignore
- items: data.items.map((item) => {
- const content = JSON.parse(item.c)
- return {
- description: item.desc,
- id: item.id,
- page: item.p,
- required: item.req,
- title: item.title,
- type: item.typ,
- content
- }
- }),
- //@ts-ignore
- cnt: data.cnt
- }
- //@ts-ignore
- useQuestionsStore.setState(parseData)
- }
- get()
- // const controller = new AbortController()
-
-
- }, [])
- return
- // return
-}
diff --git a/src/utils/hooks/useQuizData.ts b/src/utils/hooks/useQuizData.ts
new file mode 100644
index 0000000..1e180c7
--- /dev/null
+++ b/src/utils/hooks/useQuizData.ts
@@ -0,0 +1,34 @@
+import { getData } from "@api/quizRelase";
+import { parseQuizData } from "@model/api/getQuizData";
+import { QuizSettings } from "@model/settingsData";
+import { enqueueSnackbar } from "notistack";
+import useSWR from "swr";
+import { useQuizId } from "../../contexts/QuizIdContext";
+import { replaceSpacesToEmptyLines } from "../../pages/ViewPublicationPage/tools/replaceSpacesToEmptyLines";
+
+
+export function useQuizData() {
+ const quizId = useQuizId();
+ const { data } = useSWR(["quizData", quizId], params => getQuizData(params[1]), {
+ suspense: true,
+ });
+
+ return data;
+}
+
+async function getQuizData(quizId: string) {
+ const response = await getData(quizId);
+ const quizDataResponse = response.data;
+
+ if (response.error) {
+ enqueueSnackbar(response.error);
+ throw new Error(response.error);
+ }
+ if (!quizDataResponse) {
+ throw new Error("Quiz not found");
+ }
+
+ const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse, quizId));
+
+ return JSON.parse(JSON.stringify({ data: quizSettings }).replaceAll(/\\" \\"/g, '""').replaceAll(/" "/g, '""')).data as QuizSettings;
+}
diff --git a/yarn.lock b/yarn.lock
index e1e30ce..ef80ce4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2714,6 +2714,13 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-error-boundary@^4.0.12:
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.12.tgz#59f8f1dbc53bbbb34fc384c8db7cf4082cb63e2c"
+ integrity sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"