diff --git a/public/locales/v1/en/male_en.json b/public/locales/v1/en/male_en.json index e56bf47..445a62b 100644 --- a/public/locales/v1/en/male_en.json +++ b/public/locales/v1/en/male_en.json @@ -7,7 +7,6 @@ "day": "Day", "year": "Year", "month": "Month", - "aura_paywall_redesign_main": { "text_0": "We've helped millions of people to have happier lives and better relationships, and we want to help you too.", "text_0_color": "millions", @@ -120,11 +119,14 @@ }, "payment_modal": { "title": "Choose payment method", + "title1": "Payment method", "credit_card": "Credit Card", "price_for_days": " for your -day trial", "email_reminder": "We`ll email you a reminder", "description": "You will be charged only . \n before your trial period ends. \nCancel anytime. The charge will appear on your bill as witapps.", - "address": "2108 N ST STE 5446 SACRAMENTO, CA 95816" + "address": "2108 N ST STE 5446 SACRAMENTO, CA 95816", + "form_error": "Проверьте правильность заполнения формы", + "price_information": "A charge" }, "add_report": "Add Report", "unlimited_readings": "Unlimited Readings", @@ -499,7 +501,6 @@ "title7": "Analyzing relationship needs...", "title8": "Charting best guidance plan...", "title9": "Predicting future results...", - "popup": { "title1": "Do you enjoy time spent alone?", "title2": "Are you adventurous person?", @@ -510,7 +511,6 @@ "personality_traits": "Personality traits", "relationship_pattern": "Relationship Pattern" }, - "description": "Sit tight! We`re building your perfect guidance plane based on your unique astrological blueprint and data of millions users." }, "/email": { @@ -716,4 +716,4 @@ "unlock_profound": "Unlock profound insights into your personality, relationships, career trajectory, and life's pivotal moments through astrology, empowering you to make informed decisions and achieve greater fulfillment.", "choose_from": "Choose from 80+ experts astrologers." } -} +} \ No newline at end of file diff --git a/src/components/CompatibilityV2/pages/Camera/index.tsx b/src/components/CompatibilityV2/pages/Camera/index.tsx index e6052ca..839a92c 100644 --- a/src/components/CompatibilityV2/pages/Camera/index.tsx +++ b/src/components/CompatibilityV2/pages/Camera/index.tsx @@ -17,6 +17,7 @@ import CameraModal from "../../components/CameraModal"; import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import Modal from "@/components/Modal"; import Title from "@/components/Title"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; const isProduction = import.meta.env.MODE === "production"; @@ -47,10 +48,17 @@ function Camera() { const [isLoading, setIsLoading] = useState(false); const [uploadMenuModalIsOpen, setUploadMenuModalIsOpen] = useState(false); const [toastVisible, setToastVisible] = useState(null); - const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState(isIphoneSafari ? false : true); const [cameraKey, setCameraKey] = useState(0); const [isCameraModalOpen, setIsCameraModalOpen] = useState(false); + const { isReady, variant: cameraRequestModalCompatibilityV2 } = useUnleash({ + flag: EUnleashFlags.cameraRequestModalCompatibilityV2 + }); + + const isCameraRequestModal = cameraRequestModalCompatibilityV2 !== "hide"; + + const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState((isIphoneSafari || !isCameraRequestModal) ? false : true); + const handleNext = () => { metricService.reachGoal(EGoals.CAMERA_SUCCESS, [EMetrics.YANDEX, EMetrics.KLAVIYO]); navigate(routes.client.compatibilityV2ScannedPhoto()); @@ -185,7 +193,7 @@ function Camera() { const cameraError = (error: string | DOMException) => { console.error("Camera error", error) - if (!isIphoneSafari) return; + if (!isIphoneSafari || !isCameraRequestModal) return; if (error === "Video is not ready") { return setToastVisible(EToastVisible.no_access_camera) } @@ -210,6 +218,8 @@ function Camera() { } }; + if (!isReady) return ; + return ( <> console.log("close")} onTakePhoto={onTakePhoto} onError={cameraError} - isCameraVisible={isIphoneSafari ? true : isCameraModalOpen} + isCameraVisible={(isIphoneSafari || isCameraRequestModal) ? true : isCameraModalOpen} reinitializeKey={cameraKey} /> )} diff --git a/src/components/CompatibilityV2/pages/ScannedPhoto/index.tsx b/src/components/CompatibilityV2/pages/ScannedPhoto/index.tsx index 3f6a93c..1a2bc55 100644 --- a/src/components/CompatibilityV2/pages/ScannedPhoto/index.tsx +++ b/src/components/CompatibilityV2/pages/ScannedPhoto/index.tsx @@ -14,6 +14,7 @@ import ProgressBarLine from "@/components/ui/ProgressBarLine"; import Modal from "@/components/Modal"; import { useAuthentication } from "@/hooks/authentication/use-authentication"; import { ESourceAuthorization } from "@/api/resources/User"; +import { getRandomArbitrary } from "@/services/random-value"; const drawElementChangeDelay = 1500; const startDelay = 500; @@ -175,6 +176,15 @@ function ScannedPhoto() { const [isPause, setIsPause] = useState(false); const interval = useRef(); + const loadingPointSettings = useMemo(() => { + const currentPointIndex = Math.floor(progress / 100); + const endFastLoading = getRandomArbitrary(15, 30); + const startFastLoading = getRandomArbitrary(70, 85); + const pauseLoading = getRandomArbitrary(40, 60); + + return { endFastLoading, pauseLoading, startFastLoading, currentPointIndex }; + }, [Math.floor(progress / 100)]) + const getProgressValue = useCallback( (index: number) => { const integerDivision = Math.floor(progress / 100); @@ -206,7 +216,24 @@ function ScannedPhoto() { } }, [progress]); + + const getLoadingTime = useCallback((progress: number) => { + const progressOfCurrentPoint = progress % 100; + + if (progressOfCurrentPoint < loadingPointSettings.endFastLoading) { + return 40; + } + if (progressOfCurrentPoint > loadingPointSettings.startFastLoading) { + return 40; + } + if (progressOfCurrentPoint === loadingPointSettings.pauseLoading) { + return 3000; + } + return 100 + }, [Math.floor(progress / 100)]); + useEffect(() => { + const loadingTime = getLoadingTime(progress); if (progress >= loadingProfilePoints.length * 100) { return onEndLoading(); } @@ -215,7 +242,7 @@ function ScannedPhoto() { if (!isPause && !isDecorationShown) return prevProgress + 1; return prevProgress; }); - }, 100); + }, loadingTime); return () => { clearTimeout(interval.current); }; diff --git a/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss index 36ecaad..643560e 100644 --- a/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss +++ b/src/components/CompatibilityV2/pages/TrialPayment/components/ZodiacImages/styles.module.scss @@ -3,12 +3,13 @@ width: 100dvw; max-width: 560px; display: flex; - justify-content: space-between; + justify-content: center; align-items: center; gap: 0px; margin-top: 8px; &.with-partner { + justify-content: space-between; // &>img:first-child { // margin-right: -30%; // } diff --git a/src/components/CompatibilityV2/pages/TrialPayment/index.tsx b/src/components/CompatibilityV2/pages/TrialPayment/index.tsx index 8f23bfc..eb5f78a 100644 --- a/src/components/CompatibilityV2/pages/TrialPayment/index.tsx +++ b/src/components/CompatibilityV2/pages/TrialPayment/index.tsx @@ -44,11 +44,18 @@ function TrialPayment() { "/v1/palmistry/ticket.svg", ]) + const { variant: pageAfterTrialPaymentCompatibilityV2 } = useUnleash({ + flag: EUnleashFlags.pageAfterTrialPaymentCompatibilityV2 + }); + const { isReady, variant: zodiacImages } = useUnleash({ flag: EUnleashFlags.zodiacImages }); const handleNext = () => { + if (pageAfterTrialPaymentCompatibilityV2 === "paymentForm") { + return navigate(routes.client.compatibilityV2PaymentModal()); + } navigate(routes.client.compatibilityV2Payment()); }; diff --git a/src/components/CompatibilityV3/pages/ScannedPhoto/index.tsx b/src/components/CompatibilityV3/pages/ScannedPhoto/index.tsx index f5e9575..c54ce69 100644 --- a/src/components/CompatibilityV3/pages/ScannedPhoto/index.tsx +++ b/src/components/CompatibilityV3/pages/ScannedPhoto/index.tsx @@ -17,6 +17,7 @@ import { ESourceAuthorization } from "@/api/resources/User"; import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie"; import { DotLottieReact } from "@lottiefiles/dotlottie-react"; import { useMetricABFlags } from "@/services/metric/metricService"; +import { getRandomArbitrary } from "@/services/random-value"; // const drawElementChangeDelay = 1500; // const startDelay = 500; @@ -177,6 +178,15 @@ function ScannedPhoto() { const [isPause, setIsPause] = useState(false); const interval = useRef(); + const loadingPointSettings = useMemo(() => { + const currentPointIndex = Math.floor(progress / 100); + const endFastLoading = getRandomArbitrary(15, 30); + const startFastLoading = getRandomArbitrary(70, 85); + const pauseLoading = getRandomArbitrary(40, 60); + + return { endFastLoading, pauseLoading, startFastLoading, currentPointIndex }; + }, [Math.floor(progress / 100)]) + const getProgressValue = useCallback( (index: number) => { const integerDivision = Math.floor(progress / 100); @@ -211,23 +221,33 @@ function ScannedPhoto() { } }, [progress]); + const getLoadingTime = useCallback((progress: number) => { + const progressOfCurrentPoint = progress % 100; + + if (progressOfCurrentPoint < loadingPointSettings.endFastLoading) { + return 40; + } + if (progressOfCurrentPoint > loadingPointSettings.startFastLoading) { + return 40; + } + if (progressOfCurrentPoint === loadingPointSettings.pauseLoading) { + return 3000; + } + return 100 + }, [Math.floor(progress / 100)]); + useEffect(() => { + const loadingTime = getLoadingTime(progress); if (progress >= loadingProfilePoints.length * 100) { return onEndLoading(); } - const getDelay = () => { - if (progress < 15) return 50; - if (progress === 15) return 2500; - return 100; - } - interval.current = setTimeout(() => { setProgress((prevProgress) => { if (!isPause && !isDecorationShown) return prevProgress + 1; return prevProgress; }); - }, getDelay()); + }, loadingTime); return () => { clearTimeout(interval.current); diff --git a/src/components/CompatibilityV3/pages/TrialPayment/index.tsx b/src/components/CompatibilityV3/pages/TrialPayment/index.tsx index ffbc61b..df98c3a 100644 --- a/src/components/CompatibilityV3/pages/TrialPayment/index.tsx +++ b/src/components/CompatibilityV3/pages/TrialPayment/index.tsx @@ -24,6 +24,8 @@ import { formatDateToLocale } from "@/locales/localFormats"; import { useEffect } from "react"; import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import MoneyBackGuarantee from "../../components/MoneyBackGuarantee"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; +import Loader, { LoaderColor } from "@/components/Loader"; function TrialPayment() { const { height, elementRef } = useDynamicSize({}); @@ -41,7 +43,14 @@ function TrialPayment() { "/v1/palmistry/ticket.svg", ]) + const { isReady, variant: pageAfterTrialPaymentCompatibilityV3 } = useUnleash({ + flag: EUnleashFlags.pageAfterTrialPaymentCompatibilityV3 + }); + const handleNext = () => { + if (pageAfterTrialPaymentCompatibilityV3 === "paymentForm") { + return navigate(routes.client.compatibilityV3PaymentModal()); + } navigate(routes.client.compatibilityV3Payment()); }; @@ -50,6 +59,10 @@ function TrialPayment() { metricService.reachGoal(EGoals.AURA_TRIAL_PAYMENT_PAGE_VISIT, [EMetrics.KLAVIYO]); }, []); + if (!isReady) { + return ; + } + return ( <> diff --git a/src/components/CompatibilityV3/pages/TryApp/components/ZodiacImages/styles.module.scss b/src/components/CompatibilityV3/pages/TryApp/components/ZodiacImages/styles.module.scss index 65a6491..0cd7b55 100644 --- a/src/components/CompatibilityV3/pages/TryApp/components/ZodiacImages/styles.module.scss +++ b/src/components/CompatibilityV3/pages/TryApp/components/ZodiacImages/styles.module.scss @@ -2,12 +2,13 @@ position: relative; width: 100dvw; display: flex; - justify-content: space-between; + justify-content: center; align-items: center; gap: 0px; margin-top: 8px; &.with-partner { + justify-content: space-between; // &>img:first-child { // margin-right: -30%; // } diff --git a/src/components/DateTimePicker/styles.css b/src/components/DateTimePicker/styles.css index 2b0a18f..2615853 100644 --- a/src/components/DateTimePicker/styles.css +++ b/src/components/DateTimePicker/styles.css @@ -35,6 +35,12 @@ padding-top: 5px; } +.dark-theme .date-picker__field > select { + background: #343639; + border: 2px solid #54689F; + color: #F7F7F7; +} + .date-picker__field-label { color: #6b7baa; font-size: 12px; @@ -42,6 +48,10 @@ margin: 0 0 6px 6px; } +.dark-theme .date-picker__field-label { + color: #8DA4EA; +} + .date-picker__input { display: block; font-size: 16px; diff --git a/src/components/PalmistryV1/components/Answer/styles.module.scss b/src/components/PalmistryV1/components/Answer/styles.module.scss index 4fdc96e..09815b9 100644 --- a/src/components/PalmistryV1/components/Answer/styles.module.scss +++ b/src/components/PalmistryV1/components/Answer/styles.module.scss @@ -24,3 +24,8 @@ // transform: scale(1.03); } } + +:global(.dark-theme) .container { + background-color: #343639; + color: #F7F7F7; +} \ No newline at end of file diff --git a/src/components/PalmistryV1/images/SVG/ScanInstruction/index.tsx b/src/components/PalmistryV1/images/SVG/ScanInstruction/index.tsx index b435c49..727bea3 100644 --- a/src/components/PalmistryV1/images/SVG/ScanInstruction/index.tsx +++ b/src/components/PalmistryV1/images/SVG/ScanInstruction/index.tsx @@ -1,6 +1,9 @@ +import styles from "./styles.module.scss"; + function ScanInstructionSVG() { return ( <svg + className={styles.svg} width="355" height="339" viewBox="0 0 355 339" diff --git a/src/components/PalmistryV1/images/SVG/ScanInstruction/styles.module.scss b/src/components/PalmistryV1/images/SVG/ScanInstruction/styles.module.scss new file mode 100644 index 0000000..f67c71d --- /dev/null +++ b/src/components/PalmistryV1/images/SVG/ScanInstruction/styles.module.scss @@ -0,0 +1,11 @@ +:global(.dark-theme) .svg { + &>rect { + stroke: #DCDCDC; + } + + &>rect:first-child { + stroke: none; + fill: #2D2D34; + fill-opacity: 1; + } +} \ No newline at end of file diff --git a/src/components/PalmistryV1/pages/Camera/index.tsx b/src/components/PalmistryV1/pages/Camera/index.tsx index 13ac262..d4d4e14 100644 --- a/src/components/PalmistryV1/pages/Camera/index.tsx +++ b/src/components/PalmistryV1/pages/Camera/index.tsx @@ -14,9 +14,10 @@ import Toast from "@/components/pages/ABDesign/v1/components/Toast"; import { useTranslations } from "@/hooks/translations"; import { ELocalesPlacement } from "@/locales"; import CameraModal from "../../components/CameraModal"; -import metricService, { EGoals, EMetrics, useMetricABFlags } from "@/services/metric/metricService"; +import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import Modal from "@/components/Modal"; import Title from "@/components/Title"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; const isProduction = import.meta.env.MODE === "production"; @@ -50,8 +51,16 @@ function Camera() { const [cameraKey, setCameraKey] = useState(0); const [isCameraModalOpen, setIsCameraModalOpen] = useState(false); - const { flags, ready } = useMetricABFlags(); - const isCameraRequestModal = flags?.cameraRequestModal?.[0] !== "without"; + // const { flags, ready } = useMetricABFlags(); + + const { isReady, variant: cameraRequestModalPalmistryV1 } = useUnleash({ + flag: EUnleashFlags.cameraRequestModalPalmistryV1 + }); + + // const isCameraRequestModal = flags?.cameraRequestModal?.[0] !== "without"; + + const isCameraRequestModal = cameraRequestModalPalmistryV1 !== "hide"; + const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState((isIphoneSafari || !isCameraRequestModal) ? false : true); const handleNext = () => { @@ -213,7 +222,7 @@ function Camera() { } }; - if (!ready) return null; + if (!isReady) return <Loader color={LoaderColor.Black} />; return ( <> diff --git a/src/components/PalmistryV1/pages/Camera/styles.module.scss b/src/components/PalmistryV1/pages/Camera/styles.module.scss index bea602f..3112b74 100644 --- a/src/components/PalmistryV1/pages/Camera/styles.module.scss +++ b/src/components/PalmistryV1/pages/Camera/styles.module.scss @@ -56,6 +56,7 @@ .modal-container { max-width: 290px; padding: 24px 0px 0px; + overflow: hidden; &>.modal-title { @@ -85,4 +86,8 @@ } } } -} \ No newline at end of file +} + +:global(.dark-theme) .modal-container { + background-color: #343639; +} diff --git a/src/components/PalmistryV1/pages/Email/index.tsx b/src/components/PalmistryV1/pages/Email/index.tsx index a072421..6f48bf8 100644 --- a/src/components/PalmistryV1/pages/Email/index.tsx +++ b/src/components/PalmistryV1/pages/Email/index.tsx @@ -119,6 +119,7 @@ function Email() { name="email" value={email} placeholder={translate("/email.placeholder_email")} + placeholderClassName={styles["input-placeholder"]} inputClassName={styles.input} onValid={handleValidEmail} onInvalid={() => setIsValidEmail(false)} @@ -127,6 +128,7 @@ function Email() { value={name} placeholder={translate("/email.placeholder_name")} inputClassName={styles.input} + placeholderClassName={styles["input-placeholder"]} onValid={handleValidName} onInvalid={() => setIsValidName(true)} /> diff --git a/src/components/PalmistryV1/pages/Email/styles.module.scss b/src/components/PalmistryV1/pages/Email/styles.module.scss index da86796..16d9501 100644 --- a/src/components/PalmistryV1/pages/Email/styles.module.scss +++ b/src/components/PalmistryV1/pages/Email/styles.module.scss @@ -9,6 +9,15 @@ min-height: 60px; } +:global(.dark-theme) .input { + background-color: #343639; + color: #F7F7F7; +} + +:global(.dark-theme) .input-placeholder { + color: #B3B3B3; +} + .not-share { padding-top: 5px; font-size: 20px; diff --git a/src/components/PalmistryV1/pages/FindHappiness/index.tsx b/src/components/PalmistryV1/pages/FindHappiness/index.tsx index c30667d..664b443 100644 --- a/src/components/PalmistryV1/pages/FindHappiness/index.tsx +++ b/src/components/PalmistryV1/pages/FindHappiness/index.tsx @@ -10,7 +10,8 @@ import { useEffect } from "react"; import { actions } from "@/store"; // import StarSVG from "../../images/SVG/Star"; import { usePreloadImages } from "@/hooks/preload/images"; -import { useMetricABFlags } from "@/services/metric/metricService"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; +import Loader, { LoaderColor } from "@/components/Loader"; function FindHappiness() { const navigate = useNavigate(); @@ -18,8 +19,14 @@ function FindHappiness() { const location = useLocation(); const { translate } = useTranslations(ELocalesPlacement.PalmistryV1); usePreloadImages(["/male-gender.webp", "/female-gender.webp"]); - const { flags, ready } = useMetricABFlags(); - const imageType = flags?.welcomePageImage?.[0]; + // const { flags, ready } = useMetricABFlags(); + // const imageType = flags?.welcomePageImage?.[0]; + + const { isReady, variant: welcomePageImagePalmistryV1 } = useUnleash({ + flag: EUnleashFlags.welcomePageImagePalmistryV1 + }) + + const imageType = welcomePageImagePalmistryV1; const image = imageType === "v1" ? "/hand-with-lines-v1.png" : "/hand-with-lines.png"; @@ -33,7 +40,7 @@ function FindHappiness() { } }, [dispatch, location.pathname]); - if (!ready) return null; + if (!isReady) return <Loader color={LoaderColor.Black} />; return ( <> diff --git a/src/components/PalmistryV1/pages/HeadOrHeartResult/index.tsx b/src/components/PalmistryV1/pages/HeadOrHeartResult/index.tsx index 7e15a8a..21879bb 100644 --- a/src/components/PalmistryV1/pages/HeadOrHeartResult/index.tsx +++ b/src/components/PalmistryV1/pages/HeadOrHeartResult/index.tsx @@ -56,10 +56,10 @@ function HeadOrHeartResult() { {headOrHeart === "both" && translate("/both.title", { wonderful: ( - <b style={{ color: "#224e90" }}>{translate("/both.wonderful")}</b> + <b className={styles.highlite}>{translate("/both.wonderful")}</b> ), zodiacSign: ( - <b style={{ color: "#224e90" }}> + <b className={styles.highlite}> {translate(`zodiac_signs.${zodiacSign?.toLowerCase()}`)} </b> ), @@ -68,7 +68,7 @@ function HeadOrHeartResult() { {headOrHeart === "head" && translate("/with-head.title", { zodiacSign: ( - <b style={{ color: "#224e90" }}> + <b className={styles.highlite}> {translate(`zodiac_signs.${zodiacSign?.toLowerCase()}`)} </b> ), @@ -77,7 +77,7 @@ function HeadOrHeartResult() { {headOrHeart === "heart" && translate("/with-heart.title", { zodiacSign: ( - <b style={{ color: "#224e90" }}> + <b className={styles.highlite}> {translate(`zodiac_signs.${zodiacSign?.toLowerCase()}`)} </b> ), @@ -86,7 +86,7 @@ function HeadOrHeartResult() { {headOrHeart === "depends" && translate("/depends.title", { zodiacSign: ( - <b style={{ color: "#224e90" }}> + <b className={styles.highlite}> {translate(`zodiac_signs.${zodiacSign?.toLowerCase()}`)} </b> ), diff --git a/src/components/PalmistryV1/pages/HeadOrHeartResult/styles.module.scss b/src/components/PalmistryV1/pages/HeadOrHeartResult/styles.module.scss index 1923935..984e7d7 100644 --- a/src/components/PalmistryV1/pages/HeadOrHeartResult/styles.module.scss +++ b/src/components/PalmistryV1/pages/HeadOrHeartResult/styles.module.scss @@ -9,7 +9,7 @@ justify-content: space-between; padding-top: 24px; - & > .button { + &>.button { width: 48%; min-width: 0px; font-size: 23px; @@ -27,3 +27,18 @@ .lottie-animation { aspect-ratio: 128 / 82; } + +:global(.dark-theme) .buttons-container { + &>.back-button { + border-color: #F7F7F7; + color: #F7F7F7; + } +} + +.highlite { + color: #224e90; +} + +:global(.dark-theme) .highlite { + color: #4F8DE5; +} \ No newline at end of file diff --git a/src/components/PalmistryV1/pages/ScannedPhoto/index.tsx b/src/components/PalmistryV1/pages/ScannedPhoto/index.tsx index 07af3f4..89a23ca 100644 --- a/src/components/PalmistryV1/pages/ScannedPhoto/index.tsx +++ b/src/components/PalmistryV1/pages/ScannedPhoto/index.tsx @@ -144,7 +144,7 @@ function ScannedPhoto() { drawElements={drawElements} /> <h2 - className="palmistry-container__waiting-title" + className={`palmistry-container__waiting-title ${styles.waitingTitle}`} style={{ animationDelay: `${drawElementChangeDelay * drawElements.length + 2500 }ms`, @@ -154,7 +154,7 @@ function ScannedPhoto() { </h2> <h3 - className="palmistry-container__waiting-description" + className={`palmistry-container__waiting-description ${styles.waitingDescription}`} style={{ animationDelay: `${drawElementChangeDelay * drawElements.length + 3000 }ms`, diff --git a/src/components/PalmistryV1/pages/ScannedPhoto/styles.module.scss b/src/components/PalmistryV1/pages/ScannedPhoto/styles.module.scss index b175e19..68da9e1 100644 --- a/src/components/PalmistryV1/pages/ScannedPhoto/styles.module.scss +++ b/src/components/PalmistryV1/pages/ScannedPhoto/styles.module.scss @@ -92,6 +92,10 @@ } } +:global(.dark-theme) .title { + color: #F7F7F7; +} + .photo-container { width: 100%; height: fit-content; @@ -161,4 +165,12 @@ 100% { stroke-dashoffset: 0; } +} + +:global(.dark-theme) .waitingTitle { + color: #F7F7F7; +} + +:global(.dark-theme) .waitingDescription { + color: #F7F7F7; } \ No newline at end of file diff --git a/src/components/PalmistryV1/pages/TrialPayment/index.tsx b/src/components/PalmistryV1/pages/TrialPayment/index.tsx index 5df25d0..14d9352 100644 --- a/src/components/PalmistryV1/pages/TrialPayment/index.tsx +++ b/src/components/PalmistryV1/pages/TrialPayment/index.tsx @@ -17,6 +17,8 @@ import { usePreloadImages } from "@/hooks/preload/images"; import useTimer from "@/hooks/palmistry/use-timer"; import { useEffect } from "react"; import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; +import Loader, { LoaderColor } from "@/components/Loader"; function TrialPayment() { const { translate } = useTranslations(ELocalesPlacement.PalmistryV1); @@ -26,7 +28,14 @@ function TrialPayment() { "/v1/palmistry/ticket.svg", ]) + const { isReady, variant: pageAfterTrialPaymentPalmistryV1 } = useUnleash({ + flag: EUnleashFlags.pageAfterTrialPaymentPalmistryV1 + }); + const handleNext = () => { + if (pageAfterTrialPaymentPalmistryV1 === "paymentForm") { + return navigate(routes.client.palmistryV1PaymentModal()); + } navigate(routes.client.palmistryV1Payment()); }; @@ -35,6 +44,10 @@ function TrialPayment() { metricService.reachGoal(EGoals.AURA_TRIAL_PAYMENT_PAGE_VISIT, [EMetrics.KLAVIYO]); }, []); + if (!isReady) { + return <Loader color={LoaderColor.Black} />; + } + return ( <> <AppNumberOne /> diff --git a/src/components/Payment/nmi/CheckoutForm/index.tsx b/src/components/Payment/nmi/CheckoutForm/index.tsx index 5bdf588..79e2975 100644 --- a/src/components/Payment/nmi/CheckoutForm/index.tsx +++ b/src/components/Payment/nmi/CheckoutForm/index.tsx @@ -1,9 +1,13 @@ import MainButton from "@/components/MainButton"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import styles from "./styles.module.scss"; import { usePayment } from "@/hooks/payment/nmi/usePayment"; import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall"; import SecurityPayments from "../../SecurityPayments"; +import { useTranslations } from "@/hooks/translations"; +import { ELocalesPlacement } from "@/locales"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; +import Loader, { LoaderColor } from "@/components/Loader"; export type TConfirmType = "payment" | "setup"; @@ -31,6 +35,12 @@ export default function CheckoutForm({ onModalClosed, isHide = false, }: ICheckoutFormProps) { + const { translate } = useTranslations(ELocalesPlacement.V1); + const [payButtonClicked, setPayButtonClicked] = useState(false); + const { variant, isReady } = useUnleash({ + flag: EUnleashFlags.paymentButtonLogic + }); + const isNewPaymentButton = variant === "new"; const { isLoading, @@ -70,12 +80,20 @@ export default function CheckoutForm({ const handleSubmit = (e: React.FormEvent<HTMLFormElement> | React.MouseEvent<HTMLButtonElement>) => { e.preventDefault(); + setPayButtonClicked(true); + if (!isFormValid) { return; } submitInlineForm(); }; + if (!isReady) { + return <div className={styles.loaderContainer}> + <Loader color={LoaderColor.Black} /> + </div>; + } + return ( <form className={`${styles.form} ${isHide ? styles.hide : ""}`} @@ -128,12 +146,18 @@ export default function CheckoutForm({ </div> </div> </div> + {isNewPaymentButton && payButtonClicked && !isFormValid && + <p className={styles.errorMessage} style={{ marginBottom: "16px" }}> + {translate("payment_modal.form_error")} + </p> + } <SecurityPayments /> <MainButton color="blue" - disabled={isLoading || !isFormValid} + // disabled={isLoading || !isFormValid} + disabled={isNewPaymentButton ? isLoading : (isLoading || !isFormValid)} id="submit" className={styles.button} onClick={handleSubmit} diff --git a/src/components/Payment/nmi/CheckoutForm/styles.module.scss b/src/components/Payment/nmi/CheckoutForm/styles.module.scss index 2a45dfe..7d6a354 100644 --- a/src/components/Payment/nmi/CheckoutForm/styles.module.scss +++ b/src/components/Payment/nmi/CheckoutForm/styles.module.scss @@ -231,4 +231,11 @@ // .formContainer { // margin-left: -15px; // } -// } \ No newline at end of file +// } + +.loaderContainer { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/src/components/Payment/nmi/PaymentPage/index.tsx b/src/components/Payment/nmi/PaymentPage/index.tsx index 14a4617..c82f186 100644 --- a/src/components/Payment/nmi/PaymentPage/index.tsx +++ b/src/components/Payment/nmi/PaymentPage/index.tsx @@ -14,6 +14,7 @@ import metricService, { EGoals, EMetrics } from "@/services/metric/metricService import Toast from "@/components/pages/ABDesign/v1/components/Toast"; import Header from "@/components/PalmistryV1/components/Header"; import { useNavigate } from "react-router-dom"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; interface IPaymentPageProps { isSinglePayment?: boolean; @@ -54,7 +55,12 @@ function PaymentPage({ const [isPaymentSuccess, setIsPaymentSuccess] = useState(false); const [isPaymentError, setIsPaymentError] = useState(false); - const isLoading = false; + const { isReady, variant: _paymentModalPageVarinat } = useUnleash({ + flag: EUnleashFlags.paymentModalPage + }) + const paymentModalPageVarinat = _paymentModalPageVarinat || "v0"; + + const isLoading = !isReady; const paymentMethodsButtons = [ { @@ -129,15 +135,22 @@ function PaymentPage({ <div className={`${styles["payment-modal"]} ${isLoading ? styles.hide : ""} ${className}`} > - {!isSinglePayment && <Title variant="h3" className={styles.title}> - {translate("payment_modal.title")} - } - + {translate("payment_modal.title")} + + } + {!isSinglePayment && paymentModalPageVarinat === "v2" && + + {translate("payment_modal.title1")} + + } + {paymentModalPageVarinat !== "v2" && { }} - /> - {!isSinglePayment && activeProduct && ( + />} + {paymentModalPageVarinat === "v0" && !isSinglePayment && activeProduct && (

{translate("payment_modal.description", { @@ -159,7 +172,27 @@ function PaymentPage({

)} -
+ { + paymentModalPageVarinat === "v1" && ( +

+ {translate("payment_modal.price_information", { + price: addCurrency( + getPrice(activeProduct), + currency + ) + })} +

+ ) + } +
{!!activeProduct && a { text-decoration: underline; +} + +:global(.dark-theme) .text { + color: #B3B3B3; } \ No newline at end of file diff --git a/src/components/pages/ABDesign/v1/pages/EmailEnterPage/NameInput.tsx b/src/components/pages/ABDesign/v1/pages/EmailEnterPage/NameInput.tsx index 51eb162..8258364 100644 --- a/src/components/pages/ABDesign/v1/pages/EmailEnterPage/NameInput.tsx +++ b/src/components/pages/ABDesign/v1/pages/EmailEnterPage/NameInput.tsx @@ -5,6 +5,7 @@ import { FormField } from "@/types"; interface INameInputProps { value: string; placeholder: string; + placeholderClassName?: string; onValid: (value: string) => void; onInvalid: () => void; } @@ -17,6 +18,7 @@ function NameInput({ inputClassName, value, placeholder, + placeholderClassName, onValid, onInvalid, }: INameInputProps & Partial>) { @@ -43,7 +45,7 @@ function NameInput({ onChange={handleChangeName} placeholder=" " /> - {placeholder} + {placeholder}
); } diff --git a/src/components/pages/GetInformationPartner/index.tsx b/src/components/pages/GetInformationPartner/index.tsx index 9952866..a0233f5 100644 --- a/src/components/pages/GetInformationPartner/index.tsx +++ b/src/components/pages/GetInformationPartner/index.tsx @@ -35,18 +35,22 @@ function GetInformationPartnerPage() { const handleNext = () => { if (path === "palmistry" || path === "palmistry-v1") { - return navigate( - `${routes.client.palmistryOnboardingV1()}?path=palmistry` - ); + // return navigate( + // `${routes.client.palmistryOnboardingV1()}?path=palmistry` + // ); + return navigate(routes.client.home()); } if (path === "compatibility") { - return navigate(`${routes.client.palmistryOnboardingV1()}?path=compatibility`); + // return navigate(`${routes.client.palmistryOnboardingV1()}?path=compatibility`); + return navigate(routes.client.home()); } if (path === "email-compatibility") { - return navigate(routes.client.emailMarketingV1Onboarding()); + // return navigate(routes.client.emailMarketingV1Onboarding()); + return navigate(routes.client.home()); } if (path === "email-palmistry") { - return navigate(routes.client.palmistryV2Onboarding()); + // return navigate(routes.client.palmistryV2Onboarding()); + return navigate(routes.client.home()); } navigate(routes.client.home()); }; diff --git a/src/components/palmistry/scanned-photo/scanned-photo.css b/src/components/palmistry/scanned-photo/scanned-photo.css index 74f228e..8de62d8 100644 --- a/src/components/palmistry/scanned-photo/scanned-photo.css +++ b/src/components/palmistry/scanned-photo/scanned-photo.css @@ -150,6 +150,21 @@ opacity: 0; } +body.dark-theme .scanned-photo__decoration__corners { + background: linear-gradient(to right, + #BAC2EE 2px, + transparent 2px) 0 0, + linear-gradient(to right, #BAC2EE 2px, transparent 2px) 0 100%, + linear-gradient(to left, #BAC2EE 2px, transparent 2px) 100% 0, + linear-gradient(to left, #BAC2EE 2px, transparent 2px) 100% 100%, + linear-gradient(to bottom, #BAC2EE 2px, transparent 2px) 0 0, + linear-gradient(to bottom, #BAC2EE 2px, transparent 2px) 100% 0, + linear-gradient(to top, #BAC2EE 2px, transparent 2px) 0 100%, + linear-gradient(to top, #BAC2EE 2px, transparent 2px) 100% 100%; + background-repeat: no-repeat; + background-size: 15px 15px; +} + .scanned-photo__decoration__corners>svg { position: absolute; } @@ -289,4 +304,16 @@ 100% { stroke-dashoffset: 0; } +} + +body.dark-theme .scanned-photo__decoration_svg>circle:first-child { + stroke: #4C526C; +} + +body.dark-theme .scanned-photo__decoration_svg>circle:last-child { + fill: #BAC2EE; +} + +body.dark-theme .scanned-photo__decoration__light-blue-circle { + background: #4C526C; } \ No newline at end of file diff --git a/src/components/palmistry/scanned-photo/scanned-photo.tsx b/src/components/palmistry/scanned-photo/scanned-photo.tsx index 7d986f7..231b40b 100644 --- a/src/components/palmistry/scanned-photo/scanned-photo.tsx +++ b/src/components/palmistry/scanned-photo/scanned-photo.tsx @@ -255,6 +255,7 @@ export default function StepScanPhoto(props: Props) { y="0px" viewBox="0 0 220 220" enableBackground="new 0 0 0 0" + className="scanned-photo__decoration_svg" > { @@ -18,6 +27,15 @@ interface IVariants { [EUnleashFlags.zodiacImages]: "new" | "old"; [EUnleashFlags.dynamicHandsCompV2]: "show" | "hide"; [EUnleashFlags.dynamicHandsPalmistryV1]: "show" | "hide"; + [EUnleashFlags.welcomePageImagePalmistryV1]: "v0" | "v1"; + [EUnleashFlags.cameraRequestModalPalmistryV1]: "show" | "hide"; + [EUnleashFlags.cameraRequestModalCompatibilityV2]: "show" | "hide"; + [EUnleashFlags.darkThemePalmistryV1]: "enabled" | "disabled"; + [EUnleashFlags.paymentButtonLogic]: "old" | "new"; + [EUnleashFlags.pageAfterTrialPaymentCompatibilityV2]: "paymentInformation" | "paymentForm"; + [EUnleashFlags.pageAfterTrialPaymentCompatibilityV3]: "paymentInformation" | "paymentForm"; + [EUnleashFlags.pageAfterTrialPaymentPalmistryV1]: "paymentInformation" | "paymentForm"; + [EUnleashFlags.paymentModalPage]: "v0" | "v1" | "v2"; } /** diff --git a/src/index.css b/src/index.css index c0fffc0..ee5aac0 100644 --- a/src/index.css +++ b/src/index.css @@ -260,4 +260,9 @@ input, textarea { html, body { touch-action: pan-y; +} + +body.dark-theme { + background-color: #222225; + color: #F7F7F7; } \ No newline at end of file diff --git a/src/routerComponents/Compatibility/v2/index.tsx b/src/routerComponents/Compatibility/v2/index.tsx index 2598082..3640be6 100644 --- a/src/routerComponents/Compatibility/v2/index.tsx +++ b/src/routerComponents/Compatibility/v2/index.tsx @@ -73,7 +73,10 @@ function CompatibilityV2Routes() { } function onPopState(): void { - if (document.location.toString() === `${window.location.origin}${routes.client.compatibilityV2Payment()}`) { + if ( + document.location.toString() === `${window.location.origin}${routes.client.compatibilityV2Payment()}` || + document.location.toString() === `${window.location.origin}${routes.client.compatibilityV2TrialPayment()}` + ) { navigate(routes.client.compatibilityV2SaveOff()); } } diff --git a/src/routerComponents/Compatibility/v3/index.tsx b/src/routerComponents/Compatibility/v3/index.tsx index 24a3899..77bd751 100644 --- a/src/routerComponents/Compatibility/v3/index.tsx +++ b/src/routerComponents/Compatibility/v3/index.tsx @@ -75,7 +75,10 @@ function CompatibilityV3Routes() { } function onPopState(): void { - if (document.location.toString() === `${window.location.origin}${routes.client.compatibilityV3Payment()}`) { + if ( + document.location.toString() === `${window.location.origin}${routes.client.compatibilityV3Payment()}` || + document.location.toString() === `${window.location.origin}${routes.client.compatibilityV3TrialPayment()}` + ) { navigate(routes.client.compatibilityV3SaveOff()); } } diff --git a/src/routerComponents/Palmistry/v1/LayoutPalmistryV1/styles.module.css b/src/routerComponents/Palmistry/v1/LayoutPalmistryV1/styles.module.css index 5a4a749..ab51287 100644 --- a/src/routerComponents/Palmistry/v1/LayoutPalmistryV1/styles.module.css +++ b/src/routerComponents/Palmistry/v1/LayoutPalmistryV1/styles.module.css @@ -11,10 +11,18 @@ padding: 8px 0 30px; } +:global(.dark-theme) .header>button>svg>path { + fill: #BAC2EE; +} + .header-title { color: #275CA7; } +:global(.dark-theme) .header>svg>path { + fill: #4F8DE5; +} + .page { width: 100%; height: fit-content; diff --git a/src/routerComponents/Palmistry/v1/StepperLayoutPalmistryV1/index.tsx b/src/routerComponents/Palmistry/v1/StepperLayoutPalmistryV1/index.tsx index 928792c..567eba6 100644 --- a/src/routerComponents/Palmistry/v1/StepperLayoutPalmistryV1/index.tsx +++ b/src/routerComponents/Palmistry/v1/StepperLayoutPalmistryV1/index.tsx @@ -41,7 +41,7 @@ function StepperLayoutPalmistryV1() { diff --git a/src/routerComponents/Palmistry/v1/index.tsx b/src/routerComponents/Palmistry/v1/index.tsx index fe53984..7cd74cb 100644 --- a/src/routerComponents/Palmistry/v1/index.tsx +++ b/src/routerComponents/Palmistry/v1/index.tsx @@ -39,13 +39,38 @@ import AddGuides from "@/components/palmistry/AdditionalPurchases/pages/AddGuide import PaymentPage from "@/components/Payment/nmi/PaymentPage"; import { EPlacementKeys } from "@/api/resources/Paywall"; import TryApp from "@/components/PalmistryV1/pages/TryApp"; +import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; +import Loader, { LoaderColor } from "@/components/Loader"; const removePrefix = (path: string) => path.replace(palmistryV1Prefix, ""); +const availableUrlsDarkTheme = [ + routes.client.palmistryV1Welcome(), + routes.client.palmistryV1Gender(), + routes.client.palmistryV1Birthdate(), + routes.client.palmistryV1PalmsInformation(), + routes.client.palmistryV1WhatAspects(), + routes.client.palmistryV1RelationshipStatus(), + routes.client.palmistryV1ElementResonates(), + routes.client.palmistryV1FavoriteColor(), + routes.client.palmistryV1HeadOrHeart(), + routes.client.palmistryV1HeadOrHeartResult(), + routes.client.palmistryV1RelateFollowing(), + routes.client.palmistryV1LetScan(), + routes.client.palmistryV1ScanInstruction(), + routes.client.palmistryV1Camera(), + routes.client.palmistryV1ScannedPhoto(), + routes.client.palmistryV1Email(), +] + function PalmistryV1Routes() { const navigate = useNavigate(); const dispatch = useDispatch(); + const { isReady, variant: darkThemePalmistryV1Variant } = useUnleash({ + flag: EUnleashFlags.darkThemePalmistryV1 + }) + useEffect(() => { dispatch(actions.palmistry.update({ fromRedesign: true })); }, [dispatch]); @@ -67,7 +92,10 @@ function PalmistryV1Routes() { } function onPopState(): void { - if (document.location.toString() === `${window.location.origin}${routes.client.palmistryV1Payment()}`) { + if ( + document.location.toString() === `${window.location.origin}${routes.client.palmistryV1Payment()}` || + document.location.toString() === `${window.location.origin}${routes.client.palmistryV1TrialPayment()}` + ) { navigate(routes.client.palmistryV1SaveOff()); } } @@ -84,6 +112,34 @@ function PalmistryV1Routes() { }, 1500); } + useEffect(() => { + const isAvailableUrl = availableUrlsDarkTheme.reduce((acc, url) => { + if (window.location.pathname.startsWith(url)) { + return true; + } + return acc; + }, false); + + if (isAvailableUrl && darkThemePalmistryV1Variant === "enabled") { + document.body.classList.add("dark-theme"); + } else { + document.body.classList.remove("dark-theme"); + } + }, [window.location.pathname]) + + if (!isReady) { + return
+ +
+ } + return ( }> diff --git a/src/services/metric/metricService.ts b/src/services/metric/metricService.ts index 6f0ddb2..d8a6704 100644 --- a/src/services/metric/metricService.ts +++ b/src/services/metric/metricService.ts @@ -1,3 +1,4 @@ +import { getSourceByPathname } from "@/utils/source.utils"; import Clarity from "@microsoft/clarity"; import { useExperiments } from "yandex-metrica-ab-react"; @@ -180,6 +181,8 @@ const userParams = (parameters: Partial) => { const reachGoal = (goal: EGoals, usingMetrics: EMetrics[], options?: unknown) => { console.log("goal: ", goal); const isProduction = environments.MODE === "production"; + const source = getSourceByPathname(); + // if (!isProduction) return console.log("ANALYTIC IS NOT WORKING: Not production"); if (usingMetrics.includes(EMetrics.YANDEX)) { @@ -194,7 +197,10 @@ const reachGoal = (goal: EGoals, usingMetrics: EMetrics[], options?: unknown) => console.error("Google Analytics not found") } else { const eventName = goal === EGoals.PAYMENT_SUCCESS ? "purchase" : goal; - window.gtag('event', eventName, options); + window.gtag('event', eventName, { + source, + ...(options as Record) + }); console.log("goalGA: ", goal); } }