diff --git a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx index 5756519..b7cd666 100644 --- a/lib/components/ViewPublicationPage/ViewPublicationPage.tsx +++ b/lib/components/ViewPublicationPage/ViewPublicationPage.tsx @@ -15,6 +15,7 @@ import NextButton from "./tools/NextButton"; import PrevButton from "./tools/PrevButton"; import QuestionSelect from "./QuestionSelect"; import { useYandexMetrics } from "@/utils/hooks/useYandexMetrics"; +import { useVKMetrics } from "@/utils/hooks/useVKMetrics"; export default function ViewPublicationPage() { const { @@ -37,6 +38,7 @@ export default function ViewPublicationPage() { setQuestion, } = useQuestionFlowControl(); useYandexMetrics(settings?.cfg?.yandexMetricNumber); + useVKMetrics(settings?.cfg?.vkMetricNumber); const isAnswer = answers.some( (ans) => ans.questionId === currentQuestion?.id diff --git a/lib/components/ViewPublicationPage/questions/Date.tsx b/lib/components/ViewPublicationPage/questions/Date.tsx index e355738..3517d45 100644 --- a/lib/components/ViewPublicationPage/questions/Date.tsx +++ b/lib/components/ViewPublicationPage/questions/Date.tsx @@ -13,104 +13,104 @@ import { useState } from "react"; import { useQuizViewStore } from "@/stores/quizView"; type DateProps = { - currentQuestion: QuizQuestionDate; + currentQuestion: QuizQuestionDate; }; export const Date = ({ currentQuestion }: DateProps) => { - const theme = useTheme(); - const { settings, quizId, preview } = useQuizData(); - const answers = useQuizViewStore(state => state.answers); - const updateAnswer = useQuizViewStore(state => state.updateAnswer); - const answer = answers.find( - ({ questionId }) => questionId === currentQuestion.id - )?.answer as string; - const currentAnswer = moment(answer) || moment(); - const [isSending, setIsSending] = useState(false); + const theme = useTheme(); + const { settings, quizId, preview } = useQuizData(); + const answers = useQuizViewStore((state) => state.answers); + const updateAnswer = useQuizViewStore((state) => state.updateAnswer); + const answer = answers.find( + ({ questionId }) => questionId === currentQuestion.id + )?.answer as string; + const currentAnswer = moment(answer) || moment(); + const [isSending, setIsSending] = useState(false); - return ( - - - {currentQuestion.title} - - + + {currentQuestion.title} + + + ( + - ( - - ), - }} - value={currentAnswer} - onChange={async (date) => { - if (isSending || !date) return; + /> + ), + }} + value={currentAnswer} + onChange={async (date) => { + if (isSending || !date) return; - setIsSending(true); - try { - await sendAnswer({ - questionId: currentQuestion.id, - body: moment(date).format("YYYY.MM.DD"), - qid: quizId, - preview - }); + setIsSending(true); + try { + await sendAnswer({ + questionId: currentQuestion.id, + body: moment(date).format("YYYY.MM.DD"), + qid: quizId, + preview, + }); - updateAnswer(currentQuestion.id, date, 0); - } catch (e) { - enqueueSnackbar("ответ не был засчитан"); - } + updateAnswer(currentQuestion.id, date, 0); + } catch (e) { + enqueueSnackbar("ответ не был засчитан"); + } - setIsSending(false); - }} - slotProps={{ - openPickerButton: { - sx: { - p: 0, - }, - "data-cy": "open-datepicker", - }, - layout: { - sx: { backgroundColor: theme.palette.background.default }, - }, - }} - sx={{ - "& .MuiInputBase-root": { - backgroundColor: settings.cfg.design - ? quizThemes[settings.cfg.theme].isLight - ? "#F2F3F7" - : "rgba(154,154,175, 0.2)" - : quizThemes[settings.cfg.theme].isLight - ? "white" - : theme.palette.background.default, - borderRadius: "10px", - maxWidth: "250px", - pr: "30px", - "& input": { - py: "11px", - pl: "20px", - lineHeight: "19px", - }, - "& fieldset": { - borderColor: "#9A9AAF", - }, - }, - }} - /> - - - ); + setIsSending(false); + }} + slotProps={{ + openPickerButton: { + sx: { + p: 0, + }, + "data-cy": "open-datepicker", + }, + layout: { + sx: { backgroundColor: theme.palette.background.default }, + }, + }} + sx={{ + "& .MuiInputBase-root": { + backgroundColor: settings.cfg.design + ? quizThemes[settings.cfg.theme].isLight + ? "#F2F3F7" + : "rgba(154,154,175, 0.2)" + : quizThemes[settings.cfg.theme].isLight + ? "white" + : theme.palette.background.default, + borderRadius: "10px", + maxWidth: "250px", + pr: "30px", + "& input": { + py: "11px", + pl: "20px", + lineHeight: "19px", + }, + "& fieldset": { + borderColor: "#9A9AAF", + }, + }, + }} + /> + + + ); }; diff --git a/lib/model/settingsData.ts b/lib/model/settingsData.ts index cc5e851..4a0985c 100644 --- a/lib/model/settingsData.ts +++ b/lib/model/settingsData.ts @@ -109,6 +109,7 @@ export interface QuizConfig { }; meta: string; yandexMetricNumber: number | undefined; + vkMetricNumber: number | undefined; } export type FormContactFieldName = diff --git a/lib/utils/hooks/useVKMetrics.ts b/lib/utils/hooks/useVKMetrics.ts new file mode 100644 index 0000000..bea48ee --- /dev/null +++ b/lib/utils/hooks/useVKMetrics.ts @@ -0,0 +1,30 @@ +import { useEffect } from "react"; + +export const useVKMetrics = (vkMetricNumber: number | undefined) => { + useEffect(() => { + if ( + vkMetricNumber && + typeof vkMetricNumber === "number" && + !Number.isNaN(vkMetricNumber) + ) { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.innerHTML = ` + var _tmr = window._tmr || (window._tmr = []); + _tmr.push({id: "${vkMetricNumber}", type: "pageView", start: (new Date()).getTime()}); + (function (d, w, id) { + if (d.getElementById(id)) return; + var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id; + ts.src = "https://top-fwz1.mail.ru/js/code.js"; + var f = function () {var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);}; + if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); } + })(document, window, "tmr-code"); + `; + document.body.appendChild(script); + + const noscript = document.createElement("noscript"); + noscript.innerHTML = `
Top.Mail.Ru
`; + document.body.appendChild(noscript); + } + }, [vkMetricNumber]); +}; diff --git a/lib/utils/hooks/useVkMetricGoals.ts b/lib/utils/hooks/useVkMetricGoals.ts new file mode 100644 index 0000000..41c3b89 --- /dev/null +++ b/lib/utils/hooks/useVkMetricGoals.ts @@ -0,0 +1,61 @@ +import { useEffect, useState } from "react"; + +type VkMetric = { + type: "reachGoal"; + id: number; + goal: string; +}; + +type ExtendedWindow = Window & { _tmp?: VkMetric[] }; + +type Messenger = + | "telegram" + | "viber" + | "whatsapp" + | "vkontakte" + | "messenger" + | "skype" + | "instagram"; + +const sendMetrics = (vkPixelId: number | undefined, goal: string) => { + if (vkPixelId) { + (window as ExtendedWindow)._tmp?.push({ + type: "reachGoal", + id: vkPixelId, + goal, + }); + } +}; + +export const useVkMetricGoals = (vkPixelId: number | undefined) => { + const [vkId, setVkId] = useState(undefined); + + useEffect(() => { + if (vkPixelId) { + setVkId(vkPixelId); + } + }, [vkPixelId]); + + return { + // Посетитель открыл квиз + quizOpened: () => sendMetrics(vkId, "penaquiz-start"), + // Посетитель нажал на кнопку стартовой страницы + firstPageOpened: () => sendMetrics(vkId, "penaquiz-startquiz"), + // Посетитель кликнул по номеру телефона на стартовой странице + phoneNumberOpened: () => sendMetrics(vkId, "penaquiz-phone"), + // Посетитель кликнул по email на стартовой странице + emailOpened: () => sendMetrics(vkId, "penaquiz-email"), + // Посетитель увидел определенный результат (id - айдишник вопроса с типом result) + resultShown: (resultId: string) => sendMetrics(vkId, `penaquiz-result-${resultId}`), + // Посетитель дошёл до формы контактов + contactsFormOpened: () => sendMetrics(vkId, "penaquiz-form"), + // Посетитель заполнил форму контактов + contactsFormFilled: () => sendMetrics(vkId, "penaquiz-contacts"), + // Посетитель отправил заявку с мессенджером + messengerRequestSended: (messenger: Messenger) => + sendMetrics(vkId, `marquiz-messengers-${messenger}`), + // Посетитель прошёл вопрос + questionPassed: (questionId: string) => + sendMetrics(vkId, `marquiz-step${questionId}`), + }; +}; diff --git a/lib/utils/hooks/useYandexMetrics.ts b/lib/utils/hooks/useYandexMetrics.ts index 6ff5e26..ba747a8 100644 --- a/lib/utils/hooks/useYandexMetrics.ts +++ b/lib/utils/hooks/useYandexMetrics.ts @@ -3,6 +3,7 @@ import { useEffect } from "react"; export const useYandexMetrics = (yandexMetricNumber: number | undefined) => { useEffect(() => { if ( + yandexMetricNumber && typeof yandexMetricNumber === "number" && !Number.isNaN(yandexMetricNumber) ) { @@ -22,6 +23,7 @@ export const useYandexMetrics = (yandexMetricNumber: number | undefined) => { webvisor:true }); `; + document.body.appendChild(script); const noscript = document.createElement("noscript");