diff --git a/public/bg-gradient.png b/public/bg-gradient.png new file mode 100644 index 0000000..089b38a Binary files /dev/null and b/public/bg-gradient.png differ diff --git a/public/bg-location-map.webp b/public/bg-location-map.webp new file mode 100644 index 0000000..ad91101 Binary files /dev/null and b/public/bg-location-map.webp differ diff --git a/public/mike/assistant_1.webp b/public/mike/assistant_1.webp new file mode 100644 index 0000000..f45ed0e Binary files /dev/null and b/public/mike/assistant_1.webp differ diff --git a/public/mike/assistant_2.webp b/public/mike/assistant_2.webp new file mode 100644 index 0000000..b7f324d Binary files /dev/null and b/public/mike/assistant_2.webp differ diff --git a/public/mike/assistant_3.png b/public/mike/assistant_3.png new file mode 100644 index 0000000..ed032e6 Binary files /dev/null and b/public/mike/assistant_3.png differ diff --git a/public/mike/avatar.webp b/public/mike/avatar.webp new file mode 100644 index 0000000..2300f2f Binary files /dev/null and b/public/mike/avatar.webp differ diff --git a/public/mike/avatar_2.png b/public/mike/avatar_2.png new file mode 100644 index 0000000..3486a8d Binary files /dev/null and b/public/mike/avatar_2.png differ diff --git a/public/mike/avatar_3.webp b/public/mike/avatar_3.webp new file mode 100644 index 0000000..22a1cfb Binary files /dev/null and b/public/mike/avatar_3.webp differ diff --git a/public/mike/bg-gradient-female.webp b/public/mike/bg-gradient-female.webp new file mode 100644 index 0000000..30dde86 Binary files /dev/null and b/public/mike/bg-gradient-female.webp differ diff --git a/public/mike/bg-gradient-male.webp b/public/mike/bg-gradient-male.webp new file mode 100644 index 0000000..f04b8fc Binary files /dev/null and b/public/mike/bg-gradient-male.webp differ diff --git a/public/mike/chat-private.png b/public/mike/chat-private.png new file mode 100644 index 0000000..0dcd856 Binary files /dev/null and b/public/mike/chat-private.png differ diff --git a/public/mike/chat1.png b/public/mike/chat1.png new file mode 100644 index 0000000..7136a17 Binary files /dev/null and b/public/mike/chat1.png differ diff --git a/public/mike/chat2.webp b/public/mike/chat2.webp new file mode 100644 index 0000000..013b293 Binary files /dev/null and b/public/mike/chat2.webp differ diff --git a/public/mike/female.webp b/public/mike/female.webp new file mode 100644 index 0000000..14c4bb3 Binary files /dev/null and b/public/mike/female.webp differ diff --git a/public/mike/male.webp b/public/mike/male.webp new file mode 100644 index 0000000..0d0329f Binary files /dev/null and b/public/mike/male.webp differ diff --git a/public/mike/user1.webp b/public/mike/user1.webp new file mode 100644 index 0000000..6c9d8d0 Binary files /dev/null and b/public/mike/user1.webp differ diff --git a/public/mike/user2.webp b/public/mike/user2.webp new file mode 100644 index 0000000..d96ca94 Binary files /dev/null and b/public/mike/user2.webp differ diff --git a/public/mike/user3.webp b/public/mike/user3.webp new file mode 100644 index 0000000..5b3cf35 Binary files /dev/null and b/public/mike/user3.webp differ diff --git a/src/api/resources/Paywall.ts b/src/api/resources/Paywall.ts index 9e0a5ba..193c029 100644 --- a/src/api/resources/Paywall.ts +++ b/src/api/resources/Paywall.ts @@ -10,6 +10,7 @@ export interface PayloadGet extends Payload { } export enum EPlacementKeys { + "aura.placement.v1.mike" = "aura.placement.v1.mike", "aura.placement.main" = "aura.placement.main", "aura.placement.redesign.main" = "aura.placement.redesign.main", "aura.placement.email.marketing" = "aura.placement.email.marketing", diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index 53999ce..4608bc8 100755 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -121,6 +121,7 @@ import LoadingPage from "../pages/LoadingPage"; import { EProductKeys, productUrls } from "@/data/products"; import SinglePaymentPage from "../pages/SinglePaymentPage"; import ABDesignV1Routes from "@/routerComponents/ABDesign/v1"; +import MikeV1Routes from "@/routerComponents/Mike/v1"; import metricService from "@/services/metric/metricService"; const isProduction = import.meta.env.MODE === "production"; @@ -285,6 +286,7 @@ function App(): JSX.Element { }> } /> + } /> }> } /> {/* Email - Pay - Email */} @@ -1064,9 +1066,32 @@ interface IShortPathOutletProps { } function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element { + const dispatch = useDispatch(); + const { productKey, requiredParameters, redirectUrls, isProductPage } = props; const { user, token } = useAuth(); + const dateOfPaymentChatMike = useSelector( + selectors.selectDateOfPaymentChatMike + ); + + const queryParameters = new URLSearchParams(window.location.search); + const paymentMadeChatMike = queryParameters.get("paymentMadeChatMike"); + + if (paymentMadeChatMike && !dateOfPaymentChatMike) { + dispatch(actions.userConfig.setDateOfPaymentChatMike(new Date())); + } + + const isForcePaymentStatus = useMemo(() => { + if ((Date.now() - new Date(dateOfPaymentChatMike).getTime()) / 1000 < 180) { + return true; + } + if (paymentMadeChatMike && !dateOfPaymentChatMike) { + return true; + } + return false; + }, [dateOfPaymentChatMike, paymentMadeChatMike]); + const api = useApi(); const isForce = useSelector(selectors.selectIsForceShortPath); @@ -1122,7 +1147,7 @@ function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element { } return ; } - if (!isPurchasedProduct) { + if (!isPurchasedProduct && !isForcePaymentStatus) { if (isForce && redirectUrls.purchasedProduct?.force) { return ( diff --git a/src/components/EmailEnterPage/EmailInput.tsx b/src/components/EmailEnterPage/EmailInput.tsx index 98ded6e..635a72c 100755 --- a/src/components/EmailEnterPage/EmailInput.tsx +++ b/src/components/EmailEnterPage/EmailInput.tsx @@ -8,8 +8,12 @@ const isValidEmail = (email: string) => { return re.test(String(email).toLowerCase().trim()); }; -function EmailInput(props: FormField): JSX.Element { - const { name, value, placeholder, onValid, onInvalid } = props; +type EmailInputProps = FormField & { + className?: string; +}; + +function EmailInput(props: EmailInputProps): JSX.Element { + const { name, value, placeholder, onValid, onInvalid, className } = props; const [email, setEmail] = useState(value); const handleChangeEmail = (event: React.ChangeEvent) => { @@ -35,6 +39,7 @@ function EmailInput(props: FormField): JSX.Element { { + (async () => { + if ( + assistant && + !!assistant?.external_id && + !assistant?.external_chat_id?.length + ) { + await sendMessage("HI"); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [assistant?.external_id]); + return (
{isLoading && ( @@ -355,6 +368,7 @@ function AdvisorChatPage() { { + return navigate(-1); + }; + + return ( + + ); +} + +export default ButtonBack; diff --git a/src/components/pages/Mike/v1/components/ButtonBack/styles.module.css b/src/components/pages/Mike/v1/components/ButtonBack/styles.module.css new file mode 100644 index 0000000..57c3492 --- /dev/null +++ b/src/components/pages/Mike/v1/components/ButtonBack/styles.module.css @@ -0,0 +1,24 @@ +.back__button { + width: 20px; + height: 30px; + position: absolute; + top: 35px; + left: 17px; + padding: 5px; + cursor: pointer; + outline: none; + background-color: transparent; + background-image: none; + outline: none; + line-height: inherit; + color: inherit; + text-transform: none; + border: 0px; + z-index: 10; +} +.light { + color: #fff +} +.dark { + color: #000 +} \ No newline at end of file diff --git a/src/components/pages/Mike/v1/components/Link/index.tsx b/src/components/pages/Mike/v1/components/Link/index.tsx new file mode 100644 index 0000000..9714738 --- /dev/null +++ b/src/components/pages/Mike/v1/components/Link/index.tsx @@ -0,0 +1,21 @@ +import { ReactNode } from "react"; +import styles from "./styles.module.css"; +import { Link as LinkRouter } from "react-router-dom"; + +function Link({ + to, + children, + className = "", +}: { + to: string; + children?: ReactNode; + className?: string; +}) { + return ( + + {children} + + ); +} + +export default Link; diff --git a/src/components/pages/Mike/v1/components/Link/styles.module.css b/src/components/pages/Mike/v1/components/Link/styles.module.css new file mode 100644 index 0000000..b9d2738 --- /dev/null +++ b/src/components/pages/Mike/v1/components/Link/styles.module.css @@ -0,0 +1,7 @@ +.link { + margin-block: 0 10px; + margin-inline: auto; + text-align: center; + text-decoration: underline; + text-underline-offset: 3px; +} diff --git a/src/components/pages/Mike/v1/components/Message/index.tsx b/src/components/pages/Mike/v1/components/Message/index.tsx new file mode 100644 index 0000000..6b9d104 --- /dev/null +++ b/src/components/pages/Mike/v1/components/Message/index.tsx @@ -0,0 +1,19 @@ +import styles from "./styles.module.css"; +import Title from "@/components/Title"; +import { FC, PropsWithChildren } from "react"; +import cn from "classnames"; + +type MessageProps = { + className?: string; +}; + +export const Message: FC> = ({ + children, + className, +}) => { + return ( + + {children} + + ); +}; diff --git a/src/components/pages/Mike/v1/components/Message/styles.module.css b/src/components/pages/Mike/v1/components/Message/styles.module.css new file mode 100644 index 0000000..c6bb95e --- /dev/null +++ b/src/components/pages/Mike/v1/components/Message/styles.module.css @@ -0,0 +1,36 @@ +.message { + position: relative; + margin-block: 30px 16px; + padding: 10px 20px; + line-height: 1.2; + border-radius: 16px; + background: #fff; + text-align: left; + z-index: 1; +} +.message::after { + content: ""; + position: absolute; + display: block; + top: -18px; + left: 50%; + width: 50px; + height: 50px; + background: #fff; + rotate: 45deg; + translate: -50% 0; + z-index: -1; +} +@media (max-width: 420px) { + .message { + margin-block: 24px 10px; + padding: 6px 14px; + font-size: 21px; + } + .message::after { + top: -16px; + width: 40px; + height: 40px; + + } +} diff --git a/src/components/pages/Mike/v1/components/OftenAsk/Question.tsx b/src/components/pages/Mike/v1/components/OftenAsk/Question.tsx new file mode 100644 index 0000000..29a721f --- /dev/null +++ b/src/components/pages/Mike/v1/components/OftenAsk/Question.tsx @@ -0,0 +1,44 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; + +interface IQuestionProps { + title: string; + text: string; +} + +function Question({ title, text }: IQuestionProps) { + return ( +
+
+ + + + +
+ +
+ + {title} + +

{text}

+
+
+ ); +} + +export default Question; diff --git a/src/components/pages/Mike/v1/components/OftenAsk/index.tsx b/src/components/pages/Mike/v1/components/OftenAsk/index.tsx new file mode 100644 index 0000000..b5ff479 --- /dev/null +++ b/src/components/pages/Mike/v1/components/OftenAsk/index.tsx @@ -0,0 +1,31 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; +import Question from "./Question"; +import { questionsMike } from "@/data/oftenAsk"; +import { ReactNode } from "react"; + +interface IOftenAsk { + title?: ReactNode | string; +} +function OftenAsk({ title }: IOftenAsk) { + return ( + <> + {typeof title === "string" ? ( + + {title} + + ) : ( + title + )} +
    + {questionsMike.map((question, index) => ( +
  • + +
  • + ))} +
+ + ); +} + +export default OftenAsk; diff --git a/src/components/pages/Mike/v1/components/OftenAsk/styles.module.css b/src/components/pages/Mike/v1/components/OftenAsk/styles.module.css new file mode 100644 index 0000000..607838a --- /dev/null +++ b/src/components/pages/Mike/v1/components/OftenAsk/styles.module.css @@ -0,0 +1,45 @@ +.title { + margin-bottom: 20px; + font-size: 24px; + line-height: 145%; + text-align: center; + color: #333333; + font-weight: 700; +} + +.questions { + display: flex; + flex-direction: column; + gap: 26px; +} +.question { + display: flex; + gap: 8px; +} + +.image-container { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + height: 30px; + width: 30px; + border-radius: 50%; + background-color: #fff; +} + +.secondary-title { + flex: 1 1 0%; + font-weight: 600; + font-size: 16px; + line-height: 125%; + margin: 0; + text-align: left; +} + +.text { + font-weight: 400; + font-size: 16px; + line-height: 140%; + margin-top: 6px; +} diff --git a/src/components/pages/Mike/v1/components/PaymentTable/index.tsx b/src/components/pages/Mike/v1/components/PaymentTable/index.tsx new file mode 100644 index 0000000..91d78e8 --- /dev/null +++ b/src/components/pages/Mike/v1/components/PaymentTable/index.tsx @@ -0,0 +1,99 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; +import { ReactNode, useState } from "react"; +import FullScreenModal from "@/components/FullScreenModal"; +import { IPaywallProduct } from "@/api/resources/Paywall"; +import { Button } from "../../ui/Button"; +import GuardPayments from "@/components/pages/ABDesign/v1/pages/TrialPayment/components/GuardPayments"; +import { useGenderInfo } from "../../lib/getGenderInfo"; + +interface IPaymentTableProps { + product: IPaywallProduct; + buttonClick: () => void; + title?: ReactNode | string; +} + +const getPrice = (product: IPaywallProduct) => { + return (product.trialPrice || 0) / 100; +}; + +function PaymentTable({ + product, + buttonClick, + title = "Special offer", +}: IPaymentTableProps) { + const [isOpenPrivacyModal, setIsOpenPrivacyModal] = useState(false); + const genderInfo = useGenderInfo(); + + const handleSubscriptionPolicyClick = (event: React.MouseEvent) => { + event.preventDefault(); + setIsOpenPrivacyModal(true); + }; + + return ( + <> + {isOpenPrivacyModal && ( + +
+ Cross setIsOpenPrivacyModal(false)} + /> + +
+
+ )} +
+
+ {typeof title === "string" ? ( + + {title} + + ) : ( + title + )} +
+
+ + Personalized reading for ${getPrice(product)} + +
+

Total today:

+ ${getPrice(product)} +
+
+
+

Your cost per 2 weeks after trial

+
+ $65 + ${product.trialPrice / 100} +
+
+
+
+ + +

+ You are enrolling in 2 weeks subscription. By continuing you agree that + if you don't cancel prior to the end of the 3-day trial for the $ + {getPrice(product)} you will automatically be charged $19 every 2 weeks + until you cancel in settings. Learn more about cancellation and refund + policy in{" "} + Subscription policy +

+ + ); +} + +export default PaymentTable; diff --git a/src/components/pages/Mike/v1/components/PaymentTable/styles.module.css b/src/components/pages/Mike/v1/components/PaymentTable/styles.module.css new file mode 100644 index 0000000..47f4fc8 --- /dev/null +++ b/src/components/pages/Mike/v1/components/PaymentTable/styles.module.css @@ -0,0 +1,129 @@ +.payment-table { + width: 100%; + margin-top: 50px; +} + +.header { + margin-bottom: 18px; +} + +.header .title { + margin-bottom: 18px; + font-size: 47px; + font-weight: 800; + text-align: center; +} + +.table-container { + padding: 13px; + margin-inline: 26px; + border-radius: 10px; + background: #fff; +} + +.table-container > hr { + margin: 10px 0; +} + +.title { + margin-bottom: 18px; + font-weight: 700; + font-size: 15px; + color: #0f0f0f; +} + +.table-element, +.table-footer { + display: flex; + -webkit-box-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + align-items: center; +} + +.table-element > p { + font-weight: 500; + font-size: 16px; + line-height: 24px; + color: #2c2c2c; +} + +.table-element > span { + font-weight: 800; + font-size: 19px; + line-height: 22px; + margin-left: 4px; + color: #2c2c2c; +} + +.table-footer > p, +.table-footer span { + font-size: 12px; +} + +.button { + height: 53px; + max-width: 360px; + width: 100%; + margin-top: 21px; + border-radius: 8px; +} + +.policy { + max-width: 336px; + font-size: 12px; + line-height: 20px; + font-weight: 300; + margin-top: 18px; + margin-inline: auto; +} + +.policy > a { + text-decoration: underline; + font-weight: 600; + cursor: pointer; +} + +.discount { + text-decoration: line-through; + align-self: flex-end; + font-weight: 400; + font-size: 12px; + line-height: 22px; + color: rgba(44, 44, 44, 0.6); + margin-right: 2px; +} + +.price { + font-size: 14px; +} + +.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; +} + +@media (max-width: 430px) { + .header .title { + font-size: 38px; + } +} diff --git a/src/components/pages/Mike/v1/components/PersonalInformation/index.tsx b/src/components/pages/Mike/v1/components/PersonalInformation/index.tsx new file mode 100644 index 0000000..9bb0aea --- /dev/null +++ b/src/components/pages/Mike/v1/components/PersonalInformation/index.tsx @@ -0,0 +1,54 @@ +import styles from "./styles.module.css"; + +interface IPersonalInformationProps { + birthdate: string; + zodiacSign: string; + gender: string; + birthPlace: string; + primaryColor?: string; +} + +function PersonalInformation({ + birthdate, + zodiacSign, + gender, + birthPlace, + primaryColor, +}: IPersonalInformationProps) { + return ( +
+
+ {`${gender} +
+
+
    +
  • +
    Zodiac sign
    +

    {zodiacSign}

    +
  • +
  • +
    Gender
    +

    {gender}

    +
  • +
+
    +
  • +
    Date of birth
    +

    {birthdate}

    +
  • +
  • +
    Place of birth
    +

    {birthPlace}

    +
  • +
+
+
+ ); +} + +export default PersonalInformation; diff --git a/src/components/pages/Mike/v1/components/PersonalInformation/styles.module.css b/src/components/pages/Mike/v1/components/PersonalInformation/styles.module.css new file mode 100644 index 0000000..ed00888 --- /dev/null +++ b/src/components/pages/Mike/v1/components/PersonalInformation/styles.module.css @@ -0,0 +1,62 @@ +.personal-information { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 22px; +} + +.personal-information > div { + width: 100%; + background: #fff; + border-radius: 10px; + box-shadow: 0px 0px 14px rgba(0,0,0,.25); +} + +.image-container { + padding: 8px; + } + +.image-container > img { + display: block; + height: 278px; + margin-inline: auto; +} + +.text-information { + background: #fbfbff; + border-radius: 0px 0px 20px 20px; + width: 100%; + display: flex; + justify-content: space-between; + position: relative; + padding: 12px 48px; +} + +.text-information > ul { + width: min-content; + display: flex; + flex-wrap: wrap; + gap: 8px; + position: relative; + text-wrap: nowrap; +} + +.text-information > ul > li { + width: 100%; +} + +.text-information > ul > li > h6 { + font-weight: 500; + font-size: 15px; + line-height: 125%; +} + +.text-information > ul > li > p { + font-size: 13px; + line-height: 130%; + margin-top: 4px; + text-transform: capitalize; + color: #0f0f0f; +} diff --git a/src/components/pages/Mike/v1/components/PointsList/index.tsx b/src/components/pages/Mike/v1/components/PointsList/index.tsx new file mode 100644 index 0000000..9410c31 --- /dev/null +++ b/src/components/pages/Mike/v1/components/PointsList/index.tsx @@ -0,0 +1,46 @@ +import { ReactNode } from "react"; +import styles from "./styles.module.css"; + +interface IPointsListProps { + points: string[]; + title?: ReactNode; + containerClassName?: string; +} + +function PointsList({ + points, + title, + containerClassName = "", +}: IPointsListProps) { + return ( +
+ {title} +
    + {points.map((point, index) => ( +
  • + + + + + {point} +
  • + ))} +
+
+ ); +} + +export default PointsList; diff --git a/src/components/pages/Mike/v1/components/PointsList/styles.module.css b/src/components/pages/Mike/v1/components/PointsList/styles.module.css new file mode 100644 index 0000000..5be1087 --- /dev/null +++ b/src/components/pages/Mike/v1/components/PointsList/styles.module.css @@ -0,0 +1,16 @@ +.you-get { + max-width: 320px; +} + +.you-get > ul > li { + display: flex; + gap: 6px; + font-size: 16px; + line-height: 140%; + margin-bottom: 4px; +} + +.checkIcon { + margin-top: 3px; + flex-shrink: 0; +} \ No newline at end of file diff --git a/src/components/pages/Mike/v1/components/Reviews/Review.tsx b/src/components/pages/Mike/v1/components/Reviews/Review.tsx new file mode 100644 index 0000000..7e8f97e --- /dev/null +++ b/src/components/pages/Mike/v1/components/Reviews/Review.tsx @@ -0,0 +1,45 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; +import { IReview } from "@/data/reviews"; + +type IReviewProps = IReview; + +function Review({ username, date, text, mark, image }: IReviewProps) { + return ( +
+
+ {!image?.length && {username.slice(0, 2)}} + {!!image?.length && ( + Customer Avatar + )} +
+
+
+
+ + {username} + +

{date}

+
+ {!!mark && ( + + )} +
+
+

{text}

+
+
+
+ ); +} + +export default Review; diff --git a/src/components/pages/Mike/v1/components/Reviews/index.tsx b/src/components/pages/Mike/v1/components/Reviews/index.tsx new file mode 100644 index 0000000..2c72054 --- /dev/null +++ b/src/components/pages/Mike/v1/components/Reviews/index.tsx @@ -0,0 +1,23 @@ +import styles from "./styles.module.css"; +import { IReview } from "@/data/reviews"; +import Review from "./Review"; + +interface IReviewsProps { + reviews: IReview[]; +} + +function Reviews({ reviews }: IReviewsProps) { + return ( +
+
    + {reviews.map((review, index) => ( +
  • + +
  • + ))} +
+
+ ); +} + +export default Reviews; diff --git a/src/components/pages/Mike/v1/components/Reviews/styles.module.css b/src/components/pages/Mike/v1/components/Reviews/styles.module.css new file mode 100644 index 0000000..9682da4 --- /dev/null +++ b/src/components/pages/Mike/v1/components/Reviews/styles.module.css @@ -0,0 +1,111 @@ +.reviews > ul { + display: flex; + flex-direction: column; + justify-content: center; + gap: 14px; +} + +.reviews > ul > li { + width: 100%; +} + +.review { + display: grid; + grid-template-columns: min(60px, 16%) 1fr; + gap: 8px 12px; + align-items: start; + height: 100%; + padding: 13px; + background: rgb(255, 255, 255); + border-radius: 10px; + box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.25); +} + +.header { + display: flex; +} + +.avatar { + width: 32px; + height: 32px; + background-color: rgb(210, 209, 249); + border-radius: 50%; + display: flex; + -webkit-box-align: center; + align-items: center; + -webkit-box-pack: center; + justify-content: center; +} + +.avatar.middle { + width: 100%; + height: auto; +} + +.avatar > span { + font-weight: 600; + font-size: 16px; + line-height: 24px; + background: linear-gradient( + rgb(20, 19, 51) 0%, + rgb(32, 34, 97) 70.63%, + rgb(58, 35, 122) 100% + ) + text; + -webkit-text-fill-color: transparent; +} + +.info { + flex: 1 1 0%; + margin-left: 6px; +} + +.info > .title { + font-weight: 600; + font-size: 16px; + line-height: 130%; + color: #000; + margin: 0; + text-align: left; +} + +.info > p { + font-size: 14px; + line-height: 120%; + margin-top: 2px; + color: #000; +} + +.stars { + max-width: 6.75rem; + font-size: 1.375rem; + height: 1em; + width: 100%; + mask-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTciIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNyAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwKSI+CjxwYXRoIGQ9Ik04LjQ5OTc4IDEyLjE3NEwzLjc5Nzc4IDE0LjgwNkw0Ljg0Nzc4IDkuNTIwNjVMMC44OTExMTMgNS44NjE5OEw2LjI0MjQ1IDUuMjI3MzJMOC40OTk3OCAwLjMzMzk4NEwxMC43NTcxIDUuMjI3MzJMMTYuMTA4NCA1Ljg2MTk4TDEyLjE1MTggOS41MjA2NUwxMy4yMDE4IDE0LjgwNkw4LjQ5OTc4IDEyLjE3NFoiIGZpbGw9IiNGMkM5NEMiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMCI+CjxyZWN0IHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0id2hpdGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuNSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K); + mask-position: 0px 0px; + mask-size: 1em 1em; +} + +.content { + display: flex; + margin-top: 10px; +} + +.opostrafs { + width: 32px; +} + +.text { + flex: 1 1 0%; + font-size: 16px; + line-height: 1.25; + font-weight: 300; + margin-left: 6px; + color: rg#0f0f0f; +} + +.image { + width: 100%; + height: 100%; + object-fit: cover; +} diff --git a/src/components/pages/Mike/v1/components/TrialPaymentHeader/index.tsx b/src/components/pages/Mike/v1/components/TrialPaymentHeader/index.tsx new file mode 100644 index 0000000..20596c3 --- /dev/null +++ b/src/components/pages/Mike/v1/components/TrialPaymentHeader/index.tsx @@ -0,0 +1,34 @@ +import styles from "./styles.module.css"; +import DiscountExpires from "@/components/pages/TrialPayment/components/DiscountExpires"; +import CustomButton from "@/components/pages/TrialPayment/components/CustomButton"; +import { useGenderInfo } from "../../lib/getGenderInfo"; + +interface ITrialPaymentHeaderProps { + buttonText?: string; + buttonClassName?: string; + buttonClick: () => void; +} + +function TrialPaymentHeader({ + buttonClick, + buttonText = "get my reading", + buttonClassName = "", +}: ITrialPaymentHeaderProps) { + const genderInfo = useGenderInfo(); + return ( +
+ + + {buttonText} + +
+ ); +} + +export default TrialPaymentHeader; diff --git a/src/components/pages/Mike/v1/components/TrialPaymentHeader/styles.module.css b/src/components/pages/Mike/v1/components/TrialPaymentHeader/styles.module.css new file mode 100644 index 0000000..2fd1ab9 --- /dev/null +++ b/src/components/pages/Mike/v1/components/TrialPaymentHeader/styles.module.css @@ -0,0 +1,26 @@ +.header { + position: sticky; + top: -14px; + z-index: 30; + width: calc(100% + 36px); + display: flex; + -webkit-box-align: center; + align-items: center; + gap: 8px; + justify-content: space-between; + padding-inline: 12px; + margin-top: -36px; + /* background: rgba(240, 240, 240, .6); */ + backdrop-filter: blur(8px); +} + +.header > div { + flex-shrink: 0; +} + +.button { + height: 45px; + font-size: 25px; + font-weight: 600; + text-transform: none; +} diff --git a/src/components/pages/Mike/v1/data/data.ts b/src/components/pages/Mike/v1/data/data.ts new file mode 100644 index 0000000..5135852 --- /dev/null +++ b/src/components/pages/Mike/v1/data/data.ts @@ -0,0 +1,26 @@ +export interface Gender { + id: string; + name: string; + img: string; + colorAssociation: string; + subColorAssociation?: string; + bgColor: string; + } + + export const genders: Gender[] = [ + { + id: "male", + name: "Male", + img: "/mike/male.webp", + colorAssociation: "#3390EC", + subColorAssociation: '#353E75', + bgColor:"#E2F0FE", + }, + { + id: "female", + name: "Female", + img: "/mike/female.webp", + colorAssociation: "#F36CFF", + bgColor: "#FFEEF9", + }, + ]; \ No newline at end of file diff --git a/src/components/pages/Mike/v1/lib/getGenderInfo.ts b/src/components/pages/Mike/v1/lib/getGenderInfo.ts new file mode 100644 index 0000000..37bde5c --- /dev/null +++ b/src/components/pages/Mike/v1/lib/getGenderInfo.ts @@ -0,0 +1,10 @@ +import { useSelector } from "react-redux"; +import { Gender, genders } from "../data/data"; +import { selectors } from "@/store"; + +export function useGenderInfo(): Gender | undefined { + const currentGender = useSelector(selectors.selectQuestionnaire).gender; + const infoGender = genders.find((g) => g.id === currentGender); + + return infoGender; +} diff --git a/src/components/pages/Mike/v1/pages/BirthPlace/index.tsx b/src/components/pages/Mike/v1/pages/BirthPlace/index.tsx new file mode 100644 index 0000000..840c7c0 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/BirthPlace/index.tsx @@ -0,0 +1,99 @@ +import styles from "./styles.module.css"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; +import routes from "@/routes"; +import PlacePicker from "@/components/PlacePicker"; +import { useEffect, useState } from "react"; +import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie"; +import { Button } from "../../ui/Button"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; +import { useGenderInfo } from "../../lib/getGenderInfo"; +import ButtonBack from "../../components/ButtonBack"; +import { Message } from "../../components/Message"; +import { Card } from "../../ui/Card"; + +interface IBirthPlaceProps { + affiliation?: "self" | "partner"; +} + +function BirthPlacePage({ affiliation = "self" }: IBirthPlaceProps) { + const { t } = useTranslation(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + const questionnaire = useSelector(selectors.selectQuestionnaire); + const birthPlace = + affiliation === "self" + ? questionnaire.birthPlace + : questionnaire.partnerBirthPlace; + + const [isDisabled, setIsDisabled] = useState(() => !birthPlace); + const { setStyle } = useStyle(); + const genderInfo = useGenderInfo(); + + useLottie({ + preloadKey: ELottieKeys.magnifyingGlassAndPlanet, + }); + + const handleChange = (birthPlace: string) => { + if (affiliation === "partner") { + return dispatch( + actions.questionnaire.update({ partnerBirthPlace: birthPlace }) + ); + } + if (birthPlace !== "") { + setIsDisabled(false); + } else { + setIsDisabled(true); + } + // affiliation === "self" + return dispatch(actions.questionnaire.update({ birthPlace })); + }; + + const handleNext = () => { + if (affiliation === "partner") { + return navigate(routes.client.relationshipAlmostThereV1()); + } + // affiliation === "self" + return navigate(routes.client.mikeV1() + routes.client.emailEnter()); + }; + + useEffect(() => { + setStyle({ + backgroundImage: "url(/bg-location-map.webp)", + backgroundRepeat: "no-repeat", + backgroundSize: "cover", + }); + }, [setStyle]); + + return ( +
+ +
+ + {t("mike.birthplace.message")} +
+ + + + + +
+ ); +} + +export default BirthPlacePage; diff --git a/src/components/pages/Mike/v1/pages/BirthPlace/styles.module.css b/src/components/pages/Mike/v1/pages/BirthPlace/styles.module.css new file mode 100644 index 0000000..f30214f --- /dev/null +++ b/src/components/pages/Mike/v1/pages/BirthPlace/styles.module.css @@ -0,0 +1,45 @@ +:global(.page--dark + .page-footer) { + color: #fff; +} + +.assistant { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 36px; + padding-inline: 10px; +} + +.assistant img { + display: block; + margin-bottom: 24px; + border-radius: 50%; + width: 22.5%; +} + +.card { + margin-top: 16px; + padding: 40px 34px; + background: rgba(255, 255, 255, 0.78); +} + +.label { + color: #6b7baa; + font-size: 12px; + line-height: 16px; + margin: 0 0 6px 6px; +} + +.full-address { + display: block; + width: 100%; + max-width: 326px; + margin-inline: auto; + border-radius: 6px; + margin-bottom: 24px; + background: #fff; + text-align: center; + border-radius: 50px; + font-size: 20px; + padding: 14px 17px; +} diff --git a/src/components/pages/Mike/v1/pages/BirthTimePage/index.tsx b/src/components/pages/Mike/v1/pages/BirthTimePage/index.tsx new file mode 100644 index 0000000..403f2a8 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/BirthTimePage/index.tsx @@ -0,0 +1,68 @@ +import styles from "./styles.module.css"; +import { TimePicker } from "@/components/DateTimePicker"; +import routes from "@/routes"; +import { actions, selectors } from "@/store"; +import { useTranslation } from "react-i18next"; +import { useDispatch, useSelector } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import ButtonBack from "../../components/ButtonBack"; +import { Message } from "../../components/Message"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; +import { useEffect } from "react"; +import { useGenderInfo } from "../../lib/getGenderInfo"; +import { Card } from "../../ui/Card"; +import { Button } from "../../ui/Button"; +import Link from "../../components/Link"; + +function BirthTimePage() { + const { t } = useTranslation(); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const birthtime = useSelector(selectors.selectBirthtime); + const { setStyle } = useStyle(); + const genderInfo = useGenderInfo(); + + let nextRoute = routes.client.mikeV1() + routes.client.getBirthPlace(); + if (window.location.href.includes("/advisor-chat/")) { + nextRoute = routes.client.advisorChatBirthPlace(); + } + const handleNext = () => navigate(nextRoute); + const handleChange = (value: string) => dispatch(actions.form.addTime(value)); + + useEffect(() => { + setStyle({ + backgroundImage: "url(/bg-gradient.png)", + backgroundPosition: "left bottom", + backgroundRepeat: "no-repeat", + }); + }, [setStyle]); + return ( + <> + +
+
+
+ +
+ + {t("mike.birthtime.message")} + +
+ +

{t("mike.birthtime.description")}

+ + +
+ Skip this step and continue further +
+ + ); +} + +export default BirthTimePage; diff --git a/src/components/pages/Mike/v1/pages/BirthTimePage/styles.module.css b/src/components/pages/Mike/v1/pages/BirthTimePage/styles.module.css new file mode 100644 index 0000000..72c1669 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/BirthTimePage/styles.module.css @@ -0,0 +1,41 @@ +.assistant { + position: relative; + width: calc(100% + 28px); + margin-top: -14px; + background: transparent; + z-index: 1; +} +.assistant-img { + position: relative; + z-index: -1; +} +.assistant-img img { + position: relative; + display: block; + width: 100%; + height: 100%; + object-fit: cover; + z-index: -1; +} +.assistant-message { + position: absolute; + left: 18px; + right: 18px; + bottom: 56px; +} +.card { + z-index: 1; + margin-top: -47px; + margin-bottom: 26px; +} +.button { + margin-top: 18px; +} +@media (max-width: 420px) { + .assistant-message { + bottom: 40px; + } + .card { + margin-top: -42px; + } +} diff --git a/src/components/pages/Mike/v1/pages/EmailEnterPage/index.tsx b/src/components/pages/Mike/v1/pages/EmailEnterPage/index.tsx new file mode 100644 index 0000000..ae853f7 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/EmailEnterPage/index.tsx @@ -0,0 +1,231 @@ +import styles from "./styles.module.css"; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; +import routes from "@/routes"; +import Title from "@/components/Title"; +import Policy from "@/components/Policy"; +import Loader, { LoaderColor } from "@/components/Loader"; +import { ESourceAuthorization } from "@/api/resources/User"; +import { useAuthentication } from "@/hooks/authentication/use-authentication"; +import { usePaywall } from "@/hooks/paywall/usePaywall"; +import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall"; +import metricService, { EGoals } from "@/services/metric/metricService"; +import { ELottieKeys, useLottie } from "@/hooks/lottie/useLottie"; +import ButtonBack from "../../components/ButtonBack"; +import { Button } from "../../ui/Button"; +import { useGenderInfo } from "../../lib/getGenderInfo"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; +import { Message } from "../../components/Message"; +import EmailInput from "@/components/EmailEnterPage/EmailInput"; +import NameInput from "@/components/EmailEnterPage/NameInput"; + +interface IEmailEnterPage { + redirectUrl?: string; + isRequiredName?: boolean; +} + +function EmailEnterPage({ + redirectUrl = routes.client.mikeV1() + routes.client.trialPayment(), + isRequiredName = false, +}: IEmailEnterPage): JSX.Element { + const { t } = useTranslation(); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const [email, setEmail] = useState(""); + const [name, setName] = useState(""); + const [isDisabled, setIsDisabled] = useState(true); + const [isValidEmail, setIsValidEmail] = useState(false); + const [isValidName, setIsValidName] = useState(!isRequiredName); + const [isAuth, setIsAuth] = useState(false); + const { subPlan } = useParams(); + const { error, isLoading, token, user, authorization } = useAuthentication(); + const { setStyle } = useStyle(); + const infoGender = useGenderInfo(); + const activeProductFromStore = useSelector(selectors.selectActiveProduct); + const { products } = usePaywall({ + placementKey: EPlacementKeys["aura.placement.v1.mike"], + }); + const [activeProduct, setActiveProduct] = useState( + activeProductFromStore + ); + + useLottie({ + preloadKey: ELottieKeys.handWithStars, + }); + + useEffect(() => { + if (subPlan) { + const targetProduct = products.find( + (product) => + String( + product?.trialPrice + ? Math.floor((product?.trialPrice + 1) / 100) + : product.key.replace(".", "") + ) === subPlan + ); + if (targetProduct) { + setActiveProduct(targetProduct); + } + } + }, [subPlan, products]); + + const handleValidEmail = (email: string) => { + dispatch(actions.form.addEmail(email)); + setEmail(email); + setIsValidEmail(true); + }; + + const handleValidName = (name: string) => { + if (name) { + dispatch( + actions.user.update({ + username: name, + }) + ); + } + setName(name); + setIsValidName(true); + }; + + useEffect(() => { + if (isValidName && isValidEmail) { + setIsDisabled(false); + } else { + setIsDisabled(true); + } + }, [isValidEmail, isValidName, email, name]); + + const handleClick = () => { + authorize(); + metricService.reachGoal(EGoals.ENTERED_EMAIL); + }; + + const authorize = async () => { + let source = ESourceAuthorization["aura.main.new"]; + if (window.location.pathname.includes("advisor-chat")) { + source = ESourceAuthorization["aura.chat"]; + } + if (window.location.pathname.includes("/epe/")) { + source = ESourceAuthorization["aura.moons"]; + } + await authorization(email, source); + }; + + useEffect(() => { + if (user && token?.length && !isLoading && !error) { + dispatch( + actions.payment.update({ + activeProduct, + }) + ); + setIsAuth(true); + const timeout = setTimeout(() => { + navigate(redirectUrl); + }, 1000); + return () => { + clearTimeout(timeout); + }; + } + }, [ + activeProduct, + dispatch, + error, + isLoading, + navigate, + redirectUrl, + token?.length, + user, + ]); + + useEffect(() => { + if (infoGender) { + setStyle({ + backgroundColor: "#F7F7F7", + backgroundImage: `url(/mike/bg-gradient-${infoGender.id}.webp)`, + backgroundPosition: "bottom", + backgroundRepeat: "no-repeat", + }); + } + }, [infoGender, setStyle]); + + useEffect(() => { + dispatch(actions.privacyPolicy.updateChecked(true)); + setActiveProduct(products[0]); + }, [activeProduct, dispatch, products]); + + return ( +
+ +
+ + {t("mike.emailEnter.message")} +

{t("we_dont_share")}

+
+
+ setIsValidEmail(false)} + /> + setIsValidName(!isRequiredName)} + /> + + + {t("_continue_agree", { + eulaLink: ( + + {t("eula")} + + ), + privacyLink: ( + + {t("privacy_policy")} + + ), + })} + + {!!error?.length && ( + + Something went wrong + + )} +
+
+ ); +} + +export default EmailEnterPage; diff --git a/src/components/pages/Mike/v1/pages/EmailEnterPage/styles.module.css b/src/components/pages/Mike/v1/pages/EmailEnterPage/styles.module.css new file mode 100644 index 0000000..d9a1d86 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/EmailEnterPage/styles.module.css @@ -0,0 +1,73 @@ +.avatar-content { + margin-top: 18px; + padding-inline: 6px; + display: flex; + flex-direction: column; + align-items: center; +} + +.avatar-content img { + display: block; + width: 55.5%; + margin-bottom: 12px; + border-radius: 50%; + overflow: hidden; + box-shadow: 0px 0px 150px #3b3b3b; +} + +.not-share { + font-size: 16px; + line-height: 125%; + text-align: center; + margin: 24px auto 8px; + color: #333; +} + +.policy { + margin-inline: auto; + margin-top: 30px; + max-width: 300px; +} + +.policy > p { + font-size: 18px; + line-height: 125%; +} + +.policy .link { + color: #4200ff; + font-size: 18px; + text-underline-offset: 4px; +} + +.success-icon { + height: 32px; + width: 32px; + object-fit: cover; +} + +.form { + width: 100%; +} + +.form > [class*="container"] { + margin-bottom: 16px; +} + +.form input { + height: 58px; + border-radius: 14px; +} + +.button { + margin-top: 30px; +} + +@media (max-width: 420px) { + .not-share { + font-size: 15px; + } +.policy > p { + font-size: 17px; +} +} diff --git a/src/components/pages/Mike/v1/pages/Gender/index.tsx b/src/components/pages/Mike/v1/pages/Gender/index.tsx new file mode 100644 index 0000000..cbfb0b4 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/Gender/index.tsx @@ -0,0 +1,102 @@ +import Title from "@/components/Title"; +import styles from "./styles.module.css"; +import { EProductKeys } from "@/data/products"; +import routes from "@/routes"; +import { actions } from "@/store"; +import { Avatar } from "@mui/material"; +import { FC, useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { Gender, genders } from "../../data/data"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; + +interface IGenderPageProps { + productKey?: EProductKeys; +} + +const GenderPage: FC = ({ productKey }) => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { setStyle } = useStyle(); + + const selectGender = (gender: Gender) => { + dispatch(actions.questionnaire.update({ gender: gender.id })); + if (productKey === EProductKeys["moons.pdf.aura"]) { + return navigate(routes.client.epeBirthdate()); + } + if (productKey === EProductKeys["chat.aura"]) { + return navigate(routes.client.advisorChatBirthdate()); + } + navigate(`${routes.client.mikeV1()}/questionnaire/profile/flowChoice`); + }; + + useEffect(() => { + setStyle({ background: "#f7f7f7" }); + }, [setStyle]); + return ( +
+
+ + + Understand Yourself and Improve Relationships With Astrology + +
+ + 1-Minute Personal Assessment + +
+ + Select your gender: + +
+ {genders.map((gender, index) => ( +
{ + selectGender(gender); + }} + > +
+ {gender.id} +
+ +
+ ))} +
+
+
+

+ By continuing, you agree to our{" "} + + EULA + {" "} + and{" "} + + Privacy Notice + + . Have a question? Reach our support team{" "} + + here + +

+
+
+ ); +}; + +export default GenderPage; diff --git a/src/components/pages/Mike/v1/pages/Gender/styles.module.css b/src/components/pages/Mike/v1/pages/Gender/styles.module.css new file mode 100644 index 0000000..8bc6086 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/Gender/styles.module.css @@ -0,0 +1,99 @@ +.inner-container { + padding-inline: 8px; +} +.avatar { + margin-bottom: 14px; +} +.title { + padding: 24px 26px; + margin-bottom: 14px; + background: #fff; + text-align: left; + line-height: 1.2; + border-radius: 16px; + border: 1px solid #00000014; +} +.subtitle { + width: 100%; + margin-bottom: 30px; + font-weight: 500; + text-align: center; +} +.genders-wrapper { + width: 100%; + padding: 20px 8px 35px; + border-radius: 16px; + background: #fff; + border: 1px solid #0000000a; +} +.genders-container { + display: flex; + gap: 14px; + margin-top: 45px; + justify-content: space-between; + width: 100%; +} +.gender { + width: calc(50% - 7px); +} +.gender-img-container { + display: flex; + align-items: end; + justify-content: center; + width: 100%; + aspect-ratio: 1 / 1; + border-radius: 50%; + overflow: hidden; +} +.gender__img { + width: 100%; + aspect-ratio: 1 / 1; + object-fit: contain; +} +.gender__button { + margin-top: 30px; + padding: 12px; + width: 100%; + border: 0; + border-radius: 50px; + font-weight: 500; + color: #fff; + text-align: center; +} + +.container-policy { + max-width: 366px; + margin-block: 16px 32px ; + flex: 1 1; + display: flex; + align-items: end; +} + +.text { + text-align: center; + color: #000; + font-size: 15px; + font-weight: 400; + line-height: 1.2; +} + +.underlined { + text-decoration: underline; +} + +@media (max-width: 420px) { + .title { + margin-bottom: 10px; + padding: 20px 22px; + font-size: 16px; + } + + .subtitle { + margin-bottom: 20px; + font-size: 16px; + } + + .genders-container { + margin-top: 25px; + } +} diff --git a/src/components/pages/Mike/v1/pages/Questionnaire/index.tsx b/src/components/pages/Mike/v1/pages/Questionnaire/index.tsx new file mode 100644 index 0000000..342de9b --- /dev/null +++ b/src/components/pages/Mike/v1/pages/Questionnaire/index.tsx @@ -0,0 +1,84 @@ +import { DatePicker } from "@/components/DateTimePicker"; +import styles from "./styles.module.css"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; +import { useEffect, useState } from "react"; +import routes from "@/routes"; +import Title from "@/components/Title"; +import ButtonBack from "../../components/ButtonBack"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; +import { Message } from "../../components/Message"; +import { useGenderInfo } from "../../lib/getGenderInfo"; +import { Button } from "../../ui/Button"; +import { Card } from "../../ui/Card"; + +function QuestionnairePage() { + const { t } = useTranslation(); + const navigate = useNavigate(); + const dispatch = useDispatch(); + const selfBirthdate = useSelector(selectors.selectBirthdate); + const genderInfo = useGenderInfo(); + + const [birthdate, setBirthdate] = useState(selfBirthdate); + + const [isDisabled, setIsDisabled] = useState(true); + const { setStyle } = useStyle(); + + const handleValid = (_birthdate: string) => { + dispatch(actions.form.addDate(_birthdate)); + setBirthdate(_birthdate); + setIsDisabled(_birthdate === ""); + }; + + const handleNext = () => { + navigate(`${routes.client.mikeV1()}${routes.client.birthtime()}`); + }; + + useEffect(() => { + if (genderInfo) { + const styleBg = genderInfo + ? { + background: genderInfo.bgColor, + } + : undefined; + setStyle(styleBg); + } + }, [genderInfo, setStyle]); + return ( + <> + +
+
+
+ +
+ {t("mike.questionnaire.message")} +
+ + + What's your date of birth? + + setIsDisabled(true)} + inputClassName={`date-picker-input ${styles.input}`} + /> + + +
+ + ); +} + +export default QuestionnairePage; diff --git a/src/components/pages/Mike/v1/pages/Questionnaire/styles.module.css b/src/components/pages/Mike/v1/pages/Questionnaire/styles.module.css new file mode 100644 index 0000000..1c9fe9a --- /dev/null +++ b/src/components/pages/Mike/v1/pages/Questionnaire/styles.module.css @@ -0,0 +1,51 @@ +.img-wrapper { + display: block; + margin-inline: auto; + margin-top: 15px; + margin-inline: 25.8%; + border-radius: 50%; + aspect-ratio: 1 / 1; +} + +.img-wrapper img { + width: 100%; +} + +.question { + font-weight: 500; + margin-bottom: 14px; +} + +.tip__text { + text-align: center; + color: #5050506b; + font-size: 17px; + font-weight: 400; + line-height: 20.57px; + margin-top: 30px; +} + +.underlined { + text-decoration: underline; +} + +.button { + margin-top: 18px; +} + +.input > h3 { + display: none; +} + +@media (max-width: 420px) { + :global(.page-mike) .button { + max-width: 290px; + } + .date__text { + font-size: 13px; + } + .tip__text { + margin-top: 20px; + font-size: 15px; + } +} diff --git a/src/components/pages/Mike/v1/pages/TrialPayment/index.tsx b/src/components/pages/Mike/v1/pages/TrialPayment/index.tsx new file mode 100644 index 0000000..342e4fb --- /dev/null +++ b/src/components/pages/Mike/v1/pages/TrialPayment/index.tsx @@ -0,0 +1,240 @@ +import styles from "./styles.module.css"; +import { getZodiacSignByDate } from "@/services/zodiac-sign"; +import { actions, selectors } from "@/store"; +import { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import Title from "@/components/Title"; +import { mikeTrialPaymentReviews } from "@/data/reviews"; +import { trialPaymentPointsList } from "@/data/pointsLists"; +import { Navigate, useNavigate, useParams } from "react-router-dom"; +import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall"; +import { usePaywall } from "@/hooks/paywall/usePaywall"; +import routes from "@/routes"; +import metricService, { EGoals } from "@/services/metric/metricService"; +import Modal from "@/components/Modal"; +import ButtonBack from "../../components/ButtonBack"; +import { Message } from "../../components/Message"; +import TrialPaymentHeader from "../../components/TrialPaymentHeader"; +import { useStyle } from "@/routerComponents/Mike/v1/providers/StyleProvider/useStyle"; +import PersonalInformation from "../../components/PersonalInformation"; +import { useGenderInfo } from "../../lib/getGenderInfo"; +import PaymentTable from "../../components/PaymentTable"; +import Reviews from "../../components/Reviews"; +import PointsList from "../../components/PointsList"; +import OftenAsk from "../../components/OftenAsk"; +import PaymentModal from "@/components/PaymentModal"; +import { useTranslation } from "react-i18next"; + +function TrialPaymentPage() { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { t } = useTranslation(); + const birthdate = useSelector(selectors.selectBirthdate); + const zodiacSign = getZodiacSignByDate(birthdate); + const { gender, birthPlace } = useSelector(selectors.selectQuestionnaire); + const { products } = usePaywall({ + placementKey: EPlacementKeys["aura.placement.v1.mike"], + }); + const activeProductFromStore = useSelector(selectors.selectActiveProduct); + const [activeProduct, setActiveProduct] = useState( + activeProductFromStore + ); + const [isOpenPaymentModal, setIsOpenPaymentModal] = useState(false); + + const { setStyle } = useStyle(); + const genderInfo = useGenderInfo(); + const { subPlan } = useParams(); + + useEffect(() => { + if (subPlan) { + const targetProduct = products.find( + (product) => + String( + product?.trialPrice + ? Math.floor((product?.trialPrice + 1) / 100) + : product.key.replace(".", "") + ) === subPlan + ); + if (targetProduct) { + setActiveProduct(targetProduct); + dispatch(actions.payment.update({ activeProduct: targetProduct })); + } + } + }, [dispatch, subPlan, products]); + + useEffect(() => { + if (!products.length) return; + const isActiveProduct = products.find( + (product) => product._id === activeProduct?._id + ); + if (!activeProduct || !isActiveProduct) { + navigate(routes.client.trialChoiceV1()); + } + }, [activeProduct, navigate, products]); + + useEffect(() => { + setStyle({ backgroundColor: "#F0F0F0", paddingInline: "18px" }); + }, [setStyle]); + + if (!activeProduct) { + return ; + } + + if (!birthdate || !gender || !birthPlace) { + return ; + } + + const handleDiscount = () => { + setIsOpenPaymentModal(false); + // navigate(routes.client.additionalDiscount()); + }; + + const openStripeModal = () => { + metricService.reachGoal(EGoals.AURA_PAYMENT_METHODS_OPENED); + setIsOpenPaymentModal(true); + }; + + const returnUrl = `${window.location.origin + routes.client.advisorChatPrivate("asst_WWkAlT4Ovs6gKRy6VEn9LqNS")}?paymentMadeChatMike=true`; + + return ( +
+ + + + +
+ assistant + + {t("mike.trialPayment.message")} + +
+ + +
+ +
+ + {!!activeProduct && ( + <> + + + )} +
+ + Chat Private + +
+
+

Does my boyfried really love me?

+
+ 8:16 AM + + + +
+
+
+
+

+ Of course! Based on your’s and your boyfried’s natal charts your + are made for each other! The accuracy of an astrology reading + can vary and is subjective. Astrology is not an exact science, + but many find that it can provide valuable insights and + perspectives. Our platform uses advanced algorithms and expert + astrologers to provide the most accurate readings possible. +

+

+ The accuracy of an astrology reading can vary and is subjective. + Astrology is not an exact science, but many find that it can + provide valuable insights and perspectives. Our platform uses + advanced algorithms and expert astrologers to provide the most + accurate r +

+
+
+ avatar +
+
+
+ avatar + + + + + +
+
+
+
+
+ + Users love us + + +
+
+ + What you get + + } + /> +
+
+ + People often ask + + } + /> +
+
+ {!!activeProduct && ( + + )} +
+
+ ); +} + +export default TrialPaymentPage; diff --git a/src/components/pages/Mike/v1/pages/TrialPayment/styles.module.css b/src/components/pages/Mike/v1/pages/TrialPayment/styles.module.css new file mode 100644 index 0000000..5051695 --- /dev/null +++ b/src/components/pages/Mike/v1/pages/TrialPayment/styles.module.css @@ -0,0 +1,208 @@ +.modal { + max-height: calc(100dvh - 40px); +} + +.assistant-container { + position: relative; + width: calc(100% + 36px); + margin-top: -18px; + margin-inline: -18px; +} + +.assistant-container img { + width: 100%; + height: 100%; + object-fit: contain; + object-position: top; +} + +.assistant-message { + position: absolute; + bottom: 115px; + left: 15px; + right: 15px; + text-align: center; +} + +.personal-information-container { + width: 100%; + margin-top: 30px; +} + +.title { + margin-top: 50px; + margin-bottom: 18px; + font-size: 47px; + font-weight: 800; +} + +.full { + width: 100%; +} + +.chat-private .title { + margin-top: 30px; + margin-bottom: 12px; +} + +.chat-private-content { + width: 100%; +} + +.chat-message { + position: relative; + width: calc(80% - 30px); + margin-left: auto; + margin-right: 30px; + padding: 10px 16px 26px; + font-size: 15px; + line-height: 1.25; + background: #000; + color: #fff; + border-radius: 20px 20px 0px; + background-size: contain; +} + +.chat-message::after { + content: ''; + position: absolute; + bottom: -12px; + right: -4px; + width: 50px; + height: 68px; + background: #000; + clip-path: path('M 46 55 L 46 68 C 38 62 30 55 0.022 55 Z'); +} + +.chat-message p + p { + margin-top: 22px; +} + +.chat-message .chat-time { + position: absolute; + display: flex; + align-items: center; + gap: 6px; + bottom: 10px; + right: 20px; + z-index: 1; +} + +.chat-time span { + font-size: 5px; +} + +.chat-sender { + display: flex; + gap: 8px; + margin-top: 20px; +} + +.chat-sender-message { + flex-grow: 1; + margin-right: 0; + margin-left: 30px; + background: linear-gradient(90deg, #fab8c4 0%, #b48dd4 0.01%, #8973de 0.02%, #000 100%); + border-radius: 20px 20px 20px 0px; +} +.chat-sender-message::after { + right: auto; + left: 0; + width: 100%; + background: linear-gradient(90deg, #fab8c4 0%, #b48dd4 0.01%, #8973de 0.02%, #000 100%); + clip-path: path('M 0 55 L 0 68 C 12 56 30 55 55 55 Z'); +} + +.chat-sender-message::before { + content: ''; + position: absolute; + width: 100%; + height: calc(100% - 42px); + bottom: 0; + left: 0; + border-radius: 20px; + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); + -webkit-mask: -webkit-gradient( + linear, + left 12%, + left 0%, + from(rgba(0, 0, 0, 1)), + to(rgba(0, 0, 0, 0)) + ); + mask: -webkit-gradient( + linear, + left 12%, + left 0%, + from(rgba(0, 0, 0, 1)), + to(rgba(0, 0, 0, 0)) + ); +} + +.chat-sending { + margin-top: 20px; + display: flex; + align-items: center; + gap: 18px; +} + +.chat-avatar { + width: 60px; + height: 60px; + border-radius: 50%; + object-fit: cover; +} + +.chat-sending-circle { + display: flex; + gap: 4px; + border-radius: 20px; + padding: 12px; + background: #7B6BE1; +} + +.chat-sending-circle span { + display: block; + width: 6px; + height: 6px; + border-radius: 6px; + background-color: #fff; + opacity: .9; +} + +.chat-sending-circle span:nth-child(2) { + opacity: .8; +} + +.chat-sending-circle span:nth-child(3) { + opacity: .7; +} + +.reviews-container .title { + margin-top: 5px; + margin-bottom: 10px; +} + +.points-list-container .title { + margin-top: 20px; +} + +.often-ask-container .title { + margin-top: 50px; + margin-bottom: 15px; +} + +.payment-table-container { + width: 100%; + margin-bottom: 40px; +} +.payment-table-container > div { + margin-top: 20px; + margin-bottom: 18px; +} + +@media (max-width: 430px) { + .title { + font-size: 38px; + } +} diff --git a/src/components/pages/Mike/v1/ui/Button/index.tsx b/src/components/pages/Mike/v1/ui/Button/index.tsx new file mode 100644 index 0000000..c42194b --- /dev/null +++ b/src/components/pages/Mike/v1/ui/Button/index.tsx @@ -0,0 +1,16 @@ +import styles from './styles.module.css' +import MainButton from "@/components/MainButton"; +import { ButtonHTMLAttributes, FC } from "react"; +import cn from "classnames"; + +type ButtonProps = ButtonHTMLAttributes & { + color?: "black" | "blue"; +}; + +export const Button: FC = ({ children, className, ...props }) => { + return ( + + {children} + + ); +}; diff --git a/src/components/pages/Mike/v1/ui/Button/styles.module.css b/src/components/pages/Mike/v1/ui/Button/styles.module.css new file mode 100644 index 0000000..67a059a --- /dev/null +++ b/src/components/pages/Mike/v1/ui/Button/styles.module.css @@ -0,0 +1,10 @@ +.button { + display: block; + margin-inline: auto; + max-width: 326px; + width: 100%; + min-height: 54px; + border-radius: 22px; + font-size: 25px; + font-weight: 600; + } \ No newline at end of file diff --git a/src/components/pages/Mike/v1/ui/Card/index.tsx b/src/components/pages/Mike/v1/ui/Card/index.tsx new file mode 100644 index 0000000..490dad3 --- /dev/null +++ b/src/components/pages/Mike/v1/ui/Card/index.tsx @@ -0,0 +1,14 @@ +import styles from "./styles.module.css"; +import { FC, PropsWithChildren } from "react"; +import cn from "classnames"; + +interface CardProps { + className?: string; +} + +export const Card: FC> = ({ + children, + className, +}) => { + return
{children}
; +}; diff --git a/src/components/pages/Mike/v1/ui/Card/styles.module.css b/src/components/pages/Mike/v1/ui/Card/styles.module.css new file mode 100644 index 0000000..684bfcc --- /dev/null +++ b/src/components/pages/Mike/v1/ui/Card/styles.module.css @@ -0,0 +1,23 @@ +.card { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 22px; + padding: 14px 30px 30px 30px; + background-color: #fff; + border-radius: 16px; +} +.card :global(.description) { + font-weight: 500; + margin-inline: -10px; +} +@media (max-width: 420px) { + .card { + padding: 16px 20px; + } + .card :global(.description) { + line-height: 1.2; + font-size: 18px; + } +} diff --git a/src/data/oftenAsk.ts b/src/data/oftenAsk.ts index bb2fe2f..3ca12bb 100755 --- a/src/data/oftenAsk.ts +++ b/src/data/oftenAsk.ts @@ -18,3 +18,19 @@ export const questions: IQuestion[] = [ text: "Yes, all readings on our platform are strictly confidential. We respect our users' privacy and ensure that all personal data and readings are securely stored and not shared with third parties without consent.", }, ]; + +export const questionsMike: IQuestion[] = [ + { + title: "How can an astrological consultation help me in my life?", + text: "An astrological consultation can provide valuable insights into your personality traits, strengths, and weaknesses, and help you make important decisions and understand current life situations. Book your first consultation and discover new possibilities!", + }, + { + title: "How does the astrological platform work and what does it offer?", + text: "The astrological platform offers online consultations with professional astrologers, personalized natal charts, predictions, and advice based on your birth time, date, and place.", + }, + { + title: + "How accurate are the predictions and advice based on my natal chart?", + text: "The accuracy of predictions and advice depends on the accuracy of the provided data. With precise data, astrologers can offer very accurate and useful insights and recommendations.", + }, +]; diff --git a/src/data/reviews.ts b/src/data/reviews.ts index 2ce568d..d4e2992 100755 --- a/src/data/reviews.ts +++ b/src/data/reviews.ts @@ -50,3 +50,27 @@ export const marketingLandingReviews: IReview[] = [ image: "/user3.webp", }, ]; + +export const mikeTrialPaymentReviews: IReview[] = [ + { + username: "@andi36_11", + date: "06/05/2024", + text: '"Talking to Mike felt like chatting with an old friend. He mentioned some personality traits and life events that were spot-on, including a recent difficult breakup. His advice was very comforting and gave me hope."', + mark: 5, + image: "/mike/user1.webp", + }, + { + username: "@aramaska", + date: "04/17/2024", + text: '"Mike was incredibly insightful and accurate. His guidance helped me decide to take a new job offer, which turned out to be the best career move I\'ve ever made."', + mark: 5, + image: "/mike/user2.webp", + }, + { + username: "@patterso", + date: "03/01/2024", + text: '"Astrologer Mike provided clarity and direction when I needed it most. He predicted a significant change in my life, which happened when I moved to a new city. His insights helped me prepare and embrace the transition. Highly recommend his services!"', + mark: 5, + image: "/mike/user3.webp", + }, +]; diff --git a/src/hooks/paywall/defaultPaywalls.ts b/src/hooks/paywall/defaultPaywalls.ts index 3244540..1379fdf 100644 --- a/src/hooks/paywall/defaultPaywalls.ts +++ b/src/hooks/paywall/defaultPaywalls.ts @@ -1,6 +1,73 @@ import { EPlacementKeys, IPaywall } from "@/api/resources/Paywall"; export const defaultPaywalls: { [key in EPlacementKeys]: IPaywall } = { + "aura.placement.v1.mike": { + "_id": "66a910b60ac8af1928d3d822", + "key": "aura.paywall.v1.mike.default", + "name": "Mike Paywall", + "products": [ + { + "_id": "65ff043dfc0fcfc4be550035", + "key": "compatibility.pdf.trial.0", + "productId": "prod_PnStTEBzrPLgvL", + "name": "Сompatibility AURA | Trial $0.99", + "priceId": "price_1PG2RSIlX4lgwUxrDfU2BDS4", + "type": "subscription", + "description": "Description", + "discountPrice": null, + "discountPriceId": null, + "isDiscount": false, + "isFreeTrial": false, + "isTrial": true, + "price": 1900, + "trialDuration": 7, + "trialPrice": 99, + "trialPriceId": "price_1PFiSkIlX4lgwUxrVel0l445" + } + ], + "properties": [ + { + "key": "text.0", + "value": "We've helped millions of people to have happier lives and better relationships, and we want to help you too.", + "_id": "664542bbfe0a8eb4ee0b4f27" + }, + { + "key": "text.0.color", + "value": "millions", + "_id": "664542bbfe0a8eb4ee0b4f28" + }, + { + "key": "text.1", + "value": "Money shouldn’t stand in the way of finding astrology guidance that finally works. So, choose an amount that you think is reasonable to try us out for one week.", + "_id": "664542bbfe0a8eb4ee0b4f29" + }, + { + "key": "text.2", + "value": "It costs us $13.67 to offer a 3-day trial, but please choose the amount you are comfortable with.", + "_id": "664542bbfe0a8eb4ee0b4f2a" + }, + { + "key": "text.3", + "value": "This option will help us support those who need to select the lowest trial prices!", + "_id": "664542bbfe0a8eb4ee0b4f2b" + }, + { + "key": "text.4", + "value": "*Cost of trial as of February 2024", + "_id": "664542bbfe0a8eb4ee0b4f2c" + }, + { + "key": "text.5", + "value": "${quantity} people joined today", + "_id": "664542bbfe0a8eb4ee0b4f2d" + }, + { + "key": "text.button.1", + "value": "See my plan", + "_id": "664542bbfe0a8eb4ee0b4f2e" + } + ] + }, "aura.placement.redesign.main": { "_id": "664215e2859ff1199d3a6e9a", "key": "aura.paywall.redesign.main", diff --git a/src/locales/dev.ts b/src/locales/dev.ts index 9ee8f92..8f14b80 100755 --- a/src/locales/dev.ts +++ b/src/locales/dev.ts @@ -102,6 +102,12 @@ export default { "aura.name_1.review": "Samantha Green", "aura.name_2.review": "James Wilson", "aura.review_1.content": "As for me, money just doesn't stick with me at all. It turned out that it wasn't because I was bad or irresponsible, but it was because of my partner. We delved deeply into this issue thanks to Aura, and what do you think? Everything changed the very next day. Now we are happy and wealthy.", - "aura.review_2.content": "I don't know why, but I always had bad experiences in relationships and couldn't find the one who would understand and love me. So, I took a special extended test and immediately figured everything out. It turns out that the birth date of the chosen one and number coincidences are very important in relationships. Now I consider this in all areas, and it helps me a lot." + "aura.review_2.content": "I don't know why, but I always had bad experiences in relationships and couldn't find the one who would understand and love me. So, I took a special extended test and immediately figured everything out. It turns out that the birth date of the chosen one and number coincidences are very important in relationships. Now I consider this in all areas, and it helps me a lot.", + "mike.questionnaire.message": "Your date of birth will help me create your natal chart, lay out Tarot cards, understand your compatibility, and provide more accurate predictions.", + "mike.birthtime.message": "The time of birth determines the rising sign (ascendant) and the positions of the houses in the natal chart.", + "mike.birthtime.description": "What's your time of birth?", + "mike.birthplace.message": "Place of birth affects the calculation of the exact positions of the planets and houses at the moment of your birth.", + "mike.emailEnter.message": "Sign up to avoid losing access to your information", + "mike.trialPayment.message": "I am online and ready to help with your request.", }, } diff --git a/src/routerComponents/Mike/v1/Layouts/MainLayout.tsx b/src/routerComponents/Mike/v1/Layouts/MainLayout.tsx new file mode 100644 index 0000000..ece318f --- /dev/null +++ b/src/routerComponents/Mike/v1/Layouts/MainLayout.tsx @@ -0,0 +1,35 @@ +import { Outlet, useLocation } from "react-router-dom"; +import styles from "./styles.module.css"; +import { useEffect, useRef } from "react"; +import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement"; +import Footer from "@/components/Footer"; +import classNames from "classnames"; +import { useStyle } from "../providers/StyleProvider/useStyle"; + +function MainLayout() { + const mainRef = useRef(null); + const innerRef = useRef(null); + useSchemeColorByElement(mainRef.current, "section.page, .page, section", [ + location, + ]); + const { style } = useStyle(); + const { pathname } = useLocation(); + + useEffect(() => { + innerRef.current?.scrollTo({ + top: 0, + left: 0, + }); + }, [pathname]); + + return ( +
+
+ +
+
+
+ ); +} + +export default MainLayout; diff --git a/src/routerComponents/Mike/v1/Layouts/styles.module.css b/src/routerComponents/Mike/v1/Layouts/styles.module.css new file mode 100644 index 0000000..d48f897 --- /dev/null +++ b/src/routerComponents/Mike/v1/Layouts/styles.module.css @@ -0,0 +1,31 @@ +:global(.page-mike) { + display: flex; + flex-direction: column; + flex: 1 1; + width: inherit; + position: static; + padding: 0; + align-items: center; + overflow: initial; + +} +:global(.page-footer) { + font-size: 18px; + font-weight: 500; + color: #797979; +} +.content { + display: flex; + position: relative; + flex-direction: column; + align-items: center; + height: 100%; + width: 100%; + padding: 14px 14px 0px; + overflow-y: auto; +} +.main { + margin-inline: auto; + height: 100svh; + max-width: 430px; +} diff --git a/src/routerComponents/Mike/v1/index.tsx b/src/routerComponents/Mike/v1/index.tsx new file mode 100644 index 0000000..b0ba719 --- /dev/null +++ b/src/routerComponents/Mike/v1/index.tsx @@ -0,0 +1,47 @@ +import { Route, Routes } from "react-router-dom"; +import MainLayout from "./Layouts/MainLayout"; +import routes from "@/routes"; +import GenderPage from "@/components/pages/Mike/v1/pages/Gender"; +import QuestionnairePage from "@/components/pages/Mike/v1/pages/Questionnaire"; +import BirthTimePage from "@/components/pages/Mike/v1/pages/BirthTimePage"; +import { StyleProvider } from "./providers/StyleProvider/StyleProvider"; +import BirthPlacePage from "@/components/pages/Mike/v1/pages/BirthPlace"; +import EmailEnterPage from "@/components/pages/Mike/v1/pages/EmailEnterPage"; +import TrialPaymentPage from "@/components/pages/Mike/v1/pages/TrialPayment"; + +function MikeV1Routes() { + return ( + + + }> + }> + } /> + + } + > + }> + } /> + + + } /> + } + /> + } + /> + } + /> + + + + ); +} + +export default MikeV1Routes; diff --git a/src/routerComponents/Mike/v1/providers/StyleProvider/StyleProvider.tsx b/src/routerComponents/Mike/v1/providers/StyleProvider/StyleProvider.tsx new file mode 100644 index 0000000..36efcb6 --- /dev/null +++ b/src/routerComponents/Mike/v1/providers/StyleProvider/StyleProvider.tsx @@ -0,0 +1,29 @@ +import { + CSSProperties, + FC, + PropsWithChildren, + createContext, + useState, +} from "react"; + +interface IStyleContext { + style: CSSProperties | undefined; + setStyle: (css: CSSProperties | undefined) => void; +} +export const StyleContext = createContext(undefined); + +interface IStyleProviderProps { + defaultCss?: CSSProperties; +} +export const StyleProvider: FC> = ({ + children, + defaultCss = {}, +}) => { + const [style, setStyle] = useState(defaultCss); + + return ( + + {children} + + ); +}; diff --git a/src/routerComponents/Mike/v1/providers/StyleProvider/useStyle.ts b/src/routerComponents/Mike/v1/providers/StyleProvider/useStyle.ts new file mode 100644 index 0000000..925bd40 --- /dev/null +++ b/src/routerComponents/Mike/v1/providers/StyleProvider/useStyle.ts @@ -0,0 +1,10 @@ +import { useContext } from "react"; +import { StyleContext } from "./StyleProvider"; + +export const useStyle = () => { + const context = useContext(StyleContext); + if (context === undefined) { + throw new Error("useStyleContext must be used within a StyleProvider"); + } + return context; + }; \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index c78e47d..797a1c4 100755 --- a/src/routes.ts +++ b/src/routes.ts @@ -150,7 +150,9 @@ const routes = { [host, "single-payment", productId].join("/"), getInformationPartner: () => [host, "get-information-partner"].join("/"), - + + mikeV1: () => [host, "v1", "mike"].join("/"), + getBirthPlace: () => [host, "birthPlace"].join("/"), // ABDesignV1 genderV1: () => [host, "v1", "gender"].join("/"), questionnaireV1: () => [host, "v1", "questionnaire"].join("/"), @@ -489,6 +491,7 @@ export const withoutHeaderRoutes = [ routes.client.epeSuccessPayment(), routes.client.getInformationPartner(), routes.client.advisorChatPrivate(), + routes.client.gender() ]; export const hasNoHeader = (path: string) => { let result = true; diff --git a/src/store/index.ts b/src/store/index.ts index a684c89..f1a088d 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -51,6 +51,7 @@ import userConfig, { selectIsShowTryApp, selectFeature, selectIsForceShortPath, + selectDateOfPaymentChatMike, } from "./userConfig"; import compatibilities, { actions as compatibilitiesActions, @@ -125,6 +126,7 @@ export const selectors = { selectIsShowTryApp, selectFeature, selectIsForceShortPath, + selectDateOfPaymentChatMike, selectOpenAiToken, selectTrialChoiceArrowOptions, selectPalmistryLines, diff --git a/src/store/paywalls.ts b/src/store/paywalls.ts index ab99bdf..2d5d7b0 100644 --- a/src/store/paywalls.ts +++ b/src/store/paywalls.ts @@ -17,12 +17,14 @@ type IPayloadUpdatePaywall = { } const initialState: TPaywalls = { + "aura.placement.v1.mike": null, "aura.placement.main": null, "aura.placement.redesign.main": null, "aura.placement.email.marketing": null, "aura.placement.secret.discount": null, "aura.placement.palmistry.main": null, isMustUpdate: { + "aura.placement.v1.mike": true, "aura.placement.main": true, "aura.placement.redesign.main": true, "aura.placement.email.marketing": true, diff --git a/src/store/userConfig.ts b/src/store/userConfig.ts index 78fb7db..5d68a98 100644 --- a/src/store/userConfig.ts +++ b/src/store/userConfig.ts @@ -11,6 +11,7 @@ interface IUserConfig { isShowTryApp: boolean; isForceShortPath: boolean; feature: string; + dateOfPaymentChatMike: string; } const initialState: IUserConfig = { @@ -18,6 +19,7 @@ const initialState: IUserConfig = { isShowTryApp: false, isForceShortPath: false, feature: "", + dateOfPaymentChatMike: "", }; const userConfigSlice = createSlice({ @@ -43,6 +45,10 @@ const userConfigSlice = createSlice({ state.feature = action.payload; return state; }, + setDateOfPaymentChatMike(state, action: PayloadAction) { + state.dateOfPaymentChatMike = action.payload.toISOString(); + return state; + }, }, extraReducers: (builder) => builder.addCase("reset", () => initialState), }); @@ -64,4 +70,8 @@ export const selectFeature = createSelector( (state: { userConfig: IUserConfig }) => state.userConfig.feature, (userConfig) => userConfig ); +export const selectDateOfPaymentChatMike = createSelector( + (state: { userConfig: IUserConfig }) => state.userConfig.dateOfPaymentChatMike, + (userConfig) => userConfig +); export default userConfigSlice.reducer;