diff --git a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx index 2804a48..3c16969 100644 --- a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx +++ b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx @@ -1,3 +1,7 @@ +import { ContactForm } from "@/components/ViewPublicationPage/ContactForm/ContactForm.tsx"; +import { extractImageLinksFromQuestion } from "@/utils/extractImageLinks"; +import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics"; +import { useYandexMetrics } from "@/utils/hooks/metrics/useYandexMetrics"; import { sendAnswer } from "@api/quizRelase"; import { useQuizSettings } from "@contexts/QuizDataContext"; import { ThemeProvider, Typography } from "@mui/material"; @@ -7,15 +11,13 @@ import { notReachable } from "@utils/notReachable"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import { enqueueSnackbar } from "notistack"; import { ReactElement, useEffect } from "react"; +import { Helmet } from "react-helmet"; import { Question } from "./Question"; +import QuestionSelect from "./QuestionSelect"; import { ResultForm } from "./ResultForm"; import { StartPageViewPublication } from "./StartPageViewPublication"; import NextButton from "./tools/NextButton"; import PrevButton from "./tools/PrevButton"; -import QuestionSelect from "./QuestionSelect"; -import { useYandexMetrics } from "@/utils/hooks/metrics/useYandexMetrics"; -import { useVKMetrics } from "@/utils/hooks/metrics/useVKMetrics"; -import { ContactForm } from "@/components/ViewPublicationPage/ContactForm/ContactForm.tsx"; export default function ViewPublicationPage() { const { settings, recentlyCompleted, quizId, preview, changeFaviconAndTitle } = useQuizSettings(); @@ -24,6 +26,7 @@ export default function ViewPublicationPage() { const { currentQuestion, currentQuestionStepNumber, + nextQuestion, isNextButtonEnabled, isPreviousButtonEnabled, moveToPrevQuestion, @@ -56,7 +59,10 @@ export default function ViewPublicationPage() { if (!currentQuestion) return ( - + Вопрос не выбран @@ -80,7 +86,10 @@ export default function ViewPublicationPage() { currentQuestion={currentQuestion} currentQuestionStepNumber={currentQuestionStepNumber} prevButton={ - + } nextButton={ } - questionSelect={} + questionSelect={ + + } /> ); break; } case "contactform": { - quizStepElement = ; + quizStepElement = ( + + ); break; } default: notReachable(currentQuizStep); } + const preloadLinks = new Set([ + ...extractImageLinksFromQuestion(currentQuestion), + ...extractImageLinksFromQuestion(nextQuestion), + ]); + return ( - {quizStepElement} + + + {Array.from(preloadLinks).map((link) => ( + + ))} + + {quizStepElement} + ); } diff --git a/lib/utils/extractImageLinks.ts b/lib/utils/extractImageLinks.ts new file mode 100644 index 0000000..4799487 --- /dev/null +++ b/lib/utils/extractImageLinks.ts @@ -0,0 +1,29 @@ +import { AnyTypedQuizQuestion } from "@/model/questionTypes"; + +export function extractImageLinksFromQuestion(question: AnyTypedQuizQuestion | null | undefined): string[] { + if (!question) return []; + + const links: string[] = []; + + if (question.type === "images") { + question.content.variants.forEach((variant) => { + if (variant.extendedText.startsWith("https://")) links.push(variant.extendedText); + }); + } + + if (question.type === "varimg") { + question.content.variants.forEach((variant) => { + if (variant.extendedText.startsWith("https://")) links.push(variant.extendedText); + }); + } + + if (question.type === "page") { + if (question.content.back?.startsWith("https://")) links.push(question.content.back); + } + + if (question.type === "result") { + if (question.content.back?.startsWith("https://")) links.push(question.content.back); + } + + return links; +} diff --git a/lib/utils/hooks/useQuestionFlowControl.ts b/lib/utils/hooks/useQuestionFlowControl.ts index 4c94381..6a6393a 100644 --- a/lib/utils/hooks/useQuestionFlowControl.ts +++ b/lib/utils/hooks/useQuestionFlowControl.ts @@ -197,6 +197,7 @@ export function useQuestionFlowControl() { return { currentQuestion, currentQuestionStepNumber: linearQuestionIndex === null ? null : linearQuestionIndex + 1, + nextQuestion, isNextButtonEnabled, isPreviousButtonEnabled, moveToPrevQuestion, diff --git a/package.json b/package.json index ea59540..49315f4 100755 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@types/node": "^16.7.13", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "@types/react-helmet": "^6.1.11", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "@vitejs/plugin-react": "^4.2.1", @@ -95,6 +96,7 @@ "hex-rgb": "^5.0.0", "mobile-detect": "^1.4.5", "mui-tel-input": "^5.1.2", + "react-helmet": "^6.1.0", "react-imask": "^7.6.0", "react-phone-number-input": "^3.4.1" }, @@ -108,7 +110,8 @@ "endOfLine": "auto", "bracketSpacing": true, "arrowParens": "always", - "jsxSingleQuote": false + "jsxSingleQuote": false, + "singleAttributePerLine": true }, "lint-staged": { "*": "prettier --write --ignore-unknown" diff --git a/yarn.lock b/yarn.lock index 5451ba1..884c4d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -985,6 +985,13 @@ dependencies: "@types/react" "*" +"@types/react-helmet@^6.1.11": + version "6.1.11" + resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.11.tgz#8cafcafff38f75361f451563ba7b406b0c5d3907" + integrity sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g== + dependencies: + "@types/react" "*" + "@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.8": version "4.4.10" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" @@ -3213,7 +3220,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -3282,6 +3289,21 @@ react-error-boundary@^4.0.12: dependencies: "@babel/runtime" "^7.12.5" +react-fast-compare@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== + +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + react-imask@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/react-imask/-/react-imask-7.6.0.tgz#5948fc39e1d7d036292d4fade43df4636d43e7b7" @@ -3331,6 +3353,11 @@ react-router@6.23.1: dependencies: "@remix-run/router" "1.16.1" +react-side-effect@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a" + integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw== + react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"