From 733561a56cd35c7ed63dbe42e6a99484833f62d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B5=D0=BD=D0=B8=D1=81=20=D0=9A=D0=B0=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D0=B2?= Date: Wed, 28 Feb 2024 19:18:22 +0000 Subject: [PATCH] Preview/discount pages --- public/download-app.svg | 48 +++++++ src/components/App/index.tsx | 14 +- .../FullScreenModal/styles.module.css | 4 +- .../pages/AlmostThere/styles.module.css | 1 + src/components/pages/Gender/index.tsx | 9 +- src/components/pages/LoadingProfile/index.tsx | 13 +- .../pages/NotAlone/styles.module.css | 1 + .../styles.module.css | 1 + .../RelationshipAlmostThere/styles.module.css | 1 + .../pages/Satisfied/styles.module.css | 1 + .../components/PaymentTable/index.tsx | 27 +++- .../components/PaymentTable/styles.module.css | 25 ++++ .../TryApp/components/AccessCodeApp/index.tsx | 19 +++ .../AccessCodeApp/styles.module.css | 45 +++++++ src/components/pages/TryApp/index.tsx | 120 ++++++++++++++++++ src/components/pages/TryApp/styles.module.css | 48 +++++++ .../pages/WorksForUs/styles.module.css | 1 + src/index.css | 2 +- src/routes.ts | 4 + src/store/index.ts | 9 ++ src/store/siteConfig.ts | 8 +- src/store/userConfig.ts | 47 +++++++ 22 files changed, 436 insertions(+), 12 deletions(-) create mode 100644 public/download-app.svg create mode 100644 src/components/pages/TryApp/components/AccessCodeApp/index.tsx create mode 100644 src/components/pages/TryApp/components/AccessCodeApp/styles.module.css create mode 100644 src/components/pages/TryApp/index.tsx create mode 100644 src/components/pages/TryApp/styles.module.css create mode 100644 src/store/userConfig.ts diff --git a/public/download-app.svg b/public/download-app.svg new file mode 100644 index 0000000..5bfe13c --- /dev/null +++ b/public/download-app.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index 84abe85..9f8e059 100755 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -96,6 +96,8 @@ import TrialPaymentWithDiscount from "../pages/TrialPaymentWithDiscount"; import MarketingLanding from "../pages/EmailLetters/MarketingLanding"; import MarketingTrialPayment from "../pages/EmailLetters/MarketingTrialPayment"; import { ScrollToTop } from "@/hooks/scrollToTop"; +import { EUserDeviceType } from "@/store/userConfig"; +import TryAppPage from "../pages/TryApp"; const isProduction = import.meta.env.MODE === "production"; @@ -181,12 +183,22 @@ function App(): JSX.Element { dispatch(actions.form.addEmail(user.email)); }, [dispatch, user]); + // set user device type + useEffect(() => { + if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) { + dispatch(actions.userConfig.addDeviceType(EUserDeviceType.ios)); + } + }, [dispatch]); + return ( }> {/* Test Routes Start */} } /> - } /> + }> + } /> + + } /> } diff --git a/src/components/FullScreenModal/styles.module.css b/src/components/FullScreenModal/styles.module.css index 6071cc3..abfe683 100644 --- a/src/components/FullScreenModal/styles.module.css +++ b/src/components/FullScreenModal/styles.module.css @@ -1,7 +1,7 @@ .modal { width: 100%; - height: 100%; - position: absolute; + height: 100dvh; + position: fixed; top: 0; left: 0; z-index: 999; diff --git a/src/components/pages/AlmostThere/styles.module.css b/src/components/pages/AlmostThere/styles.module.css index d1b9343..b94814f 100644 --- a/src/components/pages/AlmostThere/styles.module.css +++ b/src/components/pages/AlmostThere/styles.module.css @@ -13,6 +13,7 @@ background-size: cover; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/components/pages/Gender/index.tsx b/src/components/pages/Gender/index.tsx index c2a5705..9c4cbba 100644 --- a/src/components/pages/Gender/index.tsx +++ b/src/components/pages/Gender/index.tsx @@ -2,12 +2,19 @@ import styles from "./styles.module.css"; import Title from "@/components/Title"; import { Gender, genders } from "@/data"; import { actions } from "@/store"; +import { useEffect } from "react"; import { useDispatch } from "react-redux"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; function GenderPage(): JSX.Element { const dispatch = useDispatch(); const navigate = useNavigate(); + const { targetId } = useParams(); + + useEffect(() => { + const isShowTryApp = targetId === "i"; + dispatch(actions.userConfig.addIsShowTryApp(isShowTryApp)); + }, [dispatch, targetId]); const selectGender = (gender: Gender) => { dispatch(actions.questionnaire.update({ gender: gender.id })); diff --git a/src/components/pages/LoadingProfile/index.tsx b/src/components/pages/LoadingProfile/index.tsx index 01613ab..dc5a08d 100755 --- a/src/components/pages/LoadingProfile/index.tsx +++ b/src/components/pages/LoadingProfile/index.tsx @@ -11,16 +11,25 @@ import { useNavigate } from "react-router-dom"; import routes from "@/routes"; import Modal from "@/components/Modal"; import LoadingProfileModalChild from "@/components/LoadingProfileModalChild"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import { EUserDeviceType } from "@/store/userConfig"; function LoadingProfilePage() { + const userDeviceType = useSelector(selectors.selectUserDeviceType); + const isShowTryApp = useSelector(selectors.selectIsShowTryApp); + const navigate = useNavigate(); const [progress, setProgress] = useState(0); const [isPause, setIsPause] = useState(false); const interval = useRef(); const onEndLoading = useCallback(() => { - navigate(routes.client.emailEnter()); - }, [navigate]); + if (isShowTryApp && userDeviceType === EUserDeviceType.ios) { + return navigate(routes.client.tryApp()); + } + return navigate(routes.client.emailEnter()); + }, [isShowTryApp, navigate, userDeviceType]); const getProgressValue = useCallback( (index: number) => { diff --git a/src/components/pages/NotAlone/styles.module.css b/src/components/pages/NotAlone/styles.module.css index b3f3a75..8d46ecb 100644 --- a/src/components/pages/NotAlone/styles.module.css +++ b/src/components/pages/NotAlone/styles.module.css @@ -13,6 +13,7 @@ background-size: cover; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/components/pages/QuestionnaireIntermediate/styles.module.css b/src/components/pages/QuestionnaireIntermediate/styles.module.css index 2b294a6..b87bb69 100644 --- a/src/components/pages/QuestionnaireIntermediate/styles.module.css +++ b/src/components/pages/QuestionnaireIntermediate/styles.module.css @@ -13,6 +13,7 @@ background-size: cover; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/components/pages/RelationshipAlmostThere/styles.module.css b/src/components/pages/RelationshipAlmostThere/styles.module.css index 44ab5d6..40280ff 100644 --- a/src/components/pages/RelationshipAlmostThere/styles.module.css +++ b/src/components/pages/RelationshipAlmostThere/styles.module.css @@ -13,6 +13,7 @@ background-repeat: no-repeat; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/components/pages/Satisfied/styles.module.css b/src/components/pages/Satisfied/styles.module.css index 35f7c37..cf986bc 100755 --- a/src/components/pages/Satisfied/styles.module.css +++ b/src/components/pages/Satisfied/styles.module.css @@ -13,6 +13,7 @@ background-size: cover; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/components/pages/TrialPayment/components/PaymentTable/index.tsx b/src/components/pages/TrialPayment/components/PaymentTable/index.tsx index 6ef54a1..9551357 100755 --- a/src/components/pages/TrialPayment/components/PaymentTable/index.tsx +++ b/src/components/pages/TrialPayment/components/PaymentTable/index.tsx @@ -4,6 +4,8 @@ import { getPriceFromTrial } from "@/services/price"; import { ISubscriptionPlan } from "@/api/resources/SubscriptionPlans"; import CustomButton from "../CustomButton"; import GuardPayments from "../GuardPayments"; +import { useState } from "react"; +import FullScreenModal from "@/components/FullScreenModal"; interface IPaymentTableProps { subPlan: ISubscriptionPlan; @@ -11,8 +13,30 @@ interface IPaymentTableProps { } function PaymentTable({ subPlan, buttonClick }: IPaymentTableProps) { + const [isOpenPrivacyModal, setIsOpenPrivacyModal] = useState(false); + const handleSubscriptionPolicyClick = (event: React.MouseEvent) => { + event.preventDefault(); + setIsOpenPrivacyModal(true); + }; + return ( <> + {isOpenPrivacyModal && ( + +
+ Cross setIsOpenPrivacyModal(false)} + /> + +
+
+ )}
Special offer @@ -47,7 +71,8 @@ function PaymentTable({ subPlan, buttonClick }: IPaymentTableProps) { if you don't cancel prior to the end of the 3-day trial for the $ {getPriceFromTrial(subPlan?.trial)} you will automatically be charged $19 every 2 weeks until you cancel in settings. Learn more about - cancellation and refund policy in Subscription policy + cancellation and refund policy in{" "} + Subscription policy

); diff --git a/src/components/pages/TrialPayment/components/PaymentTable/styles.module.css b/src/components/pages/TrialPayment/components/PaymentTable/styles.module.css index 14f1a9c..6a8dd3d 100755 --- a/src/components/pages/TrialPayment/components/PaymentTable/styles.module.css +++ b/src/components/pages/TrialPayment/components/PaymentTable/styles.module.css @@ -80,6 +80,7 @@ .policy > a { text-decoration: underline; font-weight: 600; + cursor: pointer; } .discount { @@ -91,3 +92,27 @@ color: rgb(130, 130, 130); margin-right: 4px; } + +.modal-container, +.iframe { + position: relative; + width: 100%; + height: 100%; +} + +.iframe { + pointer-events: all; +} + +.cross { + position: fixed; + top: 60px; + right: 20px; + width: 36px; + height: 36px; + padding: 8px; + border-radius: 100%; + background-color: #fff; + z-index: 10; + cursor: pointer; +} diff --git a/src/components/pages/TryApp/components/AccessCodeApp/index.tsx b/src/components/pages/TryApp/components/AccessCodeApp/index.tsx new file mode 100644 index 0000000..e8d1129 --- /dev/null +++ b/src/components/pages/TryApp/components/AccessCodeApp/index.tsx @@ -0,0 +1,19 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; + +function AccessCodeApp() { + return ( +
+
+ + Your access code + +
+
+ FV1HBP +
+
+ ); +} + +export default AccessCodeApp; diff --git a/src/components/pages/TryApp/components/AccessCodeApp/styles.module.css b/src/components/pages/TryApp/components/AccessCodeApp/styles.module.css new file mode 100644 index 0000000..44ca91f --- /dev/null +++ b/src/components/pages/TryApp/components/AccessCodeApp/styles.module.css @@ -0,0 +1,45 @@ +.container { + margin-top: 32px; + border-radius: 24px; + min-height: 140px; + background-color: #fff; + justify-content: start; + width: 100%; +} + +.container .header-container { + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; +} + +.header-container { + background-color: rgb(153, 116, 246); + border-top-left-radius: 24px; + border-top-right-radius: 24px; +} + +.title { + text-transform: capitalize; + margin: 0; + font-size: 20px; + line-height: 145%; + color: #fff; + font-weight: 500; +} + +.code-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: calc(100% - 29px); +} + +.code { + font-size: 36px; + font-weight: 800; +} diff --git a/src/components/pages/TryApp/index.tsx b/src/components/pages/TryApp/index.tsx new file mode 100644 index 0000000..202b132 --- /dev/null +++ b/src/components/pages/TryApp/index.tsx @@ -0,0 +1,120 @@ +import { useEffect, useState } from "react"; +import Header from "../TrialPayment/components/Header"; +import PersonalInformation from "../TrialPayment/components/PersonalInformation"; +import WithPartnerInformation from "../TrialPayment/components/WithPartnerInformation"; +import styles from "./styles.module.css"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import { getZodiacSignByDate } from "@/services/zodiac-sign"; +import Title from "@/components/Title"; +import Goal from "../TrialPayment/components/Goal"; +import Reviews from "../TrialPayment/components/Reviews"; +import { trialPaymentReviews } from "@/data/reviews"; +import AccessCodeApp from "./components/AccessCodeApp"; +import YourReading from "../TrialPayment/components/YourReading"; +import PointsList from "../TrialPayment/components/PointsList"; +import OftenAsk from "../TrialPayment/components/OftenAsk"; +import { trialPaymentPointsList } from "@/data/pointsLists"; + +function TryAppPage() { + const birthdate = useSelector(selectors.selectBirthdate); + const zodiacSign = getZodiacSignByDate(birthdate); + const { + gender, + birthPlace, + partnerBirthPlace, + partnerBirthdate, + partnerGender, + goal, + flowChoice, + } = useSelector(selectors.selectQuestionnaire); + const partnerZodiacSign = getZodiacSignByDate(partnerBirthdate); + const [singleOrWithPartner, setSingleOrWithPartner] = useState< + "single" | "partner" + >("single"); + const [marginTopTitle, setMarginTopTitle] = useState(360); + + useEffect(() => { + if (["relationship", "married"].includes(flowChoice)) { + setMarginTopTitle(460); + setSingleOrWithPartner("partner"); + return; + } + setSingleOrWithPartner("single"); + setMarginTopTitle(340); + }, [flowChoice]); + + const downloadApp = () => { + // TODO + window.location.href = + "https://apps.apple.com/us/app/aura-astrology-horoscope/id1601978549"; + }; + + return ( +
+
+ {singleOrWithPartner === "partner" && ( + + )} + {singleOrWithPartner === "single" && ( + + )} + + Your Personalized Clarity & Love Reading is ready and available in the + app for your iPhone! + + + + 1. Download App + Download on the app store + 1. Download App +
FV1HBP
+

+ Enter your access code in the app to access Your Personalized Reading. + Do not share your code with anyone +

+ + + + Users love us + + + + +
+ ); +} + +export default TryAppPage; diff --git a/src/components/pages/TryApp/styles.module.css b/src/components/pages/TryApp/styles.module.css new file mode 100644 index 0000000..2b74882 --- /dev/null +++ b/src/components/pages/TryApp/styles.module.css @@ -0,0 +1,48 @@ +.page { + background-color: #fff0f0; + height: fit-content; + min-height: 100vh; + min-height: 100dvh; + padding-top: 62px; + padding-bottom: 62px; +} + +.download-app-title { + font-size: 24px; + line-height: 145%; + color: #333333; + font-weight: 700; + text-align: center; + margin-top: 32px; + margin-bottom: 16px; +} + +.download-app-image { + width: 80%; + max-width: 270px; + height: 80px; + object-fit: cover; +} + +.code-container { + font-size: 28px; + font-weight: 600; + padding: 12px; + width: 100%; + max-width: 200px; + background-color: rgba(175, 149, 241, 0.48); + border-radius: 48px; + text-align: center; +} + +.code-description { + text-align: center; + line-height: 1.3; + font-weight: 500; + font-size: 18px; + margin-top: 12px; +} + +.title { + font-weight: 700; +} diff --git a/src/components/pages/WorksForUs/styles.module.css b/src/components/pages/WorksForUs/styles.module.css index 2b294a6..b87bb69 100644 --- a/src/components/pages/WorksForUs/styles.module.css +++ b/src/components/pages/WorksForUs/styles.module.css @@ -13,6 +13,7 @@ background-size: cover; color: #fff; padding-top: 64px; + background-color: #171717; } .title { diff --git a/src/index.css b/src/index.css index 4c9d270..14688f7 100644 --- a/src/index.css +++ b/src/index.css @@ -168,7 +168,7 @@ div[class^="divider"] { } ::-webkit-scrollbar { - /* width: 13px; */ + width: 0px; } ::-webkit-scrollbar-track { diff --git a/src/routes.ts b/src/routes.ts index 8f35750..f4ba80c 100755 --- a/src/routes.ts +++ b/src/routes.ts @@ -77,6 +77,8 @@ const routes = { trialPaymentWithDiscount: () => [host, "trial-payment-with-discount"].join("/"), + tryApp: () => [host, "try-app"].join("/"), + // Email letters email: (path: string) => [host, "email", path].join("/"), notFound: () => [host, "404"].join("/"), @@ -230,6 +232,7 @@ export const withoutFooterRoutes = [ routes.client.trialPaymentWithDiscount(), routes.client.email("marketing-landing"), routes.client.email("marketing-trial-payment"), + routes.client.tryApp(), ]; export const withoutFooterPartOfRoutes = [routes.client.questionnaire()]; @@ -294,6 +297,7 @@ export const withoutHeaderRoutes = [ routes.client.trialPaymentWithDiscount(), routes.client.email("marketing-landing"), routes.client.email("marketing-trial-payment"), + routes.client.tryApp(), ]; export const hasNoHeader = (path: string) => { let result = true; diff --git a/src/store/index.ts b/src/store/index.ts index 68cdcd6..7eeca3f 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -41,6 +41,11 @@ import compatibility, { actions as compatibilityActions, selectSelfName, } from "./compatibility"; +import userConfig, { + actions as userConfigActions, + selectUserDeviceType, + selectIsShowTryApp, +} from "./userConfig"; import compatibilities, { actions as compatibilitiesActions, selectCompatibilities, @@ -72,6 +77,7 @@ export const actions = { userCallbacks: userCallbacksActions, onboardingConfig: onboardingConfigActions, questionnaire: questionnaireActions, + userConfig: userConfigActions, reset: createAction("reset"), }; export const selectors = { @@ -97,6 +103,8 @@ export const selectors = { selectOnboardingNavbarFooter, selectCompatibilities, selectQuestionnaire, + selectUserDeviceType, + selectIsShowTryApp, ...formSelectors, }; @@ -114,6 +122,7 @@ export const reducer = combineReducers({ siteConfig, onboardingConfig, questionnaire, + userConfig, }); export type RootState = ReturnType; diff --git a/src/store/siteConfig.ts b/src/store/siteConfig.ts index 902ab51..485aacf 100644 --- a/src/store/siteConfig.ts +++ b/src/store/siteConfig.ts @@ -2,9 +2,9 @@ import { createSlice, createSelector } from "@reduxjs/toolkit"; import type { PayloadAction } from "@reduxjs/toolkit"; export enum EPathsFromHome { - compatibility, - breath, - navbar + compatibility, + breath, + navbar, } interface ISiteConfig { @@ -17,7 +17,7 @@ interface ISiteConfig { const initialState: ISiteConfig = { home: { isShowNavbar: false, - pathFromHome: EPathsFromHome.compatibility + pathFromHome: EPathsFromHome.compatibility, }, }; diff --git a/src/store/userConfig.ts b/src/store/userConfig.ts new file mode 100644 index 0000000..e722eab --- /dev/null +++ b/src/store/userConfig.ts @@ -0,0 +1,47 @@ +import { createSlice, createSelector } from "@reduxjs/toolkit"; +import type { PayloadAction } from "@reduxjs/toolkit"; + +export enum EUserDeviceType { + ios, + android, +} + +interface IUserConfig { + deviceType: EUserDeviceType; + isShowTryApp: boolean; +} + +const initialState: IUserConfig = { + deviceType: EUserDeviceType.ios, + isShowTryApp: false, +}; + +const userConfigSlice = createSlice({ + name: "userConfig", + initialState, + reducers: { + update(state, action: PayloadAction>) { + return { ...initialState, ...state, ...action.payload }; + }, + addDeviceType(state, action: PayloadAction) { + state.deviceType = action.payload; + return state; + }, + addIsShowTryApp(state, action: PayloadAction) { + state.isShowTryApp = action.payload; + return state; + }, + }, + extraReducers: (builder) => builder.addCase("reset", () => initialState), +}); + +export const { actions } = userConfigSlice; +export const selectUserDeviceType = createSelector( + (state: { userConfig: IUserConfig }) => state.userConfig.deviceType, + (userConfig) => userConfig +); +export const selectIsShowTryApp = createSelector( + (state: { userConfig: IUserConfig }) => state.userConfig.isShowTryApp, + (userConfig) => userConfig +); +export default userConfigSlice.reducer;