AW-483-484-485-fix-bugs

This commit is contained in:
Daniil Chemerkin 2025-08-29 19:01:03 +00:00
parent 97abe06ef0
commit 5b6e743aaa
38 changed files with 1077 additions and 130 deletions

View File

@ -93,6 +93,19 @@
} }
} }
}, },
"/compatibility-test": {
"title": "Тест на Совместимость",
"subtitle": "Всё начинается с вас! Выберите ваш пол.",
"points": {
"point1": "Тест займмет не более 1 мин.",
"point2": "Ты получишь разбор совместимости.",
"point3": "Решишь проблемы в отношениях за месяц.",
"point4": "Сэкономишь сотни долларов на ненадёжных прогнозах.",
"point5": "Получишь персональный анализ."
},
"already_have_account": "Уже есть аккаунт? Войти",
"button": "Начать"
},
"/birthdate": { "/birthdate": {
"title": "When Were You Born?", "title": "When Were You Born?",
"text": "Your birth date can reveal strengths and values that may help you move forward" "text": "Your birth date can reveal strengths and values that may help you move forward"
@ -159,7 +172,71 @@
"answer1": "Single", "answer1": "Single",
"answer2": "In a Relationship", "answer2": "In a Relationship",
"answer3": "Married", "answer3": "Married",
"answer4": "Divorced" "answer4": "Divorced",
"v1": {
"title": "Чтобы яснее разобрать вашу суть, укажите какие у вас отношения сейчас?",
"answer1": "Single",
"answer2": "Начало",
"answer3": "Долгие отношения",
"answer4": "Развиваются непонятно куда",
"answer5": "Разрыв/кризис"
}
},
"/relationship-status-result": {
"start": {
"title": "How can you really tell if your partner is the right one—and avoid making a mistake?",
"text": "Understanding your partners emotions is the key to a harmonious relationship. Our system predicts compatibility with up to 98% accuracy, giving you clear, detailed reports."
},
"in_relationship": {
"title": "Love is important, but why isnt love alone enough for a happy, lasting relationship?",
"text": "Daily life can either strengthen your relationship or create tension if your ideas of comfort and care dont match. Our system predicts compatibility with up to 98% accuracy, helping you understand how long-lasting and harmonious your partnership can be."
},
"developing": {
"title": "Feel like your partner just doesnt get you? Its not by chance—its about differences in your natal patterns.",
"text": "Closeness isnt just about attraction—its about understanding each others wants and emotions. Our data from 2 million people backs this up, and we know how to help."
},
"crisis": {
"title": "Why do some couples split up quickly, while others stay together for years?",
"text": "A shared future isnt just about dreams—its about common goals, values, and everyday effort. Our system predicts compatibility with up to 98% accuracy. Well show you, step by step, how to build a strong relationship."
},
"single": {
"title": "Does it feel like there are no worthy partners out there, or you keep ending up with the wrong people? It all comes down to incompatible choices.",
"text": "Our system predicts compatibility with up to 98% accuracy, helping you find the right partner and opening up new possibilities in your personal life."
}
},
"/fear-in-relationship": {
"title": "Чего вы боитесь больше всего в отношениях?",
"answer1": "Потратить жизнь не на того",
"answer2": "Остаться одиноким",
"answer3": "Пропустить свою судьбу",
"answer4": "Любовь без уважения и поддержки",
"answer5": "Не узнать правду о совместимости"
},
"/important-step": {
"title": "Ты сделал важный шаг!",
"text": "Обозначил свой главный страх в отношениях. Это шаг к тому, чтобы больше не терять время. Мы поможем избежать все ошибки."
},
"/who-matter": {
"title": "О ком вы думаете, строя отношения?",
"answer1": "О себе",
"answer2": "О детях",
"answer3": "О семье"
},
"/your-priority": {
"title": "Что сейчас для вас в приоритете?",
"answer1": "Внутренняя гармония",
"answer2": "Надёжные отношения",
"answer3": "Новые впечатления"
},
"/personalized-relationship-analysis": {
"single": {
"title": "Что такое персонализированный анализ отношений?",
"text": "У вас свои сильные стороны, ожидания и трудности. Мы создаём персональный портрет, чтобы помочь вам лучше понять себя и свои истинные потребности в отношениях.<br><br>Мы анализируем ваши ответы и показываем, что мешало вам раньше, а что наоборот поможет встретить именно «своего» человека и построить счастливую любовь."
},
"relationship": {
"title": "Что такое персонализированный анализ отношений?",
"text": "Каждая пара уникальна. У вас свои сильные стороны и свои трудности. Мы создаём персональный портрет отношений, чтобы помочь укрепить доверие, гармонию и близость именно в вашей паре.<br><br>Мы анализируем ваши ответы и показываем, что мешает вашей любви, а что наоборот поможет сделать её глубже и счастливее."
}
}, },
"/element-resonates": { "/element-resonates": {
"title": "Which Element Empowers You the Most?", "title": "Which Element Empowers You the Most?",

View File

@ -56,6 +56,18 @@
} }
} }
}, },
"/compatibility-test": {
"title": "Тест на Совместимость",
"subtitle": "Всё начинается с вас! Выберите ваш пол.",
"points": {
"point1": "Тест займмет не более 1 мин.",
"point2": "Ты получишь разбор совместимости по хиромантическому анализу линий на твоей ладони.",
"point3": "Решишь проблемы в отношениях за месяц.",
"point4": "Сэкономишь сотни долларов на ненадёжных прогнозах.",
"point5": "Получишь персональный анализ."
},
"already_have_account": "Уже есть аккаунт? Войти"
},
"/birthdate": { "/birthdate": {
"title": "Когда вы родились?", "title": "Когда вы родились?",
"text": "Ваша дата рождения может раскрыть сильные стороны и ценности, которые помогут вам двигаться вперёд." "text": "Ваша дата рождения может раскрыть сильные стороны и ценности, которые помогут вам двигаться вперёд."

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -44,7 +44,7 @@ export interface IAnswersSessionPalmistry {
export interface IAnswersSessionCompatibilityV2 { export interface IAnswersSessionCompatibilityV2 {
what_aspects: 'love_relationships' | 'health_vitality' | 'career_destiny' | 'life_transitions', // Type: string, optional - 'love_relationships' | 'health_vitality' | 'career_destiny'; what_aspects: 'love_relationships' | 'health_vitality' | 'career_destiny' | 'life_transitions', // Type: string, optional - 'love_relationships' | 'health_vitality' | 'career_destiny';
relationship_status: 'single' | 'in_relationship' | 'engaged' | 'divorced' | 'complicated', // Type: string, optional - 'single' | 'in_relationship'; relationship_status: 'single' | 'in_relationship' | 'engaged' | 'divorced' | 'complicated' | 'start' | 'developing' | 'crisis', // Type: string, optional - 'single' | 'in_relationship';
element_resonates: 'water' | 'fire' | 'air' | 'earth' | 'light' | 'darkness', // Type: string, optional - 'water' | 'fire' | 'air' | 'earth'; element_resonates: 'water' | 'fire' | 'air' | 'earth' | 'light' | 'darkness', // Type: string, optional - 'water' | 'fire' | 'air' | 'earth';
favorite_color: 'blue' | 'green' | 'orange' | 'violet' | 'red' | 'yellow' | 'turquoise', // Type: string, optional - 'blue' | 'green' | 'orange' | 'violet' | 'red' | 'yellow'; favorite_color: 'blue' | 'green' | 'orange' | 'violet' | 'red' | 'yellow' | 'turquoise', // Type: string, optional - 'blue' | 'green' | 'orange' | 'violet' | 'red' | 'yellow';
head_or_heart: 'head' | 'heart' | 'both' | 'depends', // Type: string, optional - 'head' | 'heart' | 'both'; head_or_heart: 'head' | 'heart' | 'both' | 'depends', // Type: string, optional - 'head' | 'heart' | 'both';
@ -57,6 +57,9 @@ export interface IAnswersSessionCompatibilityV2 {
partner_expectations: 1 | 2 | 3 | 4 | 5; // Type: number, optional - 1 | 2 | 3 | 4 | 5; partner_expectations: 1 | 2 | 3 | 4 | 5; // Type: number, optional - 1 | 2 | 3 | 4 | 5;
romantic_gestures: "love" | "neutral" | "dislike"; // Type: string, optional - "love" | "neutral" | "dislike"; romantic_gestures: "love" | "neutral" | "dislike"; // Type: string, optional - "love" | "neutral" | "dislike";
checking_phone: "against" | "allow" | "normally"; // Type: string, optional - "against" | "allow" | "normally"; checking_phone: "against" | "allow" | "normally"; // Type: string, optional - "against" | "allow" | "normally";
fear_in_relationship: "wasting_life_for_wrong_person" | "stay_single" | "skip_destiny" | "love_without_respect_and_support" | "not_find_truth_about_compatibility";
who_matter: "me" | "kids" | "family";
your_priority: "inner_harmony" | "reliable_relationship" | "new_impressions";
} }
export interface IAnswersSessionCompatibilityV3 { export interface IAnswersSessionCompatibilityV3 {

View File

@ -1,6 +1,7 @@
.container { .container {
width: 100%; width: 100%;
height: 71px; // height: 71px;
padding: 25px 16px;
border-radius: 20px; border-radius: 20px;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -93,7 +93,7 @@
& > .likesImages { & > .likesImages {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-left: 4px; margin-left: 8px;
& > .likesImage { & > .likesImage {
width: 28px; width: 28px;
@ -102,8 +102,8 @@
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
border: 2px solid rgba(255, 255, 255, 1); // border: 2px solid rgba(255, 255, 255, 1);
margin-left: -4px; margin-left: -8px;
} }
} }
} }

View File

@ -0,0 +1,57 @@
import { useTranslations } from "@/hooks/translations";
import styles from "./styles.module.scss";
import { ELocalesPlacement } from "@/locales";
import Title from "@/components/Title";
import PrivacyPolicy from "@/components/pages/ABDesign/v1/components/PrivacyPolicy";
import Button from "../../components/Button";
import { useNavigate } from "react-router-dom";
import routes from "@/routes";
function CompatibilityTestPage() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const navigate = useNavigate();
const handleNext = () => {
navigate(routes.client.compatibilityV2RelationshipStatus());
};
return (
<div className={styles.container}>
<Title variant="h2" className={styles.title}>
{translate("/compatibility-test.title", {
br: <br />,
})}
</Title>
<ul className={styles.points}>
{Array.from({ length: 5 }).map((_, index) => (
<li key={index}>
{translate(`/compatibility-test.points.point${index + 1}`)}
</li>
))}
</ul>
{/* <ChooseGender onSelectGender={selectGender} /> */}
{/* <div className={styles["genders-container"]}>
{localGenders.map((_gender, index) => (
<Answer
key={index}
answer={_gender}
isSelected={gender === _gender.id}
onClick={() =>
selectGender(genders.find((g) => g.id === _gender.id) ?? null)
}
/>
))}
</div> */}
<Button className={styles.button} onClick={handleNext}>
{translate("/compatibility-test.button")}
</Button>
<PrivacyPolicy
containerClassName={styles["privacy-policy"]}
haveCheckbox={false}
/>
</div>
);
}
export default CompatibilityTestPage;

View File

@ -0,0 +1,53 @@
.container {
position: relative;
min-height: calc(100dvh - 110px);
display: flex;
flex-direction: column;
align-items: center;
}
.title {
margin-top: 18px;
font-size: 28px;
font-weight: 500;
line-height: 125%;
margin-bottom: 0;
}
.privacy-policy {
max-width: 316px;
text-align: center;
position: sticky;
margin-top: auto;
}
.points {
margin-top: 46px;
color: #2c2c2c;
list-style-type: disc;
li {
font-size: 20px;
line-height: 125%;
font-weight: 300;
margin-left: 28px;
&::marker {
font-size: 14px;
}
}
}
.button.button {
background: rgba(37, 99, 235, 1);
box-shadow: 2px 5px 2.5px -1px rgba(0, 0, 0, 0.2);
border-radius: 20px;
margin-top: 64px;
margin-bottom: 26px;
}
:global(body.dark-theme) {
.points {
color: #f7f7f7;
}
}

View File

@ -0,0 +1,89 @@
import Title from "@/components/Title";
import styles from "./styles.module.scss";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import { IAnswersSessionCompatibilityV2 } from "@/api/resources/Session";
import { useMemo } from "react";
import Answer from "../../components/Answer";
import { useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { useDispatch } from "react-redux";
import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User";
import routes from "@/routes";
import { useNavigate } from "react-router-dom";
import { sleep } from "@/services/date";
import { answerTimeOut } from "../../data";
function FearInRelationship() {
const navigate = useNavigate();
const dispatch = useDispatch();
const { updateSession } = useSession();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { fearInRelationship } = useSelector(
selectors.selectCompatibilityV2Answers
);
const answers: {
id: IAnswersSessionCompatibilityV2["fear_in_relationship"];
title: string;
}[] = useMemo(
() => [
{
id: "wasting_life_for_wrong_person",
title: translate("/fear-in-relationship.answer1"),
},
{
id: "stay_single",
title: translate("/fear-in-relationship.answer2"),
},
{
id: "skip_destiny",
title: translate("/fear-in-relationship.answer3"),
},
{
id: "love_without_respect_and_support",
title: translate("/fear-in-relationship.answer4"),
},
{
id: "not_find_truth_about_compatibility",
title: translate("/fear-in-relationship.answer5"),
},
],
[translate]
);
const handleClick = async (
id: IAnswersSessionCompatibilityV2["fear_in_relationship"]
) => {
dispatch(actions.compatibilityV2Answers.update({ fearInRelationship: id }));
updateSession(
{
answers: {
fear_in_relationship: id,
},
},
ESourceAuthorization["aura.compatibility.v2"]
);
if (id !== fearInRelationship) await sleep(answerTimeOut);
navigate(routes.client.compatibilityV2ImportantStep());
};
return (
<div className={styles.container}>
<Title variant="h2" className={styles.title}>
{translate("/fear-in-relationship.title")}
</Title>
{answers.map((answers, index) => (
<Answer
key={index}
answer={answers}
isSelected={fearInRelationship === answers.id}
onClick={() => handleClick(answers.id)}
/>
))}
</div>
);
}
export default FearInRelationship;

View File

@ -54,6 +54,10 @@ function GenderPage() {
flag: EUnleashFlags.v2CompatibilityReviewPage, flag: EUnleashFlags.v2CompatibilityReviewPage,
}); });
const { variant: pathToEnteringBirthdate = "hide" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityPathToEnteringBirthdate,
});
const pageType = flags?.genderPageType?.[0] || genderPageType || "v2"; const pageType = flags?.genderPageType?.[0] || genderPageType || "v2";
const genderButtonIcon = flags?.genderButtonIcon?.[0] || "hide"; const genderButtonIcon = flags?.genderButtonIcon?.[0] || "hide";
@ -115,12 +119,24 @@ function GenderPage() {
if (relationshipStatusPagePlacement === "v2") { if (relationshipStatusPagePlacement === "v2") {
return navigate(routes.client.compatibilityV2RelationshipStatus()); return navigate(routes.client.compatibilityV2RelationshipStatus());
} }
console.log(reviewPage);
if (reviewPage === "show") { if (reviewPage === "show") {
return navigate(routes.client.compatibilityV2Review()); return navigate(routes.client.compatibilityV2Review());
} }
if (pathToEnteringBirthdate === "show") {
return navigate(routes.client.compatibilityV2CompatibilityTest());
}
return navigate(routes.client.compatibilityV2Birthdate()); return navigate(routes.client.compatibilityV2Birthdate());
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [gender, navigate]); }, [
gender,
navigate,
reviewPage,
pathToEnteringBirthdate,
relationshipStatusPagePlacement,
isReady,
]);
useEffect(() => { useEffect(() => {
if (privacyPolicyChecked && gender && isSelected) { if (privacyPolicyChecked && gender && isSelected) {
@ -129,6 +145,20 @@ function GenderPage() {
} }
}, [gender, handleNext, isSelected, privacyPolicyChecked]); }, [gender, handleNext, isSelected, privacyPolicyChecked]);
// useEffect(() => {
// if (pathToEnteringBirthdate === "show" && !pathToEnteringBirthdateShown) {
// dispatch(
// actions.compatibilityV2.update({ pathToEnteringBirthdateShown: true })
// );
// return navigate(routes.client.compatibilityV2CompatibilityTest());
// }
// }, [
// dispatch,
// navigate,
// pathToEnteringBirthdate,
// pathToEnteringBirthdateShown,
// ]);
if (!ready || !isReady) return <Loader color={LoaderColor.Black} />; if (!ready || !isReady) return <Loader color={LoaderColor.Black} />;
if (relationshipStatusPagePlacement === "v1" && !noRedirectAB) { if (relationshipStatusPagePlacement === "v1" && !noRedirectAB) {

View File

@ -0,0 +1,26 @@
import { useNavigate } from "react-router-dom";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import AnswerExplanation from "../../templates/AnswerExplanation";
import routes from "@/routes";
import styles from "./styles.module.scss";
function ImportantStep() {
const navigate = useNavigate();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
return (
<AnswerExplanation
title={translate(`/important-step.title`)}
text={translate(`/important-step.text`)}
buttonType="next"
classNameTitle={styles.title}
classNameText={styles.text}
handleNext={() => {
navigate(routes.client.compatibilityV2WhoMatter());
}}
/>
);
}
export default ImportantStep;

View File

@ -0,0 +1,8 @@
.title {
font-weight: 700;
margin-bottom: 62px;
}
.text {
margin-bottom: 62px;
}

View File

@ -14,7 +14,10 @@ import { getZodiacSignByDate } from "@/services/zodiac-sign";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import Loader, { LoaderColor } from "@/components/Loader"; import Loader, { LoaderColor } from "@/components/Loader";
import { useEffect } from "react"; import { useEffect } from "react";
import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import metricService, {
EGoals,
EMetrics,
} from "@/services/metric/metricService";
function PalmsInformation() { function PalmsInformation() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@ -26,33 +29,47 @@ function PalmsInformation() {
}); });
const { isReady, variant: zodiacImages } = useUnleash({ const { isReady, variant: zodiacImages } = useUnleash({
flag: EUnleashFlags.zodiacImages flag: EUnleashFlags.zodiacImages,
}); });
const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({ const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement,
});
const { variant: pathToEnteringBirthdate = "hide" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityPathToEnteringBirthdate,
}); });
const handleNext = () => { const handleNext = () => {
if (relationshipStatusPagePlacement === "v1" || relationshipStatusPagePlacement === "v2") { if (
relationshipStatusPagePlacement === "v1" ||
relationshipStatusPagePlacement === "v2" ||
pathToEnteringBirthdate === "show"
) {
return navigate(`${routes.client.compatibilityV2RelateFollowing()}/1`); return navigate(`${routes.client.compatibilityV2RelateFollowing()}/1`);
} }
navigate(routes.client.compatibilityV2RelationshipStatus()); navigate(routes.client.compatibilityV2RelationshipStatus());
}; };
if (!isReady) {
return <Loader color={LoaderColor.Black} />;
}
useEffect(() => { useEffect(() => {
const ua = window.navigator.userAgent; const ua = window.navigator.userAgent;
if (ua.includes("FBAN") || ua.includes("FBAV") || ua.includes("FBIOS")) { if (ua.includes("FBAN") || ua.includes("FBAV") || ua.includes("FBIOS")) {
metricService.reachGoal(EGoals.STAYED_IN_FB, [EMetrics.YANDEX, EMetrics.KLAVIYO]) metricService.reachGoal(EGoals.STAYED_IN_FB, [
EMetrics.YANDEX,
EMetrics.KLAVIYO,
]);
} }
if (ua.includes("Instagram")) { if (ua.includes("Instagram")) {
metricService.reachGoal(EGoals.STAYED_IN_INSTAGRAM, [EMetrics.YANDEX, EMetrics.KLAVIYO]) metricService.reachGoal(EGoals.STAYED_IN_INSTAGRAM, [
EMetrics.YANDEX,
EMetrics.KLAVIYO,
]);
} }
}, []) }, []);
if (!isReady) {
return <Loader color={LoaderColor.Black} />;
}
return ( return (
<div className={styles["page-container"]}> <div className={styles["page-container"]}>
@ -78,11 +95,11 @@ function PalmsInformation() {
{translate(`/palms-information.${zodiacSign?.toLowerCase()}.title`)} {translate(`/palms-information.${zodiacSign?.toLowerCase()}.title`)}
</Title> </Title>
<p className={styles.description}> <p className={styles.description}>
{translate(`/palms-information.${zodiacSign?.toLowerCase()}.description`)} {translate(
`/palms-information.${zodiacSign?.toLowerCase()}.description`
)}
</p> </p>
<Button onClick={handleNext}> <Button onClick={handleNext}>{translate("next")}</Button>
{translate("next")}
</Button>
<Policy> <Policy>
{translate("privacy_policy", { {translate("privacy_policy", {
eulaLink: ( eulaLink: (

View File

@ -0,0 +1,40 @@
import styles from "./styles.module.scss";
import AnswerExplanation from "../../templates/AnswerExplanation";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import { useNavigate } from "react-router-dom";
import routes from "@/routes";
import { useSelector } from "react-redux";
import { selectors } from "@/store";
import { useMemo } from "react";
function PersonalizedRelationshipAnalysis() {
const navigate = useNavigate();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { relationshipStatus: relationshipStatusAnswer } = useSelector(
selectors.selectCompatibilityV2Answers
);
const relationshipStatus = useMemo(() => {
return relationshipStatusAnswer === "single" ? "single" : "relationship";
}, [relationshipStatusAnswer]);
return (
<AnswerExplanation
title={translate(
`/personalized-relationship-analysis.${relationshipStatus}.title`
)}
text={translate(
`/personalized-relationship-analysis.${relationshipStatus}.text`
)}
buttonType="next"
classNameTitle={styles.title}
classNameText={styles.text}
handleNext={() => {
navigate(routes.client.compatibilityV2Birthdate());
}}
/>
);
}
export default PersonalizedRelationshipAnalysis;

View File

@ -0,0 +1,7 @@
.title {
font-weight: 700;
}
.text {
margin-bottom: 38px;
}

View File

@ -14,6 +14,7 @@ import { useSession } from "@/hooks/session/useSession";
import { IAnswersSessionCompatibilityV2 } from "@/api/resources/Session"; import { IAnswersSessionCompatibilityV2 } from "@/api/resources/Session";
import { ESourceAuthorization } from "@/api/resources/User"; import { ESourceAuthorization } from "@/api/resources/User";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import Loader, { LoaderColor } from "@/components/Loader";
function RelationshipStatus() { function RelationshipStatus() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@ -25,14 +26,47 @@ function RelationshipStatus() {
); );
const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({ const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement,
}); });
const { variant: pathToEnteringBirthdate = "hide", isReady } = useUnleash({
flag: EUnleashFlags.v2CompatibilityPathToEnteringBirthdate,
});
const isPathToEnteringBirthdate = useMemo(
() => isReady && pathToEnteringBirthdate === "show",
[isReady, pathToEnteringBirthdate]
);
const answers: { const answers: {
id: IAnswersSessionCompatibilityV2["relationship_status"]; id: IAnswersSessionCompatibilityV2["relationship_status"];
title: string; title: string;
}[] = useMemo( }[] = useMemo(() => {
() => [ if (isPathToEnteringBirthdate) {
return [
{
id: "single",
title: translate("/relationship-status.v1.answer1"),
},
{
id: "start",
title: translate("/relationship-status.v1.answer2"),
},
{
id: "in_relationship",
title: translate("/relationship-status.v1.answer3"),
},
{
id: "developing",
title: translate("/relationship-status.v1.answer4"),
},
{
id: "crisis",
title: translate("/relationship-status.v1.answer5"),
},
];
}
return [
{ {
id: "single", id: "single",
title: translate("/relationship-status.answer1"), title: translate("/relationship-status.answer1"),
@ -53,21 +87,31 @@ function RelationshipStatus() {
// id: "complicated", // id: "complicated",
// title: translate("/relationship-status.answer5"), // title: translate("/relationship-status.answer5"),
// }, // },
], ];
[translate] }, [isPathToEnteringBirthdate, translate]);
);
const handleClick = async (id: IAnswersSessionCompatibilityV2["relationship_status"]) => { const handleClick = async (
id: IAnswersSessionCompatibilityV2["relationship_status"]
) => {
dispatch(actions.compatibilityV2Answers.update({ relationshipStatus: id })); dispatch(actions.compatibilityV2Answers.update({ relationshipStatus: id }));
updateSession({ updateSession(
answers: { {
relationship_status: id, answers: {
relationship_status: id,
},
}, },
}, ESourceAuthorization["aura.compatibility.v2"]); ESourceAuthorization["aura.compatibility.v2"]
);
if (id !== relationshipStatus) await sleep(answerTimeOut); if (id !== relationshipStatus) await sleep(answerTimeOut);
if (isPathToEnteringBirthdate) {
return navigate(routes.client.compatibilityV2RelationshipStatusResult());
}
if (relationshipStatusPagePlacement === "v1") { if (relationshipStatusPagePlacement === "v1") {
return navigate(`${routes.client.compatibilityV2Gender()}?noRedirectAB=true`); return navigate(
`${routes.client.compatibilityV2Gender()}?noRedirectAB=true`
);
} }
if (relationshipStatusPagePlacement === "v2") { if (relationshipStatusPagePlacement === "v2") {
@ -77,10 +121,16 @@ function RelationshipStatus() {
navigate(`${routes.client.compatibilityV2RelateFollowing()}/1`); navigate(`${routes.client.compatibilityV2RelateFollowing()}/1`);
}; };
if (!isReady) {
return <Loader color={LoaderColor.Black} />;
}
return ( return (
<div className={styles.container}> <div className={styles.container}>
<Title variant="h2" className={styles.title}> <Title variant="h2" className={styles.title}>
{translate("/relationship-status.title")} {isPathToEnteringBirthdate
? translate("/relationship-status.v1.title")
: translate("/relationship-status.title")}
</Title> </Title>
{answers.map((answers, index) => ( {answers.map((answers, index) => (
<Answer <Answer

View File

@ -0,0 +1,29 @@
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import routes from "@/routes";
import { selectors } from "@/store";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import AnswerExplanation from "../../templates/AnswerExplanation";
function RelationshipStatusResult() {
const navigate = useNavigate();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { relationshipStatus } = useSelector(
selectors.selectCompatibilityV2Answers
);
return (
<AnswerExplanation
title={translate(
`/relationship-status-result.${relationshipStatus}.title`
)}
text={translate(`/relationship-status-result.${relationshipStatus}.text`)}
handleNext={() => {
navigate(routes.client.compatibilityV2FearInRelationship());
}}
/>
);
}
export default RelationshipStatusResult;

View File

@ -11,15 +11,31 @@ import { images } from "../../data";
import Button from "../../components/Button"; import Button from "../../components/Button";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import routes from "@/routes"; import routes from "@/routes";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import Loader, { LoaderColor } from "@/components/Loader";
function ReviewPage() { function ReviewPage() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const navigate = useNavigate(); const navigate = useNavigate();
const { variant: pathToEnteringBirthdate = "hide", isReady } = useUnleash({
flag: EUnleashFlags.v2CompatibilityPathToEnteringBirthdate,
});
const handleNext = () => { const handleNext = () => {
if (pathToEnteringBirthdate === "show") {
return navigate(routes.client.compatibilityV2CompatibilityTest());
}
navigate(routes.client.compatibilityV2Birthdate()); navigate(routes.client.compatibilityV2Birthdate());
}; };
if (!isReady) {
return (
<div className={styles.container}>
<Loader color={LoaderColor.Black} />
</div>
);
}
return ( return (
<div className={styles.container}> <div className={styles.container}>
<Title variant="h1" className={styles.title}> <Title variant="h1" className={styles.title}>
@ -51,9 +67,9 @@ function ReviewPage() {
verifiedText={translate("/review.review.verified_user")} verifiedText={translate("/review.review.verified_user")}
likesText={translate("/review.review.likes")} likesText={translate("/review.review.likes")}
likesImages={[ likesImages={[
"review/like_1.jpg", images("review/like_1.png"),
"review/like_2.jpg", images("review/like_2.png"),
"review/like_3.png", images("review/like_3.png"),
]} ]}
image={images("review/avatar.jpg")} image={images("review/avatar.jpg")}
/> />

View File

@ -6,6 +6,10 @@
min-height: 100dvh; min-height: 100dvh;
margin: 0 auto; margin: 0 auto;
padding: 45px 24px; padding: 45px 24px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
& * { & * {
font-family: Inter; font-family: Inter;

View File

@ -0,0 +1,79 @@
import Title from "@/components/Title";
import styles from "./styles.module.scss";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import { IAnswersSessionCompatibilityV2 } from "@/api/resources/Session";
import { useMemo } from "react";
import Answer from "../../components/Answer";
import { useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { useDispatch } from "react-redux";
import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User";
import routes from "@/routes";
import { useNavigate } from "react-router-dom";
import { sleep } from "@/services/date";
import { answerTimeOut } from "../../data";
function WhoMatter() {
const navigate = useNavigate();
const dispatch = useDispatch();
const { updateSession } = useSession();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { whoMatter } = useSelector(selectors.selectCompatibilityV2Answers);
const answers: {
id: IAnswersSessionCompatibilityV2["who_matter"];
title: string;
}[] = useMemo(
() => [
{
id: "me",
title: translate("/who-matter.answer1"),
},
{
id: "kids",
title: translate("/who-matter.answer2"),
},
{
id: "family",
title: translate("/who-matter.answer3"),
},
],
[translate]
);
const handleClick = async (
id: IAnswersSessionCompatibilityV2["who_matter"]
) => {
dispatch(actions.compatibilityV2Answers.update({ whoMatter: id }));
updateSession(
{
answers: {
who_matter: id,
},
},
ESourceAuthorization["aura.compatibility.v2"]
);
if (id !== whoMatter) await sleep(answerTimeOut);
navigate(routes.client.compatibilityV2YourPriority());
};
return (
<div className={styles.container}>
<Title variant="h2" className={styles.title}>
{translate("/who-matter.title")}
</Title>
{answers.map((answers, index) => (
<Answer
key={index}
answer={answers}
isSelected={whoMatter === answers.id}
onClick={() => handleClick(answers.id)}
/>
))}
</div>
);
}
export default WhoMatter;

View File

@ -0,0 +1,79 @@
import Title from "@/components/Title";
import styles from "./styles.module.scss";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import { IAnswersSessionCompatibilityV2 } from "@/api/resources/Session";
import { useMemo } from "react";
import Answer from "../../components/Answer";
import { useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { useDispatch } from "react-redux";
import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User";
import routes from "@/routes";
import { useNavigate } from "react-router-dom";
import { sleep } from "@/services/date";
import { answerTimeOut } from "../../data";
function YourPriority() {
const navigate = useNavigate();
const dispatch = useDispatch();
const { updateSession } = useSession();
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { yourPriority } = useSelector(selectors.selectCompatibilityV2Answers);
const answers: {
id: IAnswersSessionCompatibilityV2["your_priority"];
title: string;
}[] = useMemo(
() => [
{
id: "inner_harmony",
title: translate("/your-priority.answer1"),
},
{
id: "reliable_relationship",
title: translate("/your-priority.answer2"),
},
{
id: "new_impressions",
title: translate("/your-priority.answer3"),
},
],
[translate]
);
const handleClick = async (
id: IAnswersSessionCompatibilityV2["your_priority"]
) => {
dispatch(actions.compatibilityV2Answers.update({ yourPriority: id }));
updateSession(
{
answers: {
your_priority: id,
},
},
ESourceAuthorization["aura.compatibility.v2"]
);
if (id !== yourPriority) await sleep(answerTimeOut);
navigate(routes.client.compatibilityV2PersonalizedRelationshipAnalysis());
};
return (
<div className={styles.container}>
<Title variant="h2" className={styles.title}>
{translate("/your-priority.title")}
</Title>
{answers.map((answers, index) => (
<Answer
key={index}
answer={answers}
isSelected={yourPriority === answers.id}
onClick={() => handleClick(answers.id)}
/>
))}
</div>
);
}
export default YourPriority;

View File

@ -0,0 +1,73 @@
import { useTranslations } from "@/hooks/translations";
import styles from "./styles.module.scss";
import { ELocalesPlacement } from "@/locales";
import Title from "@/components/Title";
import Button from "../../components/Button";
import { useNavigate } from "react-router-dom";
interface IAnswerExplanation {
title?: string;
text?: string;
buttonType?: "back_next" | "next";
classNameTitle?: string;
classNameText?: string;
handleBack?: () => void;
handleNext: () => void;
}
function AnswerExplanation({
title,
text,
buttonType = "back_next",
classNameTitle = "",
classNameText = "",
handleBack,
handleNext,
}: IAnswerExplanation) {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const navigate = useNavigate();
const handleBackClick = () => {
return handleBack ? handleBack() : navigate(-1);
};
const handleNextClick = () => {
return handleNext();
};
return (
<div className={styles.container}>
{!!title?.length && (
<Title variant="h2" className={`${styles.title} ${classNameTitle}`}>
{title}
</Title>
)}
{!!text?.length && (
<p className={`${styles.text} ${classNameText}`}>{text}</p>
)}
{buttonType === "back_next" && (
<div className={styles["buttons-container"]}>
<Button
className={`${styles.button} ${styles["back-button"]}`}
onClick={handleBackClick}
>
{translate("back")}
</Button>
<Button
className={`${styles.button} ${styles["next-button"]}`}
onClick={handleNextClick}
>
{translate("next")}
</Button>
</div>
)}
{buttonType === "next" && (
<Button className={styles.button} onClick={handleNextClick}>
{translate("next")}
</Button>
)}
</div>
);
}
export default AnswerExplanation;

View File

@ -0,0 +1,44 @@
.container {
width: 100%;
}
.title {
font-size: 28px;
font-weight: 500;
line-height: 40px;
}
.text {
font-size: 20px;
line-height: 25px;
text-align: center;
margin-bottom: 74px;
}
.buttons-container {
display: flex;
flex-direction: row;
justify-content: space-between;
padding-top: 24px;
& > .button {
width: 48%;
min-width: 0px;
font-size: 23px;
height: 44px;
min-height: 0px;
&.back-button {
background: none;
color: #2c2c2c;
border: solid #2c2c2c 2px;
}
}
}
:global(body.dark-theme) {
.buttons-container > .button.back-button {
color: #fff;
border-color: #fff;
}
}

View File

@ -37,6 +37,7 @@ export enum EUnleashFlags {
"v2CompatibilityCameraTemplate" = "v2-compatibility-camera-template", "v2CompatibilityCameraTemplate" = "v2-compatibility-camera-template",
"v2CompatibilityRelationshipStatusPagePlacement" = "v2-compatibility-relationship-status-page-placement", "v2CompatibilityRelationshipStatusPagePlacement" = "v2-compatibility-relationship-status-page-placement",
"v2CompatibilityReviewPage" = "v2-compatibility-review-page", "v2CompatibilityReviewPage" = "v2-compatibility-review-page",
"v2CompatibilityPathToEnteringBirthdate" = "v2-compatibility-path-to-entering-birthdate",
} }
interface IUseUnleashProps<T extends EUnleashFlags> { interface IUseUnleashProps<T extends EUnleashFlags> {
@ -78,6 +79,7 @@ interface IVariants {
[EUnleashFlags.v2CompatibilityCameraTemplate]: 'v0' | 'v1' | 'v2' | 'v3' | 'v4'; [EUnleashFlags.v2CompatibilityCameraTemplate]: 'v0' | 'v1' | 'v2' | 'v3' | 'v4';
[EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement]: 'v0' | 'v1' | 'v2'; [EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement]: 'v0' | 'v1' | 'v2';
[EUnleashFlags.v2CompatibilityReviewPage]: 'show' | 'hide'; [EUnleashFlags.v2CompatibilityReviewPage]: 'show' | 'hide';
[EUnleashFlags.v2CompatibilityPathToEnteringBirthdate]: 'hide' | 'show';
} }
/** /**

View File

@ -34,17 +34,28 @@ function Layout() {
]); ]);
const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({ const { variant: relationshipStatusPagePlacement = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement flag: EUnleashFlags.v2CompatibilityRelationshipStatusPagePlacement,
}); });
const getIsBackButtonVisible = () => { const getIsBackButtonVisible = () => {
if ( if (
relationshipStatusPagePlacement === "v1" && location.pathname.includes(routes.client.compatibilityV2RelationshipStatus()) location.pathname.includes(
routes.client.compatibilityV2RelationshipStatusResult()
)
) { ) {
return false; return false;
} }
if ( if (
relationshipStatusPagePlacement === "v1" && location.pathname.includes(routes.client.compatibilityV2Gender()) relationshipStatusPagePlacement === "v1" &&
location.pathname.includes(
routes.client.compatibilityV2RelationshipStatus()
)
) {
return false;
}
if (
relationshipStatusPagePlacement === "v1" &&
location.pathname.includes(routes.client.compatibilityV2Gender())
) { ) {
return true; return true;
} }

View File

@ -1,30 +1,13 @@
import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement"; import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement";
import { useRef } from "react"; import { useMemo, useRef } from "react";
import { Outlet, useLocation } from "react-router-dom"; import { Outlet, useLocation } from "react-router-dom";
import routes from "@/routes"; import routes from "@/routes";
import StepperBar from "@/components/CompatibilityV2/components/StepperBar"; import StepperBar from "@/components/CompatibilityV2/components/StepperBar";
import styles from "./styles.module.scss"; import styles from "./styles.module.scss";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { selectors } from "@/store"; import { selectors } from "@/store";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
const stepperRoutes = [ import Loader, { LoaderColor } from "@/components/Loader";
routes.client.compatibilityV2Birthdate(),
routes.client.compatibilityV2PalmsInformation(),
// routes.client.compatibilityV2WhatAspects(),
routes.client.compatibilityV2RelationshipStatus(),
routes.client.compatibilityV2RelateFollowing(),
routes.client.compatibilityV2RomanticGestures(),
routes.client.compatibilityV2CheckingPhone(),
routes.client.compatibilityV2BirthdatePartner(),
routes.client.compatibilityV2PalmsInformationPartner(),
routes.client.compatibilityV2DateEvent(),
// routes.client.compatibilityV2ElementResonates(),
// routes.client.compatibilityV2FavoriteColor(),
routes.client.compatibilityV2HeadOrHeart(),
routes.client.compatibilityV2HeadOrHeartResult(),
routes.client.compatibilityV2Email(),
];
function StepperLayout() { function StepperLayout() {
const darkTheme = useSelector(selectors.selectDarkTheme); const darkTheme = useSelector(selectors.selectDarkTheme);
@ -33,27 +16,86 @@ function StepperLayout() {
useSchemeColorByElement(mainRef.current, "section.page, .page, section", [ useSchemeColorByElement(mainRef.current, "section.page, .page, section", [
location, location,
]); ]);
const { variant: pathToEnteringBirthdate = "hide", isReady } = useUnleash({
flag: EUnleashFlags.v2CompatibilityPathToEnteringBirthdate,
});
const stepperRoutes = useMemo(() => {
if (pathToEnteringBirthdate === "show") {
return [
routes.client.compatibilityV2RelationshipStatus(),
routes.client.compatibilityV2FearInRelationship(),
routes.client.compatibilityV2ImportantStep(),
routes.client.compatibilityV2WhoMatter(),
routes.client.compatibilityV2YourPriority(),
routes.client.compatibilityV2Birthdate(),
routes.client.compatibilityV2PalmsInformation(),
// routes.client.compatibilityV2WhatAspects(),
routes.client.compatibilityV2RelateFollowing(),
routes.client.compatibilityV2RomanticGestures(),
routes.client.compatibilityV2CheckingPhone(),
routes.client.compatibilityV2BirthdatePartner(),
routes.client.compatibilityV2PalmsInformationPartner(),
routes.client.compatibilityV2DateEvent(),
// routes.client.compatibilityV2ElementResonates(),
// routes.client.compatibilityV2FavoriteColor(),
routes.client.compatibilityV2HeadOrHeart(),
routes.client.compatibilityV2HeadOrHeartResult(),
routes.client.compatibilityV2Email(),
];
}
return [
routes.client.compatibilityV2Birthdate(),
routes.client.compatibilityV2PalmsInformation(),
// routes.client.compatibilityV2WhatAspects(),
routes.client.compatibilityV2RelationshipStatus(),
routes.client.compatibilityV2RelateFollowing(),
routes.client.compatibilityV2RomanticGestures(),
routes.client.compatibilityV2CheckingPhone(),
routes.client.compatibilityV2BirthdatePartner(),
routes.client.compatibilityV2PalmsInformationPartner(),
routes.client.compatibilityV2DateEvent(),
// routes.client.compatibilityV2ElementResonates(),
// routes.client.compatibilityV2FavoriteColor(),
routes.client.compatibilityV2HeadOrHeart(),
routes.client.compatibilityV2HeadOrHeartResult(),
routes.client.compatibilityV2Email(),
];
}, [pathToEnteringBirthdate]);
const getCurrentStep = () => { const getCurrentStep = () => {
let index = 0; let index = 0;
for (const route of stepperRoutes) { for (const route of stepperRoutes) {
if (location.pathname.includes(route)) { if (location.pathname.includes(route)) {
if (location.pathname.includes(routes.client.compatibilityV2BirthdatePartner())) { if (
location.pathname.includes(
routes.client.compatibilityV2BirthdatePartner()
)
) {
return 8; return 8;
} }
if (location.pathname.includes(routes.client.compatibilityV2PalmsInformationPartner())) { if (
location.pathname.includes(
routes.client.compatibilityV2PalmsInformationPartner()
)
) {
return 9; return 9;
} }
return index + 1; return index + 1;
} }
index++; index++;
} }
return 0; return 0;
}; };
if (!isReady) {
return <Loader color={LoaderColor.Black} />;
}
return ( return (
<> <>
<StepperBar <StepperBar

View File

@ -44,13 +44,22 @@ import AddConsultant from "@/components/palmistry/AdditionalPurchases/pages/AddC
import AddGuides from "@/components/palmistry/AdditionalPurchases/pages/AddGuides"; import AddGuides from "@/components/palmistry/AdditionalPurchases/pages/AddGuides";
import PaymentPage from "@/components/Payment/nmi/PaymentPage"; import PaymentPage from "@/components/Payment/nmi/PaymentPage";
import TryApp from "@/components/CompatibilityV2/pages/TryApp"; import TryApp from "@/components/CompatibilityV2/pages/TryApp";
import { ESiteTheme, useTheme } from "@/hooks/theme/useTheme"; import { useTheme } from "@/hooks/theme/useTheme";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import Loader, { LoaderColor } from "@/components/Loader";
import ScanHand from "@/components/CompatibilityV2/pages/ScanHand"; import ScanHand from "@/components/CompatibilityV2/pages/ScanHand";
import { ELocalesPlacement } from "@/locales"; import { ELocalesPlacement } from "@/locales";
import { useFunnel } from "@/hooks/funnel/useFunnel"; import { useFunnel } from "@/hooks/funnel/useFunnel";
import Review from "@/components/CompatibilityV2/pages/Review"; import Review from "@/components/CompatibilityV2/pages/Review";
import {
getSystemColorScheme,
subscribeToSystemThemeChange,
} from "@/utils/Theme";
import CompatibilityTestPage from "@/components/CompatibilityV2/pages/CompatibilityTest";
import RelationshipStatusResult from "@/components/CompatibilityV2/pages/RelationshipStatusResult";
import FearInRelationship from "@/components/CompatibilityV2/pages/FearInRelationship";
import ImportantStep from "@/components/CompatibilityV2/pages/ImportantStep";
import WhoMatter from "@/components/CompatibilityV2/pages/WhoMatter";
import YourPriority from "@/components/CompatibilityV2/pages/YourPriority";
import PersonalizedRelationshipAnalysis from "@/components/CompatibilityV2/pages/PersonalizedRelationshipAnalysis";
const removePrefix = (path: string) => path.replace(compatibilityV2Prefix, ""); const removePrefix = (path: string) => path.replace(compatibilityV2Prefix, "");
@ -59,10 +68,6 @@ function CompatibilityV2Routes() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { setTheme } = useTheme(); const { setTheme } = useTheme();
const { isReady, variant: darkThemeCompatibilityV2Variant } = useUnleash({
flag: EUnleashFlags.darkThemeCompatibilityV2,
});
const { funnelData } = useFunnel({ const { funnelData } = useFunnel({
funnel: ELocalesPlacement.CompatibilityV2, funnel: ELocalesPlacement.CompatibilityV2,
paymentPlacement: "", paymentPlacement: "",
@ -140,28 +145,17 @@ function CompatibilityV2Routes() {
} }
useEffect(() => { useEffect(() => {
if (darkThemeCompatibilityV2Variant === "enabled") { const systemColorScheme = getSystemColorScheme();
setTheme(ESiteTheme.Dark); setTheme(systemColorScheme);
}
return () => {
setTheme(ESiteTheme.Light);
};
}, [darkThemeCompatibilityV2Variant]);
if (!isReady) { const unsubscribe = subscribeToSystemThemeChange((theme) => {
return ( setTheme(theme);
<div });
style={{
display: "flex", return () => {
justifyContent: "center", unsubscribe?.();
alignItems: "center", };
height: "100dvh", }, [setTheme]);
}}
>
<Loader color={LoaderColor.Black} />
</div>
);
}
return ( return (
<Routes> <Routes>
@ -261,6 +255,12 @@ function CompatibilityV2Routes() {
> >
<Route path="*" element={<Gender />} /> <Route path="*" element={<Gender />} />
</Route> </Route>
<Route
path={removePrefix(
routes.client.compatibilityV2CompatibilityTest()
)}
element={<CompatibilityTestPage />}
/>
<Route <Route
path={removePrefix(routes.client.compatibilityV2GenderPartner())} path={removePrefix(routes.client.compatibilityV2GenderPartner())}
element={<GenderPartner />} element={<GenderPartner />}
@ -271,7 +271,39 @@ function CompatibilityV2Routes() {
> >
<Route path="*" element={<FindHappiness />} /> <Route path="*" element={<FindHappiness />} />
</Route> </Route>
<Route
path={removePrefix(
routes.client.compatibilityV2RelationshipStatusResult()
)}
element={<RelationshipStatusResult />}
/>
<Route
path={removePrefix(
routes.client.compatibilityV2PersonalizedRelationshipAnalysis()
)}
element={<PersonalizedRelationshipAnalysis />}
/>
<Route element={<StepperLayout />}> <Route element={<StepperLayout />}>
<Route
path={removePrefix(
routes.client.compatibilityV2FearInRelationship()
)}
element={<FearInRelationship />}
/>
<Route
path={removePrefix(
routes.client.compatibilityV2ImportantStep()
)}
element={<ImportantStep />}
/>
<Route
path={removePrefix(routes.client.compatibilityV2WhoMatter())}
element={<WhoMatter />}
/>
<Route
path={removePrefix(routes.client.compatibilityV2YourPriority())}
element={<YourPriority />}
/>
<Route <Route
path={removePrefix(routes.client.compatibilityV2Birthdate())} path={removePrefix(routes.client.compatibilityV2Birthdate())}
element={<Birthdate />} element={<Birthdate />}

View File

@ -224,6 +224,7 @@ const routes = {
palmistryOnboardingV1: () => [palmistryV1Prefix, "onboarding"].join("/"), palmistryOnboardingV1: () => [palmistryV1Prefix, "onboarding"].join("/"),
// CompatibilityV2 // CompatibilityV2
compatibilityV2Welcome: () => [compatibilityV2Prefix, "welcome"].join("/"), compatibilityV2Welcome: () => [compatibilityV2Prefix, "welcome"].join("/"),
compatibilityV2CompatibilityTest: () => [compatibilityV2Prefix, "compatibility-test"].join("/"),
compatibilityV2Gender: () => [compatibilityV2Prefix, "gender"].join("/"), compatibilityV2Gender: () => [compatibilityV2Prefix, "gender"].join("/"),
compatibilityV2GenderPartner: () => [compatibilityV2Prefix, "gender-partner"].join("/"), compatibilityV2GenderPartner: () => [compatibilityV2Prefix, "gender-partner"].join("/"),
compatibilityV2Birthdate: () => [compatibilityV2Prefix, "birthdate"].join("/"), compatibilityV2Birthdate: () => [compatibilityV2Prefix, "birthdate"].join("/"),
@ -233,6 +234,11 @@ const routes = {
compatibilityV2DateEvent: () => [compatibilityV2Prefix, "date-event"].join("/"), compatibilityV2DateEvent: () => [compatibilityV2Prefix, "date-event"].join("/"),
compatibilityV2WhatAspects: () => [compatibilityV2Prefix, "what-aspects"].join("/"), compatibilityV2WhatAspects: () => [compatibilityV2Prefix, "what-aspects"].join("/"),
compatibilityV2RelationshipStatus: () => [compatibilityV2Prefix, "relationship-status"].join("/"), compatibilityV2RelationshipStatus: () => [compatibilityV2Prefix, "relationship-status"].join("/"),
compatibilityV2RelationshipStatusResult: () => [compatibilityV2Prefix, "relationship-status-result"].join("/"),
compatibilityV2FearInRelationship: () => [compatibilityV2Prefix, "fear-in-relationship"].join("/"),
compatibilityV2ImportantStep: () => [compatibilityV2Prefix, "important-step"].join("/"),
compatibilityV2WhoMatter: () => [compatibilityV2Prefix, "who-matter"].join("/"),
compatibilityV2YourPriority: () => [compatibilityV2Prefix, "your-priority"].join("/"),
compatibilityV2ElementResonates: () => [compatibilityV2Prefix, "element-resonates"].join("/"), compatibilityV2ElementResonates: () => [compatibilityV2Prefix, "element-resonates"].join("/"),
compatibilityV2FavoriteColor: () => [compatibilityV2Prefix, "favorite-color"].join("/"), compatibilityV2FavoriteColor: () => [compatibilityV2Prefix, "favorite-color"].join("/"),
compatibilityV2HeadOrHeart: () => [compatibilityV2Prefix, "head-or-heart"].join("/"), compatibilityV2HeadOrHeart: () => [compatibilityV2Prefix, "head-or-heart"].join("/"),
@ -240,6 +246,7 @@ const routes = {
compatibilityV2RelateFollowing: () => [compatibilityV2Prefix, "relate-following"].join("/"), compatibilityV2RelateFollowing: () => [compatibilityV2Prefix, "relate-following"].join("/"),
compatibilityV2RomanticGestures: () => [compatibilityV2Prefix, "romantic-gestures"].join("/"), compatibilityV2RomanticGestures: () => [compatibilityV2Prefix, "romantic-gestures"].join("/"),
compatibilityV2CheckingPhone: () => [compatibilityV2Prefix, "checking-phone"].join("/"), compatibilityV2CheckingPhone: () => [compatibilityV2Prefix, "checking-phone"].join("/"),
compatibilityV2PersonalizedRelationshipAnalysis: () => [compatibilityV2Prefix, "personalized-relationship-analysis"].join("/"),
compatibilityV2LetScan: () => [compatibilityV2Prefix, "let-scan"].join("/"), compatibilityV2LetScan: () => [compatibilityV2Prefix, "let-scan"].join("/"),
compatibilityV2ScanInstruction: () => [compatibilityV2Prefix, "scan-instruction"].join("/"), compatibilityV2ScanInstruction: () => [compatibilityV2Prefix, "scan-instruction"].join("/"),
compatibilityV2Camera: () => [compatibilityV2Prefix, "camera"].join("/"), compatibilityV2Camera: () => [compatibilityV2Prefix, "camera"].join("/"),

View File

@ -2,7 +2,9 @@ import { IPalmistryFinger, IPalmistryLine } from "@/api/resources/Palmistry";
import { createSlice, createSelector } from "@reduxjs/toolkit"; import { createSlice, createSelector } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit"; import type { PayloadAction } from "@reduxjs/toolkit";
export type ICompatibilityV2FingerLocal = IPalmistryFinger & { fingerName?: string } export type ICompatibilityV2FingerLocal = IPalmistryFinger & {
fingerName?: string;
};
interface ICompatibilityV2 { interface ICompatibilityV2 {
lines: IPalmistryLine[]; lines: IPalmistryLine[];
@ -35,7 +37,8 @@ export const selectCompatibilityV2Lines = createSelector(
(compatibilityV2) => compatibilityV2 (compatibilityV2) => compatibilityV2
); );
export const selectCompatibilityV2Fingers = createSelector( export const selectCompatibilityV2Fingers = createSelector(
(state: { compatibilityV2: ICompatibilityV2 }) => state.compatibilityV2.fingers, (state: { compatibilityV2: ICompatibilityV2 }) =>
state.compatibilityV2.fingers,
(compatibilityV2) => compatibilityV2 (compatibilityV2) => compatibilityV2
); );
export const selectCompatibilityV2Photo = createSelector( export const selectCompatibilityV2Photo = createSelector(
@ -43,7 +46,8 @@ export const selectCompatibilityV2Photo = createSelector(
(compatibilityV2) => compatibilityV2 (compatibilityV2) => compatibilityV2
); );
export const selectCompatibilityV2FromRedesign = createSelector( export const selectCompatibilityV2FromRedesign = createSelector(
(state: { compatibilityV2: ICompatibilityV2 }) => state.compatibilityV2.fromRedesign, (state: { compatibilityV2: ICompatibilityV2 }) =>
state.compatibilityV2.fromRedesign,
(compatibilityV2) => compatibilityV2 (compatibilityV2) => compatibilityV2
); );
export default compatibilityV2Slice.reducer; export default compatibilityV2Slice.reducer;

View File

@ -2,41 +2,48 @@ import { createSlice, createSelector } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit"; import type { PayloadAction } from "@reduxjs/toolkit";
export interface ICompatibilityV2Answers { export interface ICompatibilityV2Answers {
whatAspects: string; whatAspects: string;
relationshipStatus: string; relationshipStatus: string;
elementResonates: string; elementResonates: string;
favoriteColor: string; favoriteColor: string;
headOrHeart: string; headOrHeart: string;
dateEvent: string; dateEvent: string;
romanticGestures: string; romanticGestures: string;
checkingPhone: string; checkingPhone: string;
fearInRelationship: string;
whoMatter: string;
yourPriority: string;
} }
const initialState: ICompatibilityV2Answers = { const initialState: ICompatibilityV2Answers = {
whatAspects: "", whatAspects: "",
relationshipStatus: "", relationshipStatus: "",
elementResonates: "", elementResonates: "",
favoriteColor: "", favoriteColor: "",
headOrHeart: "", headOrHeart: "",
dateEvent: "", dateEvent: "",
romanticGestures: "", romanticGestures: "",
checkingPhone: "", checkingPhone: "",
fearInRelationship: "",
whoMatter: "",
yourPriority: "",
}; };
const compatibilityV2AnswersSlice = createSlice({ const compatibilityV2AnswersSlice = createSlice({
name: "compatibilityV2Answers", name: "compatibilityV2Answers",
initialState, initialState,
reducers: { reducers: {
update(state, action: PayloadAction<Partial<ICompatibilityV2Answers>>) { update(state, action: PayloadAction<Partial<ICompatibilityV2Answers>>) {
return { ...state, ...action.payload }; return { ...state, ...action.payload };
},
}, },
extraReducers: (builder) => builder.addCase("reset", () => initialState), },
extraReducers: (builder) => builder.addCase("reset", () => initialState),
}); });
export const { actions } = compatibilityV2AnswersSlice; export const { actions } = compatibilityV2AnswersSlice;
export const selectCompatibilityV2Answers = createSelector( export const selectCompatibilityV2Answers = createSelector(
(state: { compatibilityV2Answers: ICompatibilityV2Answers }) => state.compatibilityV2Answers, (state: { compatibilityV2Answers: ICompatibilityV2Answers }) =>
(compatibilityV2Answers) => compatibilityV2Answers state.compatibilityV2Answers,
(compatibilityV2Answers) => compatibilityV2Answers
); );
export default compatibilityV2AnswersSlice.reducer; export default compatibilityV2AnswersSlice.reducer;

View File

@ -88,39 +88,56 @@ import palmistry, {
selectPalmistryFingers, selectPalmistryFingers,
selectPalmistryFromRedesign, selectPalmistryFromRedesign,
selectPalmistryLines, selectPalmistryLines,
selectPalmistryPhoto selectPalmistryPhoto,
} from "./palmistry"; } from "./palmistry";
import compatibilityV2, { import compatibilityV2, {
actions as compatibilityV2Actions, actions as compatibilityV2Actions,
selectCompatibilityV2Fingers, selectCompatibilityV2Fingers,
selectCompatibilityV2FromRedesign, selectCompatibilityV2FromRedesign,
selectCompatibilityV2Lines, selectCompatibilityV2Lines,
selectCompatibilityV2Photo selectCompatibilityV2Photo,
} from "./compatibilityV2"; } from "./compatibilityV2";
import retainingFunnel, { import retainingFunnel, {
actions as retainingFunnelActions, actions as retainingFunnelActions,
selectRetainingFunnel, selectRetainingFunnel,
selectCancellingSubscriptionId selectCancellingSubscriptionId,
} from "./retainingFunnel"; } from "./retainingFunnel";
import compatibilityV3, { import compatibilityV3, {
actions as compatibilityV3Actions, actions as compatibilityV3Actions,
selectCompatibilityV3Fingers, selectCompatibilityV3Fingers,
selectCompatibilityV3FromRedesign, selectCompatibilityV3FromRedesign,
selectCompatibilityV3Lines, selectCompatibilityV3Lines,
selectCompatibilityV3Photo selectCompatibilityV3Photo,
} from "./compatibilityV3"; } from "./compatibilityV3";
import compatibilityV4, { import compatibilityV4, {
actions as compatibilityV4Actions, actions as compatibilityV4Actions,
selectCompatibilityV4Fingers, selectCompatibilityV4Fingers,
selectCompatibilityV4FromRedesign, selectCompatibilityV4FromRedesign,
selectCompatibilityV4Lines, selectCompatibilityV4Lines,
selectCompatibilityV4Photo selectCompatibilityV4Photo,
} from "./compatibilityV4"; } from "./compatibilityV4";
import { selectPaywallsIsMustUpdate, selectPaywalls } from "./paywalls"; import { selectPaywallsIsMustUpdate, selectPaywalls } from "./paywalls";
import privacyPolicy, { actions as privacyPolicyActions, selectPrivacyPolicy } from "./privacyPolicy"; import privacyPolicy, {
import personalVideo, { actions as personalVideoActions, selectPersonalVideo } from "./personalVideo"; actions as privacyPolicyActions,
import chats, { actions as chatsActions, selectAnswers, selectCurrentStep } from "./chats"; selectPrivacyPolicy,
import chat, { actions as chatActions, selectCurrentAssistant, selectCurrentChatId, selectDateEndChatting, selectIsAutoRefill, selectIsPayedFirstPurchase } from "./chat"; } from "./privacyPolicy";
import personalVideo, {
actions as personalVideoActions,
selectPersonalVideo,
} from "./personalVideo";
import chats, {
actions as chatsActions,
selectAnswers,
selectCurrentStep,
} from "./chats";
import chat, {
actions as chatActions,
selectCurrentAssistant,
selectCurrentChatId,
selectDateEndChatting,
selectIsAutoRefill,
selectIsPayedFirstPurchase,
} from "./chat";
const preloadedState = loadStore(); const preloadedState = loadStore();
export const actions = { export const actions = {

31
src/utils/Theme/index.ts Normal file
View File

@ -0,0 +1,31 @@
import { ESiteTheme } from "@/hooks/theme/useTheme";
export function getSystemColorScheme(): ESiteTheme {
if (typeof window !== "undefined" && window.matchMedia) {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? ESiteTheme.Dark
: ESiteTheme.Light;
}
return ESiteTheme.Light;
}
export function subscribeToSystemThemeChange(
callback: (theme: ESiteTheme) => void
) {
if (typeof window === "undefined" || !window.matchMedia) {
return;
}
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = (e: MediaQueryListEvent) => {
callback(e.matches ? ESiteTheme.Dark : ESiteTheme.Light);
};
mediaQuery.addEventListener("change", handleChange);
return () => {
mediaQuery.removeEventListener("change", handleChange);
};
}