diff --git a/src/components/CompatibilityV2/pages/Gender/index.tsx b/src/components/CompatibilityV2/pages/Gender/index.tsx
index 46b0bf0..d094d25 100644
--- a/src/components/CompatibilityV2/pages/Gender/index.tsx
+++ b/src/components/CompatibilityV2/pages/Gender/index.tsx
@@ -1,9 +1,7 @@
import styles from "./styles.module.scss";
-import Title from "@/components/Title";
import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { Gender } from "@/data";
-import PrivacyPolicy from "@/components/pages/ABDesign/v1/components/PrivacyPolicy";
// import Toast from "@/components/pages/ABDesign/v1/components/Toast";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
@@ -17,10 +15,11 @@ import { usePreloadImages } from "@/hooks/preload/images";
import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie";
import { useSession } from "@/hooks/session/useSession";
import { EGender, ESourceAuthorization } from "@/api/resources/User";
-import AlreadyHaveAccount from "@/components/ui/AlreadyHaveAccount";
-import Answer from "../../components/Answer";
import Loader, { LoaderColor } from "@/components/Loader";
-import { useUnleash } from "@/hooks/ab/unleash/useUnleash";
+import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
+import GenderV0 from "./variants/GenderV0";
+import GenderV1 from "./variants/GenderV1";
+import GenderV2 from "./variants/GenderV2";
function GenderPage() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@@ -41,7 +40,7 @@ function GenderPage() {
const { flags, ready } = useMetricABFlags();
const { isReady, variant: genderPageType } = useUnleash({
- flag: "genderPageType"
+ flag: EUnleashFlags.genderPageType
});
const pageType = flags?.genderPageType?.[0] || genderPageType || "v2";
@@ -115,142 +114,19 @@ function GenderPage() {
switch (pageType) {
case "v0":
return (
- <>
-
- {translate("/gender.title")}
-
- {translate("/gender.description", {
- br:
,
- })}
- {/* */}
-
-
- {localGenders.map((_gender, index) => (
-
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
- />
- ))}
-
-
- {/* {gender && !privacyPolicyChecked && (
-
- {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
-
- )} */}
- >
+
)
case "v1":
return (
- <>
-
- {translate("/gender.v1.title", {
- br:
,
- })}
-
- {translate("/gender.v1.subtitle", {
- br:
,
- })}
-
- {Array.from({ length: 4 }).map((_, index) => (
- -
- {translate(`/gender.v1.points.point${index + 1}`)}
-
- ))}
-
- {/* */}
-
- {localGenders.map((_gender, index) => (
-
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
- />
- ))}
-
-
-
- {/* {gender && !privacyPolicyChecked && (
-
- {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
-
- )} */}
- >
+
)
case "v2":
return (
- <>
-
- {translate("/gender.v2.title", {
- br:
,
- })}
-
-
- {Array.from({ length: 5 }).map((_, index) => (
- -
- {translate(`/gender.v2.points.point${index + 1}`)}
-
- ))}
-
- {translate("/gender.v2.subtitle", {
- br:
,
- })}
- {/* */}
-
- {localGenders.map((_gender, index) => (
-
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
- />
- ))}
-
-
-
- {/* {gender && !privacyPolicyChecked && (
-
- {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
-
- )} */}
- >
+
)
default:
return (
- <>
-
- {translate("/gender.title")}
-
- {translate("/gender.description", {
- br:
,
- })}
- {/* */}
-
-
- {localGenders.map((_gender, index) => (
-
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
- />
- ))}
-
-
- {/* {gender && !privacyPolicyChecked && (
-
- {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
-
- )} */}
- >
+
);
}
diff --git a/src/components/CompatibilityV2/pages/Gender/variants/GenderV0/index.tsx b/src/components/CompatibilityV2/pages/Gender/variants/GenderV0/index.tsx
new file mode 100644
index 0000000..87a3221
--- /dev/null
+++ b/src/components/CompatibilityV2/pages/Gender/variants/GenderV0/index.tsx
@@ -0,0 +1,53 @@
+import Title from "@/components/Title"
+import styles from "../../styles.module.scss"
+import { useTranslations } from "@/hooks/translations";
+import { ELocalesPlacement } from "@/locales";
+import PrivacyPolicy from "@/components/pages/ABDesign/v1/components/PrivacyPolicy";
+import { Gender } from "@/data";
+import { genders } from "@/components/pages/ABDesign/v1/data/genders";
+import Answer from "@/components/CompatibilityV2/components/Answer";
+import AlreadyHaveAccount from "@/components/ui/AlreadyHaveAccount";
+
+interface IGenderV0Props {
+ localGenders: Array<{
+ id: string;
+ title: React.ReactNode | string;
+ }>;
+ gender: string;
+ selectGender: (gender: Gender | null) => void;
+}
+
+function GenderV0({ localGenders, gender, selectGender }: IGenderV0Props) {
+ const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
+
+ return (
+ <>
+
+ {translate("/gender.title")}
+
+ {translate("/gender.description", {
+ br:
,
+ })}
+ {/* */}
+
+
+ {localGenders.map((_gender, index) => (
+
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
+ />
+ ))}
+
+
+ {/* {gender && !privacyPolicyChecked && (
+
+ {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
+
+ )} */}
+ >
+ )
+}
+
+export default GenderV0
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/Gender/variants/GenderV1/index.tsx b/src/components/CompatibilityV2/pages/Gender/variants/GenderV1/index.tsx
new file mode 100644
index 0000000..d681987
--- /dev/null
+++ b/src/components/CompatibilityV2/pages/Gender/variants/GenderV1/index.tsx
@@ -0,0 +1,62 @@
+import Title from "@/components/Title"
+import styles from "../../styles.module.scss"
+import { useTranslations } from "@/hooks/translations";
+import { ELocalesPlacement } from "@/locales";
+import PrivacyPolicy from "@/components/pages/ABDesign/v1/components/PrivacyPolicy";
+import { Gender } from "@/data";
+import { genders } from "@/components/pages/ABDesign/v1/data/genders";
+import Answer from "@/components/CompatibilityV2/components/Answer";
+import AlreadyHaveAccount from "@/components/ui/AlreadyHaveAccount";
+
+interface IGenderV1Props {
+ localGenders: Array<{
+ id: string;
+ title: React.ReactNode | string;
+ }>;
+ gender: string;
+ selectGender: (gender: Gender | null) => void;
+}
+
+function GenderV1({ localGenders, gender, selectGender }: IGenderV1Props) {
+ const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
+
+ return (
+ <>
+
+ {translate("/gender.v1.title", {
+ br:
,
+ })}
+
+ {translate("/gender.v1.subtitle", {
+ br:
,
+ })}
+
+ {Array.from({ length: 4 }).map((_, index) => (
+ -
+ {translate(`/gender.v1.points.point${index + 1}`)}
+
+ ))}
+
+ {/* */}
+
+ {localGenders.map((_gender, index) => (
+
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
+ />
+ ))}
+
+
+
+ {/* {gender && !privacyPolicyChecked && (
+
+ {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
+
+ )} */}
+ >
+ )
+}
+
+export default GenderV1
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/Gender/variants/GenderV2/index.tsx b/src/components/CompatibilityV2/pages/Gender/variants/GenderV2/index.tsx
new file mode 100644
index 0000000..6595f4b
--- /dev/null
+++ b/src/components/CompatibilityV2/pages/Gender/variants/GenderV2/index.tsx
@@ -0,0 +1,67 @@
+import Title from "@/components/Title"
+import styles from "../../styles.module.scss"
+import { useTranslations } from "@/hooks/translations";
+import { ELocalesPlacement } from "@/locales";
+import PrivacyPolicy from "@/components/pages/ABDesign/v1/components/PrivacyPolicy";
+import { Gender } from "@/data";
+import { genders } from "@/components/pages/ABDesign/v1/data/genders";
+import Answer from "@/components/CompatibilityV2/components/Answer";
+import AlreadyHaveAccount from "@/components/ui/AlreadyHaveAccount";
+
+interface IGenderV2Props {
+ localGenders: Array<{
+ id: string;
+ title: React.ReactNode | string;
+ }>;
+ gender: string;
+ selectGender: (gender: Gender | null) => void;
+}
+
+function GenderV2({ localGenders, gender, selectGender }: IGenderV2Props) {
+ const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
+
+ return (
+ <>
+
+ {translate("/gender.v2.title", {
+ br:
,
+ })}
+
+
+ {Array.from({ length: 5 }).map((_, index) => (
+ -
+ {translate(`/gender.v2.points.point${index + 1}`)}
+
+ ))}
+
+ {translate("/gender.v2.subtitle", {
+ br:
,
+ })}
+ {/* */}
+
+ {localGenders.map((_gender, index) => (
+
selectGender(genders.find((g) => g.id === _gender.id) ?? null)}
+ />
+ ))}
+
+
+
+ {/* {gender && !privacyPolicyChecked && (
+
+ {translate("/gender.toast", undefined, ELocalesPlacement.V1)}
+
+ )} */}
+ >
+ )
+}
+
+export default GenderV2
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/PalmsInformation/index.tsx b/src/components/CompatibilityV2/pages/PalmsInformation/index.tsx
index 7f6f85d..872f829 100644
--- a/src/components/CompatibilityV2/pages/PalmsInformation/index.tsx
+++ b/src/components/CompatibilityV2/pages/PalmsInformation/index.tsx
@@ -12,6 +12,8 @@ import { selectors } from "@/store";
import { useSelector } from "react-redux";
import { images } from "../../data";
import { getZodiacSignByDate } from "@/services/zodiac-sign";
+import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
+import Loader, { LoaderColor } from "@/components/Loader";
function PalmsInformation() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@@ -24,10 +26,18 @@ function PalmsInformation() {
preloadKey: ELottieKeys.scalesHeadPalmistry,
});
+ const { isReady, variant: zodiacImages } = useUnleash({
+ flag: EUnleashFlags.zodiacImages
+ });
+
const handleNext = () => {
navigate(routes.client.compatibilityV2RelationshipStatus());
};
+ if (!isReady) {
+ return ;
+ }
+
return (
{/* {animationData && (
@@ -39,13 +49,25 @@ function PalmsInformation() {
width={1920}
/>
)} */}
-
-
}.webp`)})
-
+ {zodiacImages !== "new" && (
+
+
}.webp`)})
+
+ )}
+ {zodiacImages === "new" && (
+
+
}.webp`)})
+
+ )}
{translate(`/palms-information.${zodiacSign.toLowerCase()}.title`)}
diff --git a/src/components/CompatibilityV2/pages/PalmsInformation/styles.module.scss b/src/components/CompatibilityV2/pages/PalmsInformation/styles.module.scss
index bd40adf..650127f 100644
--- a/src/components/CompatibilityV2/pages/PalmsInformation/styles.module.scss
+++ b/src/components/CompatibilityV2/pages/PalmsInformation/styles.module.scss
@@ -56,4 +56,19 @@
.description {
white-space: pre-line;
margin-bottom: 24px;
+}
+
+.zodiacNew {
+ position: relative;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ & > img {
+ height: 100%;
+ position: relative;
+ max-width: 260px;
+ z-index: -2;
+ }
}
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/PalmsInformationPartner/index.tsx b/src/components/CompatibilityV2/pages/PalmsInformationPartner/index.tsx
index b493506..92b131d 100644
--- a/src/components/CompatibilityV2/pages/PalmsInformationPartner/index.tsx
+++ b/src/components/CompatibilityV2/pages/PalmsInformationPartner/index.tsx
@@ -11,11 +11,13 @@ import { selectors } from "@/store";
import { useSelector } from "react-redux";
import { images } from "../../data";
import { getZodiacSignByDate } from "@/services/zodiac-sign";
+import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
+import Loader, { LoaderColor } from "@/components/Loader";
function PalmsInformationPartner() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
const { partnerGender, partnerBirthdate } = useSelector(selectors.selectQuestionnaire);
-
+
const zodiacSign = getZodiacSignByDate(partnerBirthdate);
const navigate = useNavigate();
// const { animationData } =
@@ -24,10 +26,18 @@ function PalmsInformationPartner() {
preloadKey: ELottieKeys.scalesHeadPalmistry,
});
+ const { isReady, variant: zodiacImages } = useUnleash({
+ flag: EUnleashFlags.zodiacImages
+ });
+
const handleNext = () => {
navigate(routes.client.compatibilityV2DateEvent());
};
+ if (!isReady) {
+ return
;
+ }
+
return (
{/* {animationData && (
@@ -39,13 +49,25 @@ function PalmsInformationPartner() {
width={1920}
/>
)} */}
-
-
}.webp`)})
-
+ {zodiacImages !== "new" && (
+
+
}.webp`)})
+
+ )}
+ {zodiacImages === "new" && (
+
+
}.webp`)})
+
+ )}
{translate(`/palms-information-partner.${zodiacSign?.toLowerCase()}.title`)}
diff --git a/src/components/CompatibilityV2/pages/PalmsInformationPartner/styles.module.scss b/src/components/CompatibilityV2/pages/PalmsInformationPartner/styles.module.scss
index bd40adf..650127f 100644
--- a/src/components/CompatibilityV2/pages/PalmsInformationPartner/styles.module.scss
+++ b/src/components/CompatibilityV2/pages/PalmsInformationPartner/styles.module.scss
@@ -56,4 +56,19 @@
.description {
white-space: pre-line;
margin-bottom: 24px;
+}
+
+.zodiacNew {
+ position: relative;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ & > img {
+ height: 100%;
+ position: relative;
+ max-width: 260px;
+ z-index: -2;
+ }
}
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/index.tsx b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/index.tsx
new file mode 100644
index 0000000..af16b69
--- /dev/null
+++ b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/index.tsx
@@ -0,0 +1,39 @@
+import styles from "./styles.module.scss"
+
+interface ZodiacImagesProps {
+ gender: string;
+ partnerGender?: string;
+ zodiacSign: string;
+ partnerZodiacSign?: string;
+ relationshipStatus: string;
+ classNameContainer?: string;
+}
+
+function ZodiacImages({
+ gender,
+ partnerGender,
+ zodiacSign,
+ partnerZodiacSign,
+ relationshipStatus,
+ classNameContainer = ""
+}: ZodiacImagesProps) {
+
+ const getZodiacImagesWithPartnerClassName = () => {
+ if (relationshipStatus === "single") {
+ return "";
+ }
+ return `${styles["with-partner"]} ${styles[`with-partner-${gender}-${partnerGender}`]}`;
+ }
+
+ return (
+
+
}/${zodiacSign?.toLowerCase()}.svg`})
+ {relationshipStatus !== "single" &&
}/${partnerZodiacSign?.toLowerCase()}.svg`})
}
+
+ )
+}
+
+export default ZodiacImages
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss
new file mode 100644
index 0000000..36ecaad
--- /dev/null
+++ b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss
@@ -0,0 +1,66 @@
+.zodiac-images {
+ position: relative;
+ width: 100dvw;
+ max-width: 560px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 0px;
+ margin-top: 8px;
+
+ &.with-partner {
+ // &>img:first-child {
+ // margin-right: -30%;
+ // }
+
+ &>img:last-child {
+ // margin-left: -10px;
+ z-index: 2;
+ }
+
+ &>img {
+ width: 50%;
+ }
+ }
+
+ img {
+ position: relative;
+ width: 70%;
+ object-fit: cover;
+ z-index: 3;
+ }
+
+ &.with-partner-male-female {
+ flex-direction: row-reverse;
+ }
+
+ &.with-partner-male-male {
+ &>img:first-child {
+ transform: scaleX(-1);
+ }
+ }
+
+ &.with-partner-female-female {
+ &>img:last-child {
+ transform: scaleX(-1);
+ }
+ }
+
+ // &::after {
+ // content: "";
+ // position: absolute;
+ // bottom: 0;
+ // left: 0;
+ // width: 100%;
+ // height: 60%;
+ // background: linear-gradient(to bottom,
+ // rgba(255, 255, 255, 0) 0%,
+ // rgba(255, 255, 255, .7) 10%,
+ // rgba(255, 255, 255, 1) 15%,
+ // rgba(255, 255, 255, 1) 30%,
+ // rgba(255, 255, 255, 1) 40%,
+ // rgba(255, 255, 255, 1) 100%);
+ // pointer-events: none;
+ // z-index: -1;
+ // }
+}
\ No newline at end of file
diff --git a/src/components/CompatibilityV2/pages/TrialPayment/index.tsx b/src/components/CompatibilityV2/pages/TrialPayment/index.tsx
index 1ef00b2..8f23bfc 100644
--- a/src/components/CompatibilityV2/pages/TrialPayment/index.tsx
+++ b/src/components/CompatibilityV2/pages/TrialPayment/index.tsx
@@ -24,6 +24,9 @@ import { formatDateToLocale } from "@/locales/localFormats";
import { useEffect } from "react";
import metricService, { EGoals, EMetrics } from "@/services/metric/metricService";
import MoneyBackGuarantee from "../../components/MoneyBackGuarantee";
+import ZodiacImages from "./components/ZodiacImages";
+import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
+import Loader, { LoaderColor } from "@/components/Loader";
function TrialPayment() {
const { height, elementRef } = useDynamicSize
({});
@@ -41,6 +44,10 @@ function TrialPayment() {
"/v1/palmistry/ticket.svg",
])
+ const { isReady, variant: zodiacImages } = useUnleash({
+ flag: EUnleashFlags.zodiacImages
+ });
+
const handleNext = () => {
navigate(routes.client.compatibilityV2Payment());
};
@@ -50,19 +57,31 @@ function TrialPayment() {
metricService.reachGoal(EGoals.AURA_TRIAL_PAYMENT_PAGE_VISIT, [EMetrics.KLAVIYO]);
}, []);
+ if (!isReady) {
+ return ;
+ }
+
return (
<>
{translate("/trial-payment.information-title")}
- }
+ {zodiacImages !== "new" &&
}.webp`)})
{relationshipStatus !== "single" &&
}.webp`)})
}
-
+ }
{(relationshipStatus === "single" || !partnerBirthdate) &&
{translate("/trial-payment.information-description-single", {
diff --git a/src/hooks/ab/unleash/useUnleash.ts b/src/hooks/ab/unleash/useUnleash.ts
index b020b56..477c3a9 100644
--- a/src/hooks/ab/unleash/useUnleash.ts
+++ b/src/hooks/ab/unleash/useUnleash.ts
@@ -1,25 +1,51 @@
import { useFlagsStatus, useUnleashClient, useVariant } from "@unleash/proxy-client-react";
import { useEffect, useMemo } from "react";
+import { useSearchParams } from "react-router-dom";
-interface IUseUnleashProps {
- flag: string;
+export enum EUnleashFlags {
+ "genderPageType" = "genderPageType",
+ "zodiacImages" = "zodiacImages",
}
-export const useUnleash = ({
+/**
+ * Интерфейс для входных параметров хука useUnleash
+ * Использует дженерик T для типизации флага
+ */
+interface IUseUnleashProps {
+ flag: T;
+}
+
+/**
+ * Интерфейс для возможных вариантов значений флагов
+ * Каждый ключ соответствует флагу из EUnleashFlags
+ */
+interface IVariants {
+ [EUnleashFlags.genderPageType]: "v0" | "v1" | "v2";
+ [EUnleashFlags.zodiacImages]: "new" | "old";
+}
+
+/**
+ * Хук для получения значения A/B теста по флагу
+ * @template T - Тип флага из EUnleashFlags
+ * @returns Объект с информацией о готовности флага и его значении, типизированным в зависимости от переданного флага
+ */
+export const useUnleash = ({
flag
-}: IUseUnleashProps) => {
+}: IUseUnleashProps) => {
const { flagsReady } = useFlagsStatus();
const unleashClient = useUnleashClient();
const abVariant = useVariant(flag);
// const isEnabled = useFlag(flag);
+ const [searchParams] = useSearchParams();
+ const variantFromParams = searchParams.get(flag);
const isReady = useMemo(() => {
return flagsReady ?? true;
}, [flagsReady]);
const variant = useMemo(() => {
- return abVariant?.payload?.value;
- }, [abVariant]);
+ return variantFromParams || abVariant?.payload?.value;
+ }, [abVariant, variantFromParams]) as IVariants[T];
useEffect(() => {
unleashClient.on("impression", (impressionEvent: any) => {
@@ -43,5 +69,5 @@ export const useUnleash = ({
}), [
isReady,
variant
- ])
+ ]) as { isReady: boolean; variant: IVariants[T] };
};
\ No newline at end of file