Merge branch 'revert-44cd94b8' into 'develop'
Revert "Merge branch 'preview/additional-purchases' into 'develop'" See merge request witapp/aura-webapp!68
This commit is contained in:
commit
a033e4c542
Binary file not shown.
@ -67,7 +67,6 @@ const api = {
|
|||||||
runThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
|
runThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
|
||||||
getStatusRunThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
|
getStatusRunThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
|
||||||
getListRuns: createMethod<OpenAI.PayloadGetListRuns, OpenAI.ResponseGetListRuns>(OpenAI.createRequest),
|
getListRuns: createMethod<OpenAI.PayloadGetListRuns, OpenAI.ResponseGetListRuns>(OpenAI.createRequest),
|
||||||
// Single payment
|
|
||||||
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
|
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
|
||||||
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
|
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,6 @@ import AdvisorChatPage from "../pages/AdvisorChat";
|
|||||||
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
|
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
|
||||||
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
|
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
|
||||||
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
|
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
|
||||||
import GetInformationPartnerPage from "../pages/GetInformationPartner";
|
|
||||||
|
|
||||||
const isProduction = import.meta.env.MODE === "production";
|
const isProduction = import.meta.env.MODE === "production";
|
||||||
|
|
||||||
@ -234,18 +233,9 @@ function App(): JSX.Element {
|
|||||||
{/* Email - Pay - Email */}
|
{/* Email - Pay - Email */}
|
||||||
<Route path={routes.client.epeGender()} element={<GenderPage />} />
|
<Route path={routes.client.epeGender()} element={<GenderPage />} />
|
||||||
<Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} />
|
<Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} />
|
||||||
<Route
|
<Route path={routes.client.epePayment()} element={<PaymentWithEmailPage />} />
|
||||||
path={routes.client.epePayment()}
|
<Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} />
|
||||||
element={<PaymentWithEmailPage />}
|
<Route path={routes.client.epeFailPayment()} element={<FailPaymentPage />} />
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={routes.client.epeSuccessPayment()}
|
|
||||||
element={<SuccessPaymentPage />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={routes.client.epeFailPayment()}
|
|
||||||
element={<FailPaymentPage />}
|
|
||||||
/>
|
|
||||||
{/* Email - Pay - Email */}
|
{/* Email - Pay - Email */}
|
||||||
|
|
||||||
{/* Test Routes Start */}
|
{/* Test Routes Start */}
|
||||||
@ -361,12 +351,8 @@ function App(): JSX.Element {
|
|||||||
{/* Email Letters End */}
|
{/* Email Letters End */}
|
||||||
|
|
||||||
{/* Additional Purchases */}
|
{/* Additional Purchases */}
|
||||||
<Route element={<PrivateOutlet />}>
|
|
||||||
<Route element={<AdditionalPurchases />}>
|
<Route element={<AdditionalPurchases />}>
|
||||||
<Route
|
<Route path={routes.client.addReport()} element={<AddReportPage />} />
|
||||||
path={routes.client.addReport()}
|
|
||||||
element={<AddReportPage />}
|
|
||||||
/>
|
|
||||||
<Route
|
<Route
|
||||||
path={routes.client.unlimitedReadings()}
|
path={routes.client.unlimitedReadings()}
|
||||||
element={<UnlimitedReadingsPage />}
|
element={<UnlimitedReadingsPage />}
|
||||||
@ -376,14 +362,8 @@ function App(): JSX.Element {
|
|||||||
element={<AddConsultationPage />}
|
element={<AddConsultationPage />}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
|
||||||
{/* Additional Purchases End */}
|
{/* Additional Purchases End */}
|
||||||
|
|
||||||
<Route
|
|
||||||
path={routes.client.getInformationPartner()}
|
|
||||||
element={<GetInformationPartnerPage />}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={routes.client.paymentResult()}
|
path={routes.client.paymentResult()}
|
||||||
element={<PaymentResultPage />}
|
element={<PaymentResultPage />}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ interface IFooterButtonProps {
|
|||||||
classNameButton?: string;
|
classNameButton?: string;
|
||||||
classNameSkip?: string;
|
classNameSkip?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
disabled?: boolean;
|
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
onClickSkip: () => void;
|
onClickSkip: () => void;
|
||||||
}
|
}
|
||||||
@ -18,13 +17,11 @@ function FooterButton({
|
|||||||
classNameContainer = "",
|
classNameContainer = "",
|
||||||
classNameButton = "",
|
classNameButton = "",
|
||||||
classNameSkip = "",
|
classNameSkip = "",
|
||||||
disabled = false,
|
|
||||||
}: IFooterButtonProps) {
|
}: IFooterButtonProps) {
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.container} ${classNameContainer}`}>
|
<div className={`${styles.container} ${classNameContainer}`}>
|
||||||
<MainButton
|
<MainButton
|
||||||
className={`${styles.button} ${classNameButton}`}
|
className={`${styles.button} ${classNameButton}`}
|
||||||
disabled={disabled}
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { ISignUpOffer } from "@/data/additionalPurchases";
|
import { ISignUpOffer } from "@/data/additionalPurchases";
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import CheckMark from "./check-mark-1.svg";
|
import CheckMark from "./check-mark-1.svg";
|
||||||
import { getPriceCentsToDollars } from "@/services/price";
|
|
||||||
|
|
||||||
interface ISignUpOfferProps extends ISignUpOffer {
|
interface ISignUpOfferProps extends ISignUpOffer {
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
@ -32,14 +31,9 @@ function SignUpOffer(props: ISignUpOfferProps) {
|
|||||||
)}
|
)}
|
||||||
<div className={styles["price-container"]}>
|
<div className={styles["price-container"]}>
|
||||||
<span className={styles.price}>
|
<span className={styles.price}>
|
||||||
<span className={styles["current-price"]}>
|
<span className={styles["current-price"]}>${current}</span> ({" "}
|
||||||
${getPriceCentsToDollars(current || 0)}
|
{id === "ultra-pack" ? "regular price" : "was"}{" "}
|
||||||
</span>{" "}
|
<span className={styles["old-price"]}>${old}</span> )
|
||||||
( {id === "ultra-pack" ? "regular price" : "was"}{" "}
|
|
||||||
<span className={styles["old-price"]}>
|
|
||||||
${getPriceCentsToDollars(old || 0)}
|
|
||||||
</span>{" "}
|
|
||||||
)
|
|
||||||
</span>
|
</span>
|
||||||
{id !== "ultra-pack" && (
|
{id !== "ultra-pack" && (
|
||||||
<div className={styles["discount-container"]}>
|
<div className={styles["discount-container"]}>
|
||||||
|
|||||||
@ -5,93 +5,14 @@ import PaymentAddress from "../../components/PaymentAddress";
|
|||||||
import FooterButton from "../../components/FooterButton";
|
import FooterButton from "../../components/FooterButton";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
import { useAuth } from "@/auth";
|
|
||||||
import { SinglePayment, useApi, useApiCall } from "@/api";
|
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { selectors } from "@/store";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import {
|
|
||||||
ResponsePost,
|
|
||||||
ResponsePostExistPaymentData,
|
|
||||||
} from "@/api/resources/SinglePayment";
|
|
||||||
import { createSinglePayment } from "@/services/singlePayment";
|
|
||||||
import Modal from "@/components/Modal";
|
|
||||||
import PaymentForm from "@/components/pages/PaymentWithEmailPage/PaymentForm";
|
|
||||||
import { getPriceCentsToDollars } from "@/services/price";
|
|
||||||
import Loader, { LoaderColor } from "@/components/Loader";
|
|
||||||
|
|
||||||
function AddConsultationPage() {
|
function AddConsultationPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user: userFromStore } = useAuth();
|
const handleNext = () => {
|
||||||
const api = useApi();
|
navigate(routes.client.home());
|
||||||
const tokenFromStore = useSelector(selectors.selectToken);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [paymentIntent, setPaymentIntent] = useState<
|
|
||||||
ResponsePost | ResponsePostExistPaymentData | null
|
|
||||||
>(null);
|
|
||||||
const [isError, setIsError] = useState(false);
|
|
||||||
const returnUrl = `${window.location.protocol}//${
|
|
||||||
window.location.host
|
|
||||||
}${routes.client.getInformationPartner()}`;
|
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
return await api.getSinglePaymentProducts({ token: tokenFromStore });
|
|
||||||
}, [api, tokenFromStore]);
|
|
||||||
|
|
||||||
const { data: products, isPending: isPendingProducts } =
|
|
||||||
useApiCall<SinglePayment.ResponseGet[]>(loadData);
|
|
||||||
|
|
||||||
const currentProduct = products?.find(
|
|
||||||
(product) => product.key === "main.unique.individual.consultation"
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClick = async () => {
|
|
||||||
if (!userFromStore || !currentProduct) return;
|
|
||||||
setIsLoading(true);
|
|
||||||
const paymentIntent = await createSinglePayment(
|
|
||||||
userFromStore,
|
|
||||||
currentProduct.productId,
|
|
||||||
tokenFromStore,
|
|
||||||
userFromStore.email,
|
|
||||||
userFromStore.profile.full_name,
|
|
||||||
userFromStore.profile.birthday,
|
|
||||||
returnUrl,
|
|
||||||
api
|
|
||||||
);
|
|
||||||
setPaymentIntent(paymentIntent);
|
|
||||||
setIsLoading(false);
|
|
||||||
if ("payment" in paymentIntent) {
|
|
||||||
if (paymentIntent.payment.status === "paid")
|
|
||||||
return navigate(routes.client.getInformationPartner());
|
|
||||||
return setIsError(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickSkip = () => {
|
|
||||||
navigate(routes.client.getInformationPartner());
|
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{!isLoading &&
|
|
||||||
paymentIntent &&
|
|
||||||
"paymentIntent" in paymentIntent &&
|
|
||||||
!!tokenFromStore.length && (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
open={!!paymentIntent}
|
|
||||||
onClose={() => setPaymentIntent(null)}
|
|
||||||
>
|
|
||||||
<Title variant="h1" className={styles["modal-title"]}>
|
|
||||||
{getPriceCentsToDollars(currentProduct?.amount || 0)}$
|
|
||||||
</Title>
|
|
||||||
<PaymentForm
|
|
||||||
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
|
|
||||||
clientSecret={paymentIntent.paymentIntent.data.client_secret}
|
|
||||||
returnUrl={returnUrl}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Title variant="h2" className={styles.title}>
|
<Title variant="h2" className={styles.title}>
|
||||||
More for you
|
More for you
|
||||||
</Title>
|
</Title>
|
||||||
@ -106,22 +27,11 @@ function AddConsultationPage() {
|
|||||||
This is a non-recuring payment.
|
This is a non-recuring payment.
|
||||||
</p>
|
</p>
|
||||||
<PaymentAddress />
|
<PaymentAddress />
|
||||||
{isError && (
|
|
||||||
<p className={styles.error}>
|
|
||||||
Something went wrong. Please try again later.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<FooterButton
|
<FooterButton
|
||||||
onClick={handleClick}
|
onClick={handleNext}
|
||||||
onClickSkip={handleClickSkip}
|
onClickSkip={handleNext}
|
||||||
disabled={isPendingProducts || isLoading}
|
children="Get my consultation"
|
||||||
>
|
/>
|
||||||
{isPendingProducts || isLoading ? (
|
|
||||||
<Loader color={LoaderColor.White} />
|
|
||||||
) : (
|
|
||||||
"Get my consultation"
|
|
||||||
)}
|
|
||||||
</FooterButton>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,12 +36,3 @@
|
|||||||
line-height: 140%;
|
line-height: 140%;
|
||||||
color: rgb(79, 79, 79);
|
color: rgb(79, 79, 79);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
|
||||||
max-width: 526px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,102 +3,22 @@ import ThankYouBanner from "../../components/ThankYouBanner";
|
|||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import { signUpOffers } from "@/data/additionalPurchases";
|
import { signUpOffers } from "@/data/additionalPurchases";
|
||||||
import SignUpOffer from "../../components/SignUpOffer";
|
import SignUpOffer from "../../components/SignUpOffer";
|
||||||
import { useCallback, useState } from "react";
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import FooterButton from "../../components/FooterButton";
|
import FooterButton from "../../components/FooterButton";
|
||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
import PaymentAddress from "../../components/PaymentAddress";
|
import PaymentAddress from "../../components/PaymentAddress";
|
||||||
import { createSinglePayment } from "@/services/singlePayment";
|
|
||||||
import {
|
|
||||||
ResponsePost,
|
|
||||||
ResponsePostExistPaymentData,
|
|
||||||
} from "@/api/resources/SinglePayment";
|
|
||||||
import { useAuth } from "@/auth";
|
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { selectors } from "@/store";
|
|
||||||
import { SinglePayment, useApi, useApiCall } from "@/api";
|
|
||||||
import Loader, { LoaderColor } from "@/components/Loader";
|
|
||||||
import { getPriceCentsToDollars } from "@/services/price";
|
|
||||||
import Modal from "@/components/Modal";
|
|
||||||
import PaymentForm from "@/components/pages/PaymentWithEmailPage/PaymentForm";
|
|
||||||
|
|
||||||
function AddReportPage() {
|
function AddReportPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user: userFromStore } = useAuth();
|
const [activeOffer, setActiveOffer] = useState(signUpOffers[0].id);
|
||||||
const api = useApi();
|
|
||||||
const tokenFromStore = useSelector(selectors.selectToken);
|
|
||||||
const [paymentIntent, setPaymentIntent] = useState<
|
|
||||||
ResponsePost | ResponsePostExistPaymentData | null
|
|
||||||
>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [isError, setIsError] = useState(false);
|
|
||||||
const [activeOffer, setActiveOffer] = useState(signUpOffers[0]);
|
|
||||||
const returnUrl = `${window.location.protocol}//${
|
|
||||||
window.location.host
|
|
||||||
}${routes.client.unlimitedReadings()}`;
|
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
const handleClick = () => {
|
||||||
return await api.getSinglePaymentProducts({ token: tokenFromStore });
|
|
||||||
}, [api, tokenFromStore]);
|
|
||||||
|
|
||||||
const { data: products, isPending: isPendingProducts } =
|
|
||||||
useApiCall<SinglePayment.ResponseGet[]>(loadData);
|
|
||||||
|
|
||||||
const getCurrentProduct = (id: string) => {
|
|
||||||
return products?.find((product) => product.key === id) || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = async () => {
|
|
||||||
if (!userFromStore || !activeOffer) return;
|
|
||||||
const currentProduct = getCurrentProduct(activeOffer?.productKey);
|
|
||||||
if (!currentProduct) return;
|
|
||||||
setIsLoading(true);
|
|
||||||
const paymentIntent = await createSinglePayment(
|
|
||||||
userFromStore,
|
|
||||||
currentProduct.productId,
|
|
||||||
tokenFromStore,
|
|
||||||
userFromStore.email,
|
|
||||||
userFromStore.profile.full_name,
|
|
||||||
userFromStore.profile.birthday,
|
|
||||||
returnUrl,
|
|
||||||
api
|
|
||||||
);
|
|
||||||
setPaymentIntent(paymentIntent);
|
|
||||||
setIsLoading(false);
|
|
||||||
if ("payment" in paymentIntent) {
|
|
||||||
if (paymentIntent.payment.status === "paid")
|
|
||||||
return navigate(routes.client.unlimitedReadings());
|
|
||||||
return setIsError(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickSkip = () => {
|
|
||||||
navigate(routes.client.unlimitedReadings());
|
navigate(routes.client.unlimitedReadings());
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{!isLoading &&
|
|
||||||
paymentIntent &&
|
|
||||||
"paymentIntent" in paymentIntent &&
|
|
||||||
!!tokenFromStore.length && (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
open={!!paymentIntent}
|
|
||||||
onClose={() => setPaymentIntent(null)}
|
|
||||||
>
|
|
||||||
<Title variant="h1" className={styles["modal-title"]}>
|
|
||||||
{getPriceCentsToDollars(activeOffer.price.current || 0)}$
|
|
||||||
</Title>
|
|
||||||
<PaymentForm
|
|
||||||
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
|
|
||||||
clientSecret={paymentIntent.paymentIntent.data.client_secret}
|
|
||||||
returnUrl={returnUrl}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ThankYouBanner />
|
<ThankYouBanner />
|
||||||
<Title variant="h2" className={styles.title}>
|
<Title variant="h2" className={styles.title}>
|
||||||
Choose your sign-up offer 🔥
|
Choose your sign-up offer 🔥
|
||||||
@ -107,33 +27,26 @@ function AddReportPage() {
|
|||||||
Available only now
|
Available only now
|
||||||
</Title>
|
</Title>
|
||||||
<div className={styles["offers-container"]}>
|
<div className={styles["offers-container"]}>
|
||||||
{!isPendingProducts &&
|
{signUpOffers.map((offer, index) => (
|
||||||
signUpOffers.map((offer, index) => (
|
|
||||||
<SignUpOffer
|
<SignUpOffer
|
||||||
key={index}
|
key={index}
|
||||||
isActive={offer.id === activeOffer.id}
|
id={offer.id}
|
||||||
onClick={() => setActiveOffer(offer)}
|
title={offer.title}
|
||||||
{...offer}
|
subtitle={offer.subtitle}
|
||||||
|
price={offer.price}
|
||||||
|
emoji={offer.emoji}
|
||||||
|
isActive={offer.id === activeOffer}
|
||||||
|
onClick={() => setActiveOffer(offer.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{isPendingProducts && <Loader color={LoaderColor.Black} />}
|
|
||||||
</div>
|
</div>
|
||||||
<p className={styles.description}>
|
<p className={styles.description}>
|
||||||
*You will be charged for the add-on services or offers selected at the
|
*You will be charged for the add-on services or offers selected at the
|
||||||
time of purchase. This is a non-recuring payment.
|
time of purchase. This is a non-recuring payment.
|
||||||
</p>
|
</p>
|
||||||
{isError && (
|
|
||||||
<p className={`${styles.description} ${styles.error}`}>
|
|
||||||
Something went wrong. Please try again later.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<PaymentAddress />
|
<PaymentAddress />
|
||||||
<FooterButton
|
<FooterButton onClick={handleClick} onClickSkip={handleClick}>
|
||||||
onClick={handleClick}
|
Get my copy
|
||||||
onClickSkip={handleClickSkip}
|
|
||||||
disabled={isPendingProducts || isLoading}
|
|
||||||
>
|
|
||||||
{isLoading ? <Loader color={LoaderColor.White} /> : "Get my copy"}
|
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -34,10 +34,6 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -60,7 +56,3 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: rgb(79, 79, 79);
|
color: rgb(79, 79, 79);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -9,22 +9,14 @@ import SliderNextArrow from "../../components/SliderNextArrow";
|
|||||||
import SliderPrevArrow from "../../components/SliderPrevArrow";
|
import SliderPrevArrow from "../../components/SliderPrevArrow";
|
||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
import PaymentAddress from "../../components/PaymentAddress";
|
import PaymentAddress from "../../components/PaymentAddress";
|
||||||
import { useAuth } from "@/auth";
|
|
||||||
import { SinglePayment, useApi, useApiCall } from "@/api";
|
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { selectors } from "@/store";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import { createSinglePayment } from "@/services/singlePayment";
|
|
||||||
import Loader, { LoaderColor } from "@/components/Loader";
|
|
||||||
import {
|
|
||||||
ResponsePost,
|
|
||||||
ResponsePostExistPaymentData,
|
|
||||||
} from "@/api/resources/SinglePayment";
|
|
||||||
import Modal from "@/components/Modal";
|
|
||||||
import { getPriceCentsToDollars } from "@/services/price";
|
|
||||||
import PaymentForm from "@/components/pages/PaymentWithEmailPage/PaymentForm";
|
|
||||||
|
|
||||||
const sliderSettings = {
|
function UnlimitedReadingsPage() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const handleClick = () => {
|
||||||
|
navigate(routes.client.addConsultation());
|
||||||
|
};
|
||||||
|
|
||||||
|
const sliderSettings = {
|
||||||
dots: false,
|
dots: false,
|
||||||
infinite: false,
|
infinite: false,
|
||||||
speed: 500,
|
speed: 500,
|
||||||
@ -33,81 +25,10 @@ const sliderSettings = {
|
|||||||
className: styles["slider-container"],
|
className: styles["slider-container"],
|
||||||
nextArrow: <SliderNextArrow />,
|
nextArrow: <SliderNextArrow />,
|
||||||
prevArrow: <SliderPrevArrow />,
|
prevArrow: <SliderPrevArrow />,
|
||||||
};
|
|
||||||
|
|
||||||
function UnlimitedReadingsPage() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { user: userFromStore } = useAuth();
|
|
||||||
const api = useApi();
|
|
||||||
const tokenFromStore = useSelector(selectors.selectToken);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [paymentIntent, setPaymentIntent] = useState<
|
|
||||||
ResponsePost | ResponsePostExistPaymentData | null
|
|
||||||
>(null);
|
|
||||||
const [isError, setIsError] = useState(false);
|
|
||||||
const returnUrl = `${window.location.protocol}//${
|
|
||||||
window.location.host
|
|
||||||
}${routes.client.addConsultation()}`;
|
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
return await api.getSinglePaymentProducts({ token: tokenFromStore });
|
|
||||||
}, [api, tokenFromStore]);
|
|
||||||
|
|
||||||
const { data: products, isPending: isPendingProducts } =
|
|
||||||
useApiCall<SinglePayment.ResponseGet[]>(loadData);
|
|
||||||
|
|
||||||
const currentProduct = products?.find(
|
|
||||||
(product) => product.key === "main.unlimited.readings"
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClick = async () => {
|
|
||||||
if (!userFromStore || !currentProduct) return;
|
|
||||||
setIsLoading(true);
|
|
||||||
const paymentIntent = await createSinglePayment(
|
|
||||||
userFromStore,
|
|
||||||
currentProduct.productId,
|
|
||||||
tokenFromStore,
|
|
||||||
userFromStore.email,
|
|
||||||
userFromStore.profile.full_name,
|
|
||||||
userFromStore.profile.birthday,
|
|
||||||
returnUrl,
|
|
||||||
api
|
|
||||||
);
|
|
||||||
setPaymentIntent(paymentIntent);
|
|
||||||
setIsLoading(false);
|
|
||||||
if ("payment" in paymentIntent) {
|
|
||||||
if (paymentIntent.payment.status === "paid")
|
|
||||||
return navigate(routes.client.addConsultation());
|
|
||||||
return setIsError(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickSkip = () => {
|
|
||||||
navigate(routes.client.addConsultation());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{!isLoading &&
|
|
||||||
paymentIntent &&
|
|
||||||
"paymentIntent" in paymentIntent &&
|
|
||||||
!!tokenFromStore.length && (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
open={!!paymentIntent}
|
|
||||||
onClose={() => setPaymentIntent(null)}
|
|
||||||
>
|
|
||||||
<Title variant="h1" className={styles["modal-title"]}>
|
|
||||||
{getPriceCentsToDollars(currentProduct?.amount || 0)}$
|
|
||||||
</Title>
|
|
||||||
<PaymentForm
|
|
||||||
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
|
|
||||||
clientSecret={paymentIntent.paymentIntent.data.client_secret}
|
|
||||||
returnUrl={returnUrl}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Slider {...sliderSettings}>
|
<Slider {...sliderSettings}>
|
||||||
<FirstSlide />
|
<FirstSlide />
|
||||||
<div className={styles.slider}>
|
<div className={styles.slider}>
|
||||||
@ -133,24 +54,14 @@ function UnlimitedReadingsPage() {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
{isError && (
|
|
||||||
<p className={styles.error}>
|
|
||||||
Something went wrong. Please try again later.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<FooterButton
|
<FooterButton
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onClickSkip={handleClickSkip}
|
onClickSkip={handleClick}
|
||||||
classNameContainer={styles["buttons-container"]}
|
classNameContainer={styles["buttons-container"]}
|
||||||
classNameButton={styles.button}
|
classNameButton={styles.button}
|
||||||
classNameSkip={styles.skip}
|
classNameSkip={styles.skip}
|
||||||
disabled={isPendingProducts || isLoading}
|
|
||||||
>
|
>
|
||||||
{isPendingProducts || isLoading ? (
|
Add unlimited readings
|
||||||
<Loader color={LoaderColor.White} />
|
|
||||||
) : (
|
|
||||||
"Add unlimited readings"
|
|
||||||
)}
|
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
<p className={styles.policy}>
|
<p className={styles.policy}>
|
||||||
Please note: In addition to your subscription, your account will be
|
Please note: In addition to your subscription, your account will be
|
||||||
|
|||||||
@ -82,12 +82,3 @@
|
|||||||
height: 189px;
|
height: 189px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
|
||||||
max-width: 526px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import Title from "@/components/Title";
|
|
||||||
import styles from "./styles.module.css";
|
|
||||||
import MainButton from "@/components/MainButton";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import routes from "@/routes";
|
|
||||||
|
|
||||||
function GetInformationPartnerPage() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleBack = () => {
|
|
||||||
navigate(routes.client.addConsultation());
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNext = () => {
|
|
||||||
navigate(routes.client.home());
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className={`${styles.page} page`}>
|
|
||||||
<video className={styles["background-video"]} loop autoPlay muted>
|
|
||||||
<source src="/videos/background-video-1.mp4" type="video/mp4" />
|
|
||||||
<source src="/videos/background-video-1.mp4" type="video/ogg" />
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
<Title variant="h2" className={styles.title}>
|
|
||||||
AURA
|
|
||||||
</Title>
|
|
||||||
<div className={styles["bottom-container"]}>
|
|
||||||
<Title variant="h3" className={styles.subtitle}>
|
|
||||||
Wonderful! Let's find out what's working (and what isn't) and go from
|
|
||||||
there.
|
|
||||||
</Title>
|
|
||||||
<p className={styles.description}>
|
|
||||||
Now we need some information about Your Partner's Profile to create
|
|
||||||
the astrological synastry blueprint between you and your partner.
|
|
||||||
</p>
|
|
||||||
<div className={styles["buttons-container"]}>
|
|
||||||
<MainButton
|
|
||||||
onClick={handleBack}
|
|
||||||
className={`${styles.button} ${styles["back-button"]}`}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</MainButton>
|
|
||||||
<MainButton
|
|
||||||
onClick={handleNext}
|
|
||||||
className={`${styles.button} ${styles["next-button"]}`}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</MainButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GetInformationPartnerPage;
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
.page {
|
|
||||||
background-color: #171717;
|
|
||||||
height: fit-content;
|
|
||||||
min-height: 100dvh;
|
|
||||||
color: #fff;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin-top: 58px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
min-width: 0;
|
|
||||||
min-height: 0;
|
|
||||||
width: 160px;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-button {
|
|
||||||
background-color: transparent;
|
|
||||||
border: 2px solid #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next-button {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 170px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
line-height: 140%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.background-video {
|
|
||||||
position: fixed;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
top: 0;
|
|
||||||
padding: 0;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
@ -12,6 +12,7 @@ import { getClientTimezone } from "@/locales";
|
|||||||
import ErrorText from "@/components/ErrorText";
|
import ErrorText from "@/components/ErrorText";
|
||||||
import Title from "@/components/Title";
|
import Title from "@/components/Title";
|
||||||
import NameInput from "@/components/EmailEnterPage/NameInput";
|
import NameInput from "@/components/EmailEnterPage/NameInput";
|
||||||
|
import { getZodiacSignByDate } from "@/services/zodiac-sign";
|
||||||
import {
|
import {
|
||||||
ResponseGet,
|
ResponseGet,
|
||||||
ResponsePost,
|
ResponsePost,
|
||||||
@ -21,7 +22,7 @@ import { useNavigate } from "react-router-dom";
|
|||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
import PaymentForm from "./PaymentForm";
|
import PaymentForm from "./PaymentForm";
|
||||||
import { getPriceCentsToDollars } from "@/services/price";
|
import { getPriceCentsToDollars } from "@/services/price";
|
||||||
import { createSinglePayment } from "@/services/singlePayment";
|
import { User } from "@/api/resources/User";
|
||||||
|
|
||||||
function PaymentWithEmailPage() {
|
function PaymentWithEmailPage() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
@ -174,10 +175,7 @@ function PaymentWithEmailPage() {
|
|||||||
productId,
|
productId,
|
||||||
token,
|
token,
|
||||||
email,
|
email,
|
||||||
name,
|
name
|
||||||
birthday,
|
|
||||||
returnUrl,
|
|
||||||
api
|
|
||||||
);
|
);
|
||||||
setPaymentIntent(paymentIntent);
|
setPaymentIntent(paymentIntent);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -206,10 +204,7 @@ function PaymentWithEmailPage() {
|
|||||||
productId,
|
productId,
|
||||||
tokenFromStore,
|
tokenFromStore,
|
||||||
userFromStore.email,
|
userFromStore.email,
|
||||||
userFromStore.profile.full_name,
|
userFromStore.profile.full_name
|
||||||
userFromStore.profile.birthday,
|
|
||||||
returnUrl,
|
|
||||||
api
|
|
||||||
);
|
);
|
||||||
setPaymentIntent(paymentIntent);
|
setPaymentIntent(paymentIntent);
|
||||||
setIsLoadingPage(false);
|
setIsLoadingPage(false);
|
||||||
|
|||||||
@ -37,7 +37,6 @@ export interface ISignUpOffer {
|
|||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
productKey: string;
|
|
||||||
price: ISignUpOfferPrice;
|
price: ISignUpOfferPrice;
|
||||||
emoji: string;
|
emoji: string;
|
||||||
}
|
}
|
||||||
@ -48,44 +47,40 @@ export const signUpOffers: ISignUpOffer[] = [
|
|||||||
title: "ULTRA PACK",
|
title: "ULTRA PACK",
|
||||||
subtitle: "(3 in 1 + 2 secret bonus reading)",
|
subtitle: "(3 in 1 + 2 secret bonus reading)",
|
||||||
price: {
|
price: {
|
||||||
current: 4999,
|
current: 49.99,
|
||||||
old: 9999,
|
old: 99.99,
|
||||||
discount: 50,
|
discount: 50,
|
||||||
},
|
},
|
||||||
productKey: "main.ultra.pack",
|
|
||||||
emoji: "star_struck.png",
|
emoji: "star_struck.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "numerology-analyses",
|
id: "numerology-analyses",
|
||||||
title: "NUMEROLOGY ANALYSIS",
|
title: "NUMEROLOGY ANALYSIS",
|
||||||
price: {
|
price: {
|
||||||
current: 1499,
|
current: 14.99,
|
||||||
old: 2999,
|
old: 29.99,
|
||||||
discount: 50,
|
discount: 50,
|
||||||
},
|
},
|
||||||
productKey: "main.numerology.analysis",
|
|
||||||
emoji: "input_numbers.png",
|
emoji: "input_numbers.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "tarot-reading",
|
id: "tarot-reading",
|
||||||
title: "TAROT READING",
|
title: "TAROT READING",
|
||||||
price: {
|
price: {
|
||||||
current: 1999,
|
current: 19.99,
|
||||||
old: 3499,
|
old: 34.99,
|
||||||
discount: 45,
|
discount: 45,
|
||||||
},
|
},
|
||||||
productKey: "main.tarot.reading",
|
|
||||||
emoji: "sunset.png",
|
emoji: "sunset.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "palmistry-guide",
|
id: "palmistry-guide",
|
||||||
title: "PALMISTRY GUIDE",
|
title: "PALMISTRY GUIDE",
|
||||||
price: {
|
price: {
|
||||||
current: 1999,
|
current: 19.99,
|
||||||
old: 2999,
|
old: 29.99,
|
||||||
discount: 30,
|
discount: 30,
|
||||||
},
|
},
|
||||||
productKey: "main.palmistry.guide",
|
|
||||||
emoji: "rised_hand.png",
|
emoji: "rised_hand.png",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -4,10 +4,7 @@ const isProduction = import.meta.env.MODE === "production";
|
|||||||
|
|
||||||
const host = "";
|
const host = "";
|
||||||
export const apiHost = "https://api-web.aura.wit.life";
|
export const apiHost = "https://api-web.aura.wit.life";
|
||||||
const dApiHost = isProduction
|
const dApiHost = isProduction ? "https://d.api.witapps.us" : "https://dev.api.witapps.us"
|
||||||
? "https://d.api.witapps.us"
|
|
||||||
: "https://dev.api.witapps.us";
|
|
||||||
// const dApiHost = "https://d.api.witapps.us";
|
|
||||||
const siteHost = "https://aura.wit.life";
|
const siteHost = "https://aura.wit.life";
|
||||||
const prefix = "api/v1";
|
const prefix = "api/v1";
|
||||||
const openAIHost = " https://api.openai.com";
|
const openAIHost = " https://api.openai.com";
|
||||||
@ -41,8 +38,7 @@ const routes = {
|
|||||||
palmistryPaywall: () => [host, "palmistry", "paywall"].join("/"),
|
palmistryPaywall: () => [host, "palmistry", "paywall"].join("/"),
|
||||||
palmistryPayment: () => [host, "palmistry", "payment"].join("/"),
|
palmistryPayment: () => [host, "palmistry", "payment"].join("/"),
|
||||||
palmistryDiscount: () => [host, "palmistry", "discount"].join("/"),
|
palmistryDiscount: () => [host, "palmistry", "discount"].join("/"),
|
||||||
palmistryPremiumBundle: () =>
|
palmistryPremiumBundle: () => [host, "palmistry", "premium-bundle"].join("/"),
|
||||||
[host, "palmistry", "premium-bundle"].join("/"),
|
|
||||||
birthday: () => [host, "birthday"].join("/"),
|
birthday: () => [host, "birthday"].join("/"),
|
||||||
didYouKnow: () => [host, "did-you-know"].join("/"),
|
didYouKnow: () => [host, "did-you-know"].join("/"),
|
||||||
freePeriodInfo: () => [host, "free-period"].join("/"),
|
freePeriodInfo: () => [host, "free-period"].join("/"),
|
||||||
@ -132,8 +128,6 @@ const routes = {
|
|||||||
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),
|
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),
|
||||||
epeFailPayment: () => [host, "epe", "fail-payment"].join("/"),
|
epeFailPayment: () => [host, "epe", "fail-payment"].join("/"),
|
||||||
|
|
||||||
getInformationPartner: () => [host, "get-information-partner"].join("/"),
|
|
||||||
|
|
||||||
notFound: () => [host, "404"].join("/"),
|
notFound: () => [host, "404"].join("/"),
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
@ -317,7 +311,6 @@ export const withoutFooterRoutes = [
|
|||||||
routes.client.addConsultation(),
|
routes.client.addConsultation(),
|
||||||
routes.client.advisors(),
|
routes.client.advisors(),
|
||||||
routes.client.epeSuccessPayment(),
|
routes.client.epeSuccessPayment(),
|
||||||
routes.client.getInformationPartner(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const withoutFooterPartOfRoutes = [
|
export const withoutFooterPartOfRoutes = [
|
||||||
@ -392,7 +385,6 @@ export const withoutHeaderRoutes = [
|
|||||||
routes.client.tryApp(),
|
routes.client.tryApp(),
|
||||||
routes.client.advisors(),
|
routes.client.advisors(),
|
||||||
routes.client.epeSuccessPayment(),
|
routes.client.epeSuccessPayment(),
|
||||||
routes.client.getInformationPartner(),
|
|
||||||
];
|
];
|
||||||
export const hasNoHeader = (path: string) => {
|
export const hasNoHeader = (path: string) => {
|
||||||
let result = true;
|
let result = true;
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { User } from "@/api/resources/User";
|
|
||||||
import { getZodiacSignByDate } from "../zodiac-sign";
|
|
||||||
import { ApiContextValue } from "@/api";
|
|
||||||
|
|
||||||
export const createSinglePayment = async (
|
|
||||||
user: User,
|
|
||||||
productId: string,
|
|
||||||
token: string,
|
|
||||||
email: string,
|
|
||||||
name: string | null,
|
|
||||||
birthday: string | null,
|
|
||||||
returnUrl: string,
|
|
||||||
api: ApiContextValue
|
|
||||||
) => {
|
|
||||||
return await api.createSinglePayment({
|
|
||||||
token,
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
id: `${user?.id}`,
|
|
||||||
email,
|
|
||||||
name: name || "",
|
|
||||||
sign: user?.profile?.sign?.sign || getZodiacSignByDate(birthday || ""),
|
|
||||||
age: user?.profile?.age?.years || 1,
|
|
||||||
},
|
|
||||||
partner: {
|
|
||||||
sign: "partner_cancer",
|
|
||||||
age: 26,
|
|
||||||
},
|
|
||||||
paymentInfo: {
|
|
||||||
productId,
|
|
||||||
},
|
|
||||||
return_url: returnUrl,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Loading…
Reference in New Issue
Block a user