diff --git a/index.html b/index.html index 9d7ae8b..1dbec75 100755 --- a/index.html +++ b/index.html @@ -120,6 +120,7 @@ e[i]=e[i]||function(){(e[i].a=e[i].a||[]).push(arguments)}, me=x.createElement(pe),me.async=1,me.src=r,nt=x.getElementsByTagName(pe)[0],nt.parentNode.insertBefore(me,nt)}) (window, document, 'script', 'https://abt.s3.yandex.net/expjs/latest/exp.js', 'ymab'); + ymab('metrika.95799066', 'setConfig', { enableJS: true, enableWatch: true }); ymab('metrika.95799066', 'init'/*, {clientFeatures}, {callback}*/); diff --git a/package-lock.json b/package-lock.json index b4afd0a..f5caf0c 100755 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,8 @@ "react-slick": "^0.30.2", "sass": "^1.77.6", "slick-carousel": "^1.8.1", - "unique-names-generator": "^4.7.1" + "unique-names-generator": "^4.7.1", + "yandex-metrica-ab-react": "^1.6.1" }, "devDependencies": { "@types/core-js": "^2.5.8", @@ -4964,6 +4965,15 @@ "node": ">= 6" } }, + "node_modules/yandex-metrica-ab-react": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yandex-metrica-ab-react/-/yandex-metrica-ab-react-1.6.1.tgz", + "integrity": "sha512-PES0h8lxE/4MgGkGjvaVyyf3axqiJ6/J857jI9N3GCK8+CA0QBLSwtWw4s7DKDUqYgJBPI0sBlhuplCFHWJRgQ==", + "peerDependencies": { + "react": ">=16", + "react-dom": ">16" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -8336,6 +8346,12 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, + "yandex-metrica-ab-react": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yandex-metrica-ab-react/-/yandex-metrica-ab-react-1.6.1.tgz", + "integrity": "sha512-PES0h8lxE/4MgGkGjvaVyyf3axqiJ6/J857jI9N3GCK8+CA0QBLSwtWw4s7DKDUqYgJBPI0sBlhuplCFHWJRgQ==", + "requires": {} + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 15f562d..ff002c6 100755 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "react-slick": "^0.30.2", "sass": "^1.77.6", "slick-carousel": "^1.8.1", - "unique-names-generator": "^4.7.1" + "unique-names-generator": "^4.7.1", + "yandex-metrica-ab-react": "^1.6.1" }, "devDependencies": { "@types/core-js": "^2.5.8", diff --git a/public/new-york-times.png b/public/new-york-times.png new file mode 100644 index 0000000..6f36522 Binary files /dev/null and b/public/new-york-times.png differ diff --git a/public/partnersWithoutNewYorkTime.png b/public/partnersWithoutNewYorkTime.png new file mode 100644 index 0000000..442c297 Binary files /dev/null and b/public/partnersWithoutNewYorkTime.png differ diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index 2368625..66ecc94 100755 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -169,6 +169,7 @@ function App(): JSX.Element { } else if (location.pathname.includes("v1/trial-payment")) { metricService.reachGoal(EGoals.AURA_TRIAL_PAYMENT_PAGE_VISIT, true) } + // metricService.initMetricAB() metricService.hit() }, [location]); diff --git a/src/components/pages/ABDesign/v1/components/Questionnaire/index.tsx b/src/components/pages/ABDesign/v1/components/Questionnaire/index.tsx index b6b9ce1..ceee7f6 100644 --- a/src/components/pages/ABDesign/v1/components/Questionnaire/index.tsx +++ b/src/components/pages/ABDesign/v1/components/Questionnaire/index.tsx @@ -14,6 +14,7 @@ import { stepsQuestionary } from "../../data/stepsQuestionary"; import Answer from "../../ui/Answer"; import Stepper from "../Stepper"; import { useLottie } from "@/hooks/lottie/useLottie"; +import {useMetricABFlags} from "@/services/metric/metricService.ts"; function QuestionnairePage(): JSX.Element { const { question, stepId } = useParams(); @@ -29,10 +30,13 @@ function QuestionnairePage(): JSX.Element { }); const { gender } = useSelector(selectors.selectQuestionnaire); const clickAnswerTimeOutRef = useRef(); + const { flags } = useMetricABFlags(); + const aboutUsAnswersKey = flags?.aboutUsAnswers?.[0] useLottie({ preloadKey: currentQuestion?.lottie?.preloadKey, }); + useEffect(() => { const currentStepIndex = steps.findIndex((item) => item.id === stepId); if (currentStepIndex === -1) return navigate(routes.client.notFound()); @@ -83,7 +87,7 @@ function QuestionnairePage(): JSX.Element { currentStepIndex >= steps.length - 1 && questionIndex >= questionsLength - 1 ) { - return navigate(routes.client.aboutUsV1()); + return navigate(routes.client.aboutUsV1(aboutUsAnswersKey)); } if (questionIndex < questionsLength - 1) { diff --git a/src/components/pages/ABDesign/v1/pages/AboutUs/index.tsx b/src/components/pages/ABDesign/v1/pages/AboutUs/index.tsx index 0bf141e..8d17dad 100644 --- a/src/components/pages/ABDesign/v1/pages/AboutUs/index.tsx +++ b/src/components/pages/ABDesign/v1/pages/AboutUs/index.tsx @@ -3,7 +3,7 @@ import styles from "./styles.module.css"; import Title from "@/components/Title"; import { useDispatch, useSelector } from "react-redux"; import { actions, selectors } from "@/store"; -import { useNavigate } from "react-router-dom"; +import {useNavigate, useSearchParams} from "react-router-dom"; import routes from "@/routes"; import Header from "../../components/Header"; import Answer from "../../ui/Answer"; @@ -15,6 +15,8 @@ function AboutUsPage() { const { gender } = useSelector(selectors.selectQuestionnaire); const [selectedAnswer, setSelectedAnswer] = useState(null); const clickAnswerTimeOutRef = useRef(); + const [searchParams] = useSearchParams() + const aboutUsAnswersKey = searchParams.get('key') ?? "aboutUsAnswersNormal" const handleClick = async (answer: IAnswer) => { setSelectedAnswer(answer); @@ -43,7 +45,7 @@ function AboutUsPage() {
- {aboutUsAnswers.map((answer, index) => ( + {aboutUsAnswers[aboutUsAnswersKey].map((answer, index) => ( { navigate(-1); }; const handleNext = () => { - navigate(routes.client.aboutUsV1()); + navigate(routes.client.aboutUsV1(aboutUsAnswersKey)); }; return ( diff --git a/src/components/pages/ABDesign/v1/pages/Gender/index.tsx b/src/components/pages/ABDesign/v1/pages/Gender/index.tsx index f46acf4..e7c1041 100644 --- a/src/components/pages/ABDesign/v1/pages/Gender/index.tsx +++ b/src/components/pages/ABDesign/v1/pages/Gender/index.tsx @@ -14,6 +14,7 @@ import { genders } from "../../data/genders"; import PrivacyPolicy from "../../components/PrivacyPolicy"; import Toast from "../../components/Toast"; import { DotLottieReact } from "@lottiefiles/dotlottie-react"; +import { useMetricABFlags } from "@/services/metric/metricService"; interface IGenderPageProps { productKey?: EProductKeys; @@ -29,12 +30,18 @@ function GenderPage({ productKey }: IGenderPageProps): JSX.Element { const { checked: privacyPolicyChecked } = useSelector( selectors.selectPrivacyPolicy ); + const { flags } = useMetricABFlags(); + const isNextPageMentioned = flags?.isNextPageMentioned?.[0] useEffect(() => { const feature = location.pathname.replace("/v1/gender/", ""); const isShowTryApp = targetId === "i"; dispatch(actions.userConfig.addIsShowTryApp(isShowTryApp)); - dispatch(actions.userConfig.setFeature(feature.includes("/v1/gender") ? "" : feature)); + dispatch( + actions.userConfig.setFeature( + feature.includes("/v1/gender") ? "" : feature + ) + ); }, [dispatch, location.pathname, targetId]); useEffect(() => { @@ -54,7 +61,10 @@ function GenderPage({ productKey }: IGenderPageProps): JSX.Element { if (productKey === EProductKeys["chat.aura"]) { return navigate(routes.client.advisorChatBirthdate()); } - navigate(`/v1/questionnaire/profile/flowChoice`); + if (isNextPageMentioned === "true") { + return navigate(routes.client.mentionedInV1()); + } + return navigate(`/v1/questionnaire/profile/flowChoice`); }; const selectGender = async (gender: Gender) => { diff --git a/src/components/pages/ABDesign/v1/pages/MentionedIn/index.tsx b/src/components/pages/ABDesign/v1/pages/MentionedIn/index.tsx new file mode 100644 index 0000000..96724c4 --- /dev/null +++ b/src/components/pages/ABDesign/v1/pages/MentionedIn/index.tsx @@ -0,0 +1,100 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; +import { useNavigate } from "react-router-dom"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import Header from "../../components/Header"; +import { useDynamicSize } from "@/hooks/useDynamicSize"; +import BackgroundTopBlob from "../../ui/BackgroundTopBlob"; +import QuestionnaireGreenButton from "../../ui/GreenButton"; +import { useTranslation } from "react-i18next"; + +function MentionedInPage() { + const navigate = useNavigate(); + const { t } = useTranslation(); + const { width: pageWidth, elementRef } = useDynamicSize({ + defaultWidth: 393, + }); + const { gender } = useSelector(selectors.selectQuestionnaire); + + const handleNext = () => { + return navigate(`/v1/questionnaire/profile/flowChoice`); + }; + + const getBackgroundColor = () => { + return gender === "male" ? "#C1E5FF" : "#f7ebff"; + }; + + return ( +
+ +
+ + + 42+ million people + + + already use AURA + + +
+ + quotes + + + + +

+ AURA aims to illuminate interpersonal connections using astrological + signs +

+ +
+ + + MENTIONED IN + + +
+ + {t("next")} + +

1123 Rimer Dr Moraga, California 94556

+
+
+ ); +} + +export default MentionedInPage; diff --git a/src/components/pages/ABDesign/v1/pages/MentionedIn/styles.module.css b/src/components/pages/ABDesign/v1/pages/MentionedIn/styles.module.css new file mode 100644 index 0000000..fd898fe --- /dev/null +++ b/src/components/pages/ABDesign/v1/pages/MentionedIn/styles.module.css @@ -0,0 +1,100 @@ +.page { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + min-height: 100dvh; + max-width: 460px; + padding: 20px 24px; + color: #2c2c2c; + overflow: initial; +} + +.background-top-blob { + position: absolute; + top: -40px; + left: 0; +} + +.header { + z-index: 1; +} + +.title { + font-size: 28px; + font-weight: 600; + margin: 0; + margin-top: 40px; + z-index: 1; + line-height: 125%; + color: #0cc3ac; +} + +.sub-title { + font-size: 16px; + font-weight: 400; + line-height: 24px; + color: rgb(32, 31, 31); +} + +.quote-container { + display: flex; + flex-direction: column; + -webkit-box-align: center; + align-items: center; + background: rgb(251, 251, 255); + border-radius: 12px; + padding: 24px 21px 28px; + width: 100%; + margin-bottom: 24px; +} + +.quote { + color: #0cc3ac; +} + +.quote-container p { + width: 100%; + margin-top: 8px; + margin-bottom: 28px; + font-size: 16px; + font-weight: 600; + line-height: 24px; + text-align: center; + color: rgb(15, 15, 15); +} + +.quote-img { + max-width: 134px; + width: 100%; +} + +.text-h3 { + font-size: 12px; + font-weight: 600; + line-height: 18px; + color: rgb(32, 31, 31); + margin-bottom: 16px; +} + +.full { + width: 100%; +} + +.buttons-container { + position: sticky; + bottom: 0; + margin-top: 10px; + padding-top: 10px; + width: 100%; +} + +.address { + margin-top: 12px; + margin-bottom: 8px; + text-align: center; + color: gray; + font-size: 12px; + margin-bottom: 16px; + text-transform: uppercase; +} \ No newline at end of file diff --git a/src/components/pages/ABDesign/v1/pages/WithHead/index.tsx b/src/components/pages/ABDesign/v1/pages/WithHead/index.tsx index 6f070e7..44fcf97 100644 --- a/src/components/pages/ABDesign/v1/pages/WithHead/index.tsx +++ b/src/components/pages/ABDesign/v1/pages/WithHead/index.tsx @@ -11,13 +11,15 @@ import BackgroundTopBlob from "../../ui/BackgroundTopBlob"; import Header from "../../components/Header"; import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie"; import { DotLottieReact } from "@lottiefiles/dotlottie-react"; +import {useMetricABFlags} from "@/services/metric/metricService.ts"; function WithHeadPage() { const navigate = useNavigate(); const birthdate = useSelector(selectors.selectBirthdate); const zodiacSign = getZodiacSignByDate(birthdate); const { width: pageWidth, elementRef: pageRef } = useDynamicSize({}); - + const { flags } = useMetricABFlags(); + const aboutUsAnswersKey = flags?.aboutUsAnswers?.[0] const { animationData } = useLottie({ loadKey: ELottieKeys.scalesHead, }); @@ -27,7 +29,7 @@ function WithHeadPage() { }; const handleNext = () => { - navigate(routes.client.aboutUsV1()); + navigate(routes.client.aboutUsV1(aboutUsAnswersKey)); }; return ( diff --git a/src/components/pages/ABDesign/v1/pages/WithHeart/index.tsx b/src/components/pages/ABDesign/v1/pages/WithHeart/index.tsx index 250fb47..29c85e6 100644 --- a/src/components/pages/ABDesign/v1/pages/WithHeart/index.tsx +++ b/src/components/pages/ABDesign/v1/pages/WithHeart/index.tsx @@ -11,13 +11,15 @@ import BackgroundTopBlob from "../../ui/BackgroundTopBlob"; import Header from "../../components/Header"; import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie"; import { DotLottieReact } from "@lottiefiles/dotlottie-react"; +import {useMetricABFlags} from "@/services/metric/metricService.ts"; function WithHeartPage() { const navigate = useNavigate(); const birthdate = useSelector(selectors.selectBirthdate); const zodiacSign = getZodiacSignByDate(birthdate); const { width: pageWidth, elementRef: pageRef } = useDynamicSize({}); - + const { flags } = useMetricABFlags(); + const aboutUsAnswersKey = flags?.aboutUsAnswers?.[0] const { animationData } = useLottie({ loadKey: ELottieKeys.scalesHeart, }); @@ -27,7 +29,7 @@ function WithHeartPage() { }; const handleNext = () => { - navigate(routes.client.aboutUsV1()); + navigate(routes.client.aboutUsV1(aboutUsAnswersKey)); }; return ( diff --git a/src/components/pages/AboutUs/index.tsx b/src/components/pages/AboutUs/index.tsx index 0a4b069..85ea36c 100755 --- a/src/components/pages/AboutUs/index.tsx +++ b/src/components/pages/AboutUs/index.tsx @@ -27,7 +27,7 @@ function AboutUsPage() {
- {aboutUsAnswers.map((answer, index) => ( + {aboutUsAnswers['aboutUsAnswersNormal'].map((answer, index) => ( { }; metricService.initMetric(); + // metricService.initMetricAB(); if (isProduction) { smartLook(); diff --git a/src/routerComponents/ABDesign/v1/index.tsx b/src/routerComponents/ABDesign/v1/index.tsx index c3fb657..b940f70 100644 --- a/src/routerComponents/ABDesign/v1/index.tsx +++ b/src/routerComponents/ABDesign/v1/index.tsx @@ -32,6 +32,7 @@ import TrialChoicePage from "@/components/pages/ABDesign/v1/pages/TrialChoice"; import TrialPaymentPage from "@/components/pages/ABDesign/v1/pages/TrialPayment"; import TrialPaymentWithDiscount from "@/components/pages/ABDesign/v1/pages/TrialPaymentWithDiscount"; import AdditionalDiscount from "@/components/pages/ABDesign/v1/pages/AdditionalDiscount"; +import MentionedInPage from "@/components/pages/ABDesign/v1/pages/MentionedIn"; function ABDesignV1Routes() { return ( @@ -144,6 +145,10 @@ function ABDesignV1Routes() { path={routes.client.additionalDiscountV1()} element={} /> + } + /> ); diff --git a/src/routes.ts b/src/routes.ts index 5552350..fdd76ee 100755 --- a/src/routes.ts +++ b/src/routes.ts @@ -1,13 +1,13 @@ import { EPlacementKeys } from "./api/resources/Paywall"; import type { UserStatus } from "./types"; -const environments = import.meta.env +const environments = import.meta.env; const host = ""; export const apiHost = environments.AURA_API_HOST; -const dApiHost = environments.AURA_DAPI_HOST -const dApiPrefix = environments.AURA_DAPI_PREFIX -const siteHost = environments.AURA_SITE_HOST +const dApiHost = environments.AURA_DAPI_HOST; +const dApiPrefix = environments.AURA_DAPI_PREFIX; +const siteHost = environments.AURA_SITE_HOST; const prefix = environments.AURA_PREFIX; const openAIHost = environments.AURA_OPEN_AI_HOST; const openAiPrefix = environments.AURA_OPEN_AI_PREFIX; @@ -155,15 +155,23 @@ const routes = { genderV1: () => [host, "v1", "gender"].join("/"), questionnaireV1: () => [host, "v1", "questionnaire"].join("/"), goalSetupV1: () => [host, "v1", "goal-setup"].join("/"), - aboutUsV1: () => [host, "v1", "about-us"].join("/"), + aboutUsV1: (key?: string) => { + if (key === undefined) { + return [host, "v1", "about-us"].join("/") + } else { + return [host, "v1", "about-us"].join("/") + `?key=${key}` + } + }, hyperPersonalizedAstrologyV1: () => [host, "v1", "hyper-personalized-astrology"].join("/"), singleZodiacInfoV1: () => [host, "v1", "single-zodiac-info"].join("/"), - relationshipZodiacInfoV1: () => [host, "v1", "relationship-zodiac-info"].join("/"), + relationshipZodiacInfoV1: () => + [host, "v1", "relationship-zodiac-info"].join("/"), noTimeV1: () => [host, "v1", "no-time"].join("/"), relationshipAlmostThereV1: () => [host, "v1", "relationship-almost-there"].join("/"), - loadingInRelationshipV1: () => [host, "v1", "loading-in-relationship"].join("/"), + loadingInRelationshipV1: () => + [host, "v1", "loading-in-relationship"].join("/"), problemsV1: () => [host, "v1", "problems"].join("/"), worksRouterV1: () => [host, "v1", "works-router"].join("/"), worksForUsV1: () => [host, "v1", "works-for-us"].join("/"), @@ -173,7 +181,8 @@ const routes = { almostThereV1: () => [host, "v1", "almost-there"].join("/"), partnerRightPlaceV1: () => [host, "v1", "partner-right-place"].join("/"), partnerThingV1: () => [host, "v1", "partner-thing"].join("/"), - partnerTotallyNormalV1: () => [host, "v1", "partner-totally-normal"].join("/"), + partnerTotallyNormalV1: () => + [host, "v1", "partner-totally-normal"].join("/"), withHeartV1: () => [host, "v1", "with-heart"].join("/"), withHeadV1: () => [host, "v1", "with-head"].join("/"), bothV1: () => [host, "v1", "both"].join("/"), @@ -187,6 +196,7 @@ const routes = { trialPaymentWithDiscountV1: () => [host, "v1", "trial-payment-with-discount"].join("/"), additionalDiscountV1: () => [host, "v1", "additional-discount"].join("/"), + mentionedInV1: () => [host, "v1", "mentionedIn"].join("/"), loadingPage: () => [host, "loading-page"].join("/"), notFound: () => [host, "404"].join("/"), @@ -271,17 +281,14 @@ const routes = { [dApiHost, dApiPrefix, "placement", placementKey, "paywall"].join("/"), // Payment - makePayment: () => - [dApiHost, dApiPrefix, "payment", "checkout"].join("/"), + makePayment: () => [dApiHost, dApiPrefix, "payment", "checkout"].join("/"), // User videos - getUserVideos: () => - [dApiHost, "users", "videos", "combined"].join("/"), + getUserVideos: () => [dApiHost, "users", "videos", "combined"].join("/"), // User videos getUserPDFCompatibility: () => [dApiHost, "users", "pdf", "compatibility"].join("/"), - }, openAi: { createThread: () => [openAIHost, openAiPrefix, "threads"].join("/"), @@ -517,4 +524,4 @@ export const getRouteBy = (status: UserStatus): string => { } }; -export default routes; \ No newline at end of file +export default routes; diff --git a/src/services/metric/metricService.ts b/src/services/metric/metricService.ts index 729bb7a..e7e0420 100644 --- a/src/services/metric/metricService.ts +++ b/src/services/metric/metricService.ts @@ -1,3 +1,5 @@ +import { useExperiments } from "yandex-metrica-ab-react"; + export enum EGoals { ENTERED_EMAIL = "EnteredEmail", PAYMENT_SUCCESS = "PaymentSuccess", @@ -15,6 +17,11 @@ export enum EGoals { AURA_TRIAL_PAYMENT_PAGE_VISIT = "AuraTrialPaymentPageVisit" } +export enum EFlags { + isNextPageMentioned = 'Go to page mentionedIn', + aboutUsAnswers = 'Key for aboutUsAnswers' +} + interface IUserParams { UserID: number | string; genderFrom: string; @@ -33,6 +40,14 @@ const checkIsAvailableYandexMetric = () => { return true } +const checkIsAvailableYandexMetricAB = () => { + if (typeof window.ymab !== "function") { + console.error("Yandex.Metric not found") + return false + } + return true +} + const setUserID = (userId: string) => { if (!checkIsAvailableYandexMetric()) return; window.ym(metricCounterNumber, "setUserID", userId) @@ -94,4 +109,21 @@ const initMetric = () => { // eslint-disable-next-line react-hooks/exhaustive-deps } -export default { setUserID, userParams, reachGoal, hit, initMetric } \ No newline at end of file +const initMetricAB = () => { + if (!checkIsAvailableYandexMetricAB()) return; + + + window.ymab(`metrika.${metricCounterNumber}`, 'setConfig', { enableJS: true, enableWatch: true }); + window.ymab(`metrika.${metricCounterNumber}`, 'init'/*, {clientFeatures}, {callback}*/); + console.log("Metric initialized"); + + // eslint-disable-next-line react-hooks/exhaustive-deps +} + +export const useMetricABFlags = () => { + return useExperiments({ + clientId: `metrika.${metricCounterNumber}` + }) +} + +export default { setUserID, userParams, reachGoal, hit, initMetric, initMetricAB } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index fa1ecd6..fc4183c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,6 +27,7 @@ declare global { interface Window { // eslint-disable-next-line @typescript-eslint/no-explicit-any ym: any; + ymab: any; // eslint-disable-next-line @typescript-eslint/no-explicit-any klaviyo: any; }