diff --git a/src/assets/icons/NameplateLogoFQ.tsx b/src/assets/icons/NameplateLogoFQ.tsx new file mode 100644 index 00000000..db350ab5 --- /dev/null +++ b/src/assets/icons/NameplateLogoFQ.tsx @@ -0,0 +1,23 @@ +import { FC, SVGProps } from "react"; + +export const NameplateLogoFQ: FC> = (props) => ( + + + + + + + + + + + + + + + + + + + +); diff --git a/src/constants/result.ts b/src/constants/result.ts index b9f40159..1e1d5c35 100644 --- a/src/constants/result.ts +++ b/src/constants/result.ts @@ -12,6 +12,7 @@ export const QUIZ_QUESTION_RESULT: Omit innerName: "", text: "", price: [0], - useImage: true + useImage: true, + usage: true }, }; diff --git a/src/model/questionTypes/result.ts b/src/model/questionTypes/result.ts index 7636bd36..0437b2ce 100644 --- a/src/model/questionTypes/result.ts +++ b/src/model/questionTypes/result.ts @@ -18,5 +18,6 @@ export interface QuizQuestionResult extends QuizQuestionBase { rule: QuestionBranchingRule, hint: QuestionHint; autofill: boolean; + usage: boolean }; } diff --git a/src/pages/Landing/HeaderLanding.tsx b/src/pages/Landing/HeaderLanding.tsx index 95105a06..94444268 100644 --- a/src/pages/Landing/HeaderLanding.tsx +++ b/src/pages/Landing/HeaderLanding.tsx @@ -66,7 +66,7 @@ export default function Component() { {/**/} - - ); }; diff --git a/src/pages/ResultPage/ResultPage.tsx b/src/pages/ResultPage/ResultPage.tsx index 06eb39bb..913fe71a 100644 --- a/src/pages/ResultPage/ResultPage.tsx +++ b/src/pages/ResultPage/ResultPage.tsx @@ -1,15 +1,43 @@ -import { useQuestionsStore } from "@root/questions/store"; import { FirstEntry } from "./FirstEntry" import { ResultSettings } from "./ResultSettings" +import { decrementCurrentStep, incrementCurrentStep } from "@root/quizes/actions"; +import { Box, Button } from "@mui/material"; +import ArrowLeft from "@icons/questionsPage/arrowLeft" export const ResultPage = () => { - const { questions } = useQuestionsStore(); - //ищём хотя бы один result - const haveResult = questions.some((question) => question.type === "result") return ( - haveResult ? - - : + <> - ); + + + + + + + + ) } \ No newline at end of file diff --git a/src/pages/ResultPage/ResultSettings.tsx b/src/pages/ResultPage/ResultSettings.tsx index e912f0d8..157f424d 100644 --- a/src/pages/ResultPage/ResultSettings.tsx +++ b/src/pages/ResultPage/ResultSettings.tsx @@ -14,7 +14,7 @@ import { ResultCard, checkEmptyData } from "./cards/ResultCard"; import { EmailSettingsCard } from "./cards/EmailSettingsCard"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { useQuestionsStore } from "@root/questions/store"; -import { createFrontResult, deleteQuestion } from "@root/questions/actions"; +import { deleteQuestion } from "@root/questions/actions"; import { QuizQuestionResult } from "@model/questionTypes/result"; export const ResultSettings = () => { @@ -25,6 +25,8 @@ export const ResultSettings = () => { const [resultContract, setResultContract] = useState(true); const isReadyToLeaveRef = useRef(true); + console.log(quiz) + console.log(results) useEffect( function calcIsReadyToLeave() { let isReadyToLeave = true; diff --git a/src/pages/ViewPublicationPage/ContactForm.tsx b/src/pages/ViewPublicationPage/ContactForm.tsx index ddef90fd..728c7ba5 100644 --- a/src/pages/ViewPublicationPage/ContactForm.tsx +++ b/src/pages/ViewPublicationPage/ContactForm.tsx @@ -6,6 +6,7 @@ import TextIcon from "@icons/ContactFormIcon/TextIcon"; import AddressIcon from "@icons/ContactFormIcon/AddressIcon"; import { useCurrentQuiz } from "@root/quizes/hooks"; +import { NameplateLogo } from "@icons/NameplateLogo"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; import { useState } from "react"; import { useQuestionsStore } from "@root/questions/store"; @@ -71,19 +72,19 @@ export const ContactForm = ({ }} > {quiz?.config.formContact.title || "Заполните форму, чтобы получить результаты теста"} - + { quiz?.config.formContact.desc && - - {quiz?.config.formContact.desc} - + + {quiz?.config.formContact.desc} + } @@ -138,6 +139,16 @@ export const ContactForm = ({ + + + Сделано на PenaQuiz + @@ -154,14 +165,14 @@ const Inputs = () => { if (FC.used) someUsed.push() return }) - + if (someUsed.length) { return <>{someUsed} } else { return <> - {Icons[0]} - {Icons[1]} - {Icons[2]} + {Icons[0]} + {Icons[1]} + {Icons[2]} } } diff --git a/src/pages/ViewPublicationPage/Footer.tsx b/src/pages/ViewPublicationPage/Footer.tsx index e6ccf759..8366771a 100644 --- a/src/pages/ViewPublicationPage/Footer.tsx +++ b/src/pages/ViewPublicationPage/Footer.tsx @@ -8,7 +8,7 @@ import { useQuestionsStore } from "@root/questions/store"; import type { AnyTypedQuizQuestion, QuizQuestionBase } from "../../model/questionTypes/shared"; import { getQuestionByContentId } from "@root/questions/actions"; import { enqueueSnackbar } from "notistack"; -import { NameplateLogo } from "@icons/NameplateLogo"; +import { NameplateLogoFQ } from "@icons/NameplateLogoFQ"; type FooterProps = { setCurrentQuestion: (step: AnyTypedQuizQuestion) => void; @@ -189,22 +189,11 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh position: "relative", padding: "15px 0", borderTop: `1px solid ${theme.palette.grey[400]}`, + height: '75px', + + display: "flex" }} > - - - Сделано на PenaQuiz - + { QUESTIONS_MAP[currentQuestion.type as Exclude]; return ( - + {!showContactForm && !showResultForm && ( { @@ -100,31 +101,59 @@ export const ResultForm = ({ - { - quiz?.config.resultInfo.when === "before" && + - + + Сделано на PenaQuiz + + - } + + { + quiz?.config.resultInfo.when === "before" && + <> + + + + + } + + + ); }; diff --git a/src/pages/startPage/EditPage.tsx b/src/pages/startPage/EditPage.tsx index 636ed4ad..02de534d 100755 --- a/src/pages/startPage/EditPage.tsx +++ b/src/pages/startPage/EditPage.tsx @@ -32,7 +32,7 @@ import { Link, useNavigate } from "react-router-dom"; import useSWR from "swr"; import { useDebouncedCallback } from "use-debounce"; import { SidebarMobile } from "./Sidebar/SidebarMobile"; -import { cleanQuestions, setQuestions } from "@root/questions/actions"; +import { cleanQuestions, createResult, setQuestions } from "@root/questions/actions"; import { updateOpenBranchingPanel, updateCanCreatePublic, updateModalInfoWhyCantCreate } from "@root/uiTools/actions"; import { BranchingPanel } from "../Questions/BranchingPanel"; import { useQuestionsStore } from "@root/questions/store"; @@ -60,10 +60,14 @@ export default function EditPage() { const questions = await questionApi.getList({ quiz_id: editQuizId }); setQuestions(questions); + if (questions === null || !questions.find(q => q.type !== null && q.content?.rule.parentId === "line")) createResult(quiz?.backendId, "line") }; getData(); }, []); +console.log(quiz) +console.log(questions) + const { openBranchingPanel, whyCantCreatePublic, canCreatePublic } = useUiTools(); const theme = useTheme(); const navigate = useNavigate(); @@ -79,10 +83,12 @@ export default function EditPage() { }, [navigate, editQuizId]); useEffect( - () => () => { - resetEditConfig(); - cleanQuestions(); - updateModalInfoWhyCantCreate(false) + () => { + return () => { + resetEditConfig(); + cleanQuestions(); + updateModalInfoWhyCantCreate(false) + } }, [] ); @@ -124,7 +130,7 @@ export default function EditPage() { useEffect(() => { updateQuestionHint(questions) }, [questions]); - + async function handleLogoutClick() { const [, logoutError] = await logout(); @@ -377,11 +383,11 @@ export default function EditPage() { height: "34px", minWidth: "130px", }} - onClick={() => Object.keys(whyCantCreatePublic).length === 0 ? () => {} : updateModalInfoWhyCantCreate(true)} + onClick={() => Object.keys(whyCantCreatePublic).length === 0 ? () => { } : updateModalInfoWhyCantCreate(true)} > Тестовый просмотр - : + : - {quiz?.status === "start" && https://hbpn.link/{quiz.qid} - } - - + {quiz?.status === "start" ? "Стоп" : "Старт"} + + {quiz?.status === "start" && https://hbpn.link/{quiz.qid} + } + + ); diff --git a/src/stores/questions/actions.ts b/src/stores/questions/actions.ts index c59e00db..456f4566 100644 --- a/src/stores/questions/actions.ts +++ b/src/stores/questions/actions.ts @@ -15,6 +15,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks"; import { QuestionsStore, useQuestionsStore } from "./store"; import { useUiTools } from "../uiTools/store"; import { withErrorBoundary } from "react-error-boundary"; +import { QuizQuestionResult } from "@model/questionTypes/result"; export const setQuestions = (questions: RawQuestion[] | null) => setProducedState(state => { @@ -481,7 +482,12 @@ export const getQuestionByContentId = (questionContentId: string | null) => { export const clearRuleForAll = () => { const { questions } = useQuestionsStore.getState(); questions.forEach(question => { - if (question.type !== null && (question.content.rule.main.length > 0 || question.content.rule.default.length > 0 || question.content.rule.parentId.length > 0)) { + if (question.type !== null && + (question.content.rule.main.length > 0 + || question.content.rule.default.length > 0 + || question.content.rule.parentId.length > 0) + && question.type !== "result") { + updateQuestion(question.content.id, question => { question.content.rule.parentId = ""; question.content.rule.main = []; @@ -491,63 +497,48 @@ export const clearRuleForAll = () => { }); }; - -export const createFrontResult = (quizId: number, parentContentId?: string) => setProducedState(state => { - const frontId = nanoid(); - const content = JSON.parse(JSON.stringify(defaultQuestionByType["result"].content)); - content.id = frontId; - if (parentContentId) content.rule.parentId = parentContentId; - state.questions.push({ - id: frontId, - quizId, - type: "result", - title: "", - description: "", - deleted: false, - expanded: true, - page: 101, - required: true, - content - }); -}, { - type: "createFrontResult", - quizId, -}); - - -export const createBackResult = async ( - questionId: string, - type: QuestionType, +export const createResult = async ( + quizId: number, + parentContentId?: string ) => requestQueue.enqueue(async () => { - const question = useQuestionsStore.getState().questions.find(q => q.id === questionId); - if (!question) return; - if (question.type !== "result") throw new Error("Cannot upgrade already typed question"); - - try { - const createdQuestion = await questionApi.create({ - quiz_id: question.quizId, - type, - title: question.title, - description: question.description, - page: 0, - required: true, - content: JSON.stringify(defaultQuestionByType[type].content), - }); - - setProducedState(state => { - const questionIndex = state.questions.findIndex(q => q.id === questionId); - if (questionIndex !== -1) state.questions.splice( - questionIndex, - 1, - rawQuestionToQuestion(createdQuestion) - ); - }, { - type: "createBackResult", - question, - }); - } catch (error) { - devlog("Error creating question", error); - enqueueSnackbar("Не удалось создать вопрос"); + if (!quizId || !parentContentId) { + console.error("Нет данных для создания результата. quizId: ", quizId, ", quizId: ", parentContentId) } + + //Мы получили запрос на создание резулта. Анализируем существует ли такой. Если да - просто делаем его активным + const question = useQuestionsStore.getState().questions.find(q=> q.type !== null && q?.content.rule.parentContentId === parentContentId) + + if (question) {//существует, делаем активным + + updateQuestion(question.id, (q) => { + q.content.usage = true + }) + + } else {//не существует, создаём + const content = JSON.parse(JSON.stringify(defaultQuestionByType["result"].content)); + content.rule.parentId = parentContentId; + + try { + const createdQuestion:RawQuestion = await questionApi.create({ + quiz_id: quizId, + type: "result", + title: "", + description: "", + page: 101, + required: true, + content: JSON.stringify(content), + }); + + setProducedState(state => { + state.questions.push(rawQuestionToQuestion(createdQuestion)) + }, { + type: "createBackResult", + createdQuestion, + }); + } catch (error) { + devlog("Error creating question", error); + enqueueSnackbar("Не удалось создать вопрос"); + } + } }); diff --git a/src/stores/quizes/actions.ts b/src/stores/quizes/actions.ts index e0367bfd..fd718a1d 100644 --- a/src/stores/quizes/actions.ts +++ b/src/stores/quizes/actions.ts @@ -9,8 +9,9 @@ import { NavigateFunction } from "react-router-dom"; import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError"; import { RequestQueue } from "../../utils/requestQueue"; import { QuizStore, useQuizStore } from "./store"; -import { createUntypedQuestion } from "@root/questions/actions"; +import { createUntypedQuestion, updateQuestion } from "@root/questions/actions"; import { useCurrentQuiz } from "./hooks" +import { useQuestionsStore } from "@root/questions/store"; export const setEditQuizId = (quizId: number | null) => setProducedState(state => { @@ -176,12 +177,40 @@ export const deleteQuiz = async (quizId: string) => requestQueue.enqueue(async ( enqueueSnackbar(`Не удалось удалить квиз. ${message}`); } }); -export const updateRootContentId = (quizId: string, id:string) => updateQuiz( - quizId, - quiz => { - quiz.config.haveRoot = id - }, -); +export const updateRootContentId = (quizId: string, id: string) => { + + if (id.length === 0) {//дерева больше не существует, все результаты неактивны кроме результата линейности + useQuestionsStore.getState().questions.forEach((q) => { + if (q.type !== null && q.type === "result") { + if (q.content.rule.parentId === "line" && q.content.usage === false) { + updateQuestion(q.id, (q) => { + q.content.usage === true + }) + } else { + updateQuestion(q.id, (q) => { + q.content.usage === false + }) + } + } + }) + } else { //было создано дерево, результат линейности неактивен + useQuestionsStore.getState().questions.forEach((q) => { + if (q.type !== null && q.content.rule.parentId === "line") { + updateQuestion(q.id, (q) => { + q.content.usage === false + }) + } + + }) + } + + updateQuiz( + quizId, + quiz => { + quiz.config.haveRoot = id + }, + ); +} // TODO copy quiz