Develop
This commit is contained in:
parent
a365a9eb40
commit
2ee80ee89f
BIN
public/videos/background-video-1.mp4
Normal file
BIN
public/videos/background-video-1.mp4
Normal file
Binary file not shown.
@ -67,6 +67,7 @@ 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),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export interface PayloadPost extends Payload {
|
|||||||
name: string;
|
name: string;
|
||||||
sign: string;
|
sign: string;
|
||||||
age: number;
|
age: number;
|
||||||
|
gender?: string;
|
||||||
};
|
};
|
||||||
partner: {
|
partner: {
|
||||||
sign: string | null;
|
sign: string | null;
|
||||||
|
|||||||
@ -109,6 +109,7 @@ 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";
|
||||||
|
|
||||||
@ -233,9 +234,18 @@ 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 path={routes.client.epePayment()} element={<PaymentWithEmailPage />} />
|
<Route
|
||||||
<Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} />
|
path={routes.client.epePayment()}
|
||||||
<Route path={routes.client.epeFailPayment()} element={<FailPaymentPage />} />
|
element={<PaymentWithEmailPage />}
|
||||||
|
/>
|
||||||
|
<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 */}
|
||||||
@ -351,19 +361,29 @@ function App(): JSX.Element {
|
|||||||
{/* Email Letters End */}
|
{/* Email Letters End */}
|
||||||
|
|
||||||
{/* Additional Purchases */}
|
{/* Additional Purchases */}
|
||||||
<Route element={<AdditionalPurchases />}>
|
<Route element={<PrivateOutlet />}>
|
||||||
<Route path={routes.client.addReport()} element={<AddReportPage />} />
|
<Route element={<AdditionalPurchases />}>
|
||||||
<Route
|
<Route
|
||||||
path={routes.client.unlimitedReadings()}
|
path={routes.client.addReport()}
|
||||||
element={<UnlimitedReadingsPage />}
|
element={<AddReportPage />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={routes.client.addConsultation()}
|
path={routes.client.unlimitedReadings()}
|
||||||
element={<AddConsultationPage />}
|
element={<UnlimitedReadingsPage />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path={routes.client.addConsultation()}
|
||||||
|
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 />}
|
||||||
|
|||||||
@ -27,7 +27,11 @@ function PaymentSuccessPage(): JSX.Element {
|
|||||||
<Title variant="h1">{t("auweb.pay_good.title")}</Title>
|
<Title variant="h1">{t("auweb.pay_good.title")}</Title>
|
||||||
<p>{t("auweb.pay_good.text1")}</p>
|
<p>{t("auweb.pay_good.text1")}</p>
|
||||||
</div>
|
</div>
|
||||||
<MainButton className={styles.button} onClick={handleNext}>
|
<MainButton
|
||||||
|
className={styles.button}
|
||||||
|
onClick={handleNext}
|
||||||
|
id="success-payment"
|
||||||
|
>
|
||||||
{t("auweb.pay_good.button")}
|
{t("auweb.pay_good.button")}
|
||||||
</MainButton>
|
</MainButton>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -17,11 +18,13 @@ 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,6 +1,7 @@
|
|||||||
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;
|
||||||
@ -31,9 +32,14 @@ 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"]}>${current}</span> ({" "}
|
<span className={styles["current-price"]}>
|
||||||
{id === "ultra-pack" ? "regular price" : "was"}{" "}
|
${getPriceCentsToDollars(current || 0)}
|
||||||
<span className={styles["old-price"]}>${old}</span> )
|
</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,14 +5,93 @@ 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 handleNext = () => {
|
const { user: userFromStore } = useAuth();
|
||||||
navigate(routes.client.home());
|
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.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>
|
||||||
@ -27,11 +106,22 @@ 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={handleNext}
|
onClick={handleClick}
|
||||||
onClickSkip={handleNext}
|
onClickSkip={handleClickSkip}
|
||||||
children="Get my consultation"
|
disabled={isPendingProducts || isLoading}
|
||||||
/>
|
>
|
||||||
|
{isPendingProducts || isLoading ? (
|
||||||
|
<Loader color={LoaderColor.White} />
|
||||||
|
) : (
|
||||||
|
"Get my consultation"
|
||||||
|
)}
|
||||||
|
</FooterButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,3 +36,12 @@
|
|||||||
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,22 +3,102 @@ 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 { useState } from "react";
|
import { useCallback, 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 [activeOffer, setActiveOffer] = useState(signUpOffers[0].id);
|
const { user: userFromStore } = useAuth();
|
||||||
|
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 handleClick = () => {
|
const loadData = useCallback(async () => {
|
||||||
|
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 🔥
|
||||||
@ -27,26 +107,33 @@ function AddReportPage() {
|
|||||||
Available only now
|
Available only now
|
||||||
</Title>
|
</Title>
|
||||||
<div className={styles["offers-container"]}>
|
<div className={styles["offers-container"]}>
|
||||||
{signUpOffers.map((offer, index) => (
|
{!isPendingProducts &&
|
||||||
<SignUpOffer
|
signUpOffers.map((offer, index) => (
|
||||||
key={index}
|
<SignUpOffer
|
||||||
id={offer.id}
|
key={index}
|
||||||
title={offer.title}
|
isActive={offer.id === activeOffer.id}
|
||||||
subtitle={offer.subtitle}
|
onClick={() => setActiveOffer(offer)}
|
||||||
price={offer.price}
|
{...offer}
|
||||||
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 onClick={handleClick} onClickSkip={handleClick}>
|
<FooterButton
|
||||||
Get my copy
|
onClick={handleClick}
|
||||||
|
onClickSkip={handleClickSkip}
|
||||||
|
disabled={isPendingProducts || isLoading}
|
||||||
|
>
|
||||||
|
{isLoading ? <Loader color={LoaderColor.White} /> : "Get my copy"}
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -34,6 +34,10 @@
|
|||||||
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;
|
||||||
@ -56,3 +60,7 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: rgb(79, 79, 79);
|
color: rgb(79, 79, 79);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|||||||
@ -9,26 +9,105 @@ 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 = {
|
||||||
|
dots: false,
|
||||||
|
infinite: false,
|
||||||
|
speed: 500,
|
||||||
|
slidesToShow: 1,
|
||||||
|
slidesToScroll: 1,
|
||||||
|
className: styles["slider-container"],
|
||||||
|
nextArrow: <SliderNextArrow />,
|
||||||
|
prevArrow: <SliderPrevArrow />,
|
||||||
|
};
|
||||||
|
|
||||||
function UnlimitedReadingsPage() {
|
function UnlimitedReadingsPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const handleClick = () => {
|
const { user: userFromStore } = useAuth();
|
||||||
navigate(routes.client.addConsultation());
|
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 sliderSettings = {
|
const handleClickSkip = () => {
|
||||||
dots: false,
|
navigate(routes.client.addConsultation());
|
||||||
infinite: false,
|
|
||||||
speed: 500,
|
|
||||||
slidesToShow: 1,
|
|
||||||
slidesToScroll: 1,
|
|
||||||
className: styles["slider-container"],
|
|
||||||
nextArrow: <SliderNextArrow />,
|
|
||||||
prevArrow: <SliderPrevArrow />,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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}>
|
||||||
@ -54,14 +133,24 @@ 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={handleClick}
|
onClickSkip={handleClickSkip}
|
||||||
classNameContainer={styles["buttons-container"]}
|
classNameContainer={styles["buttons-container"]}
|
||||||
classNameButton={styles.button}
|
classNameButton={styles.button}
|
||||||
classNameSkip={styles.skip}
|
classNameSkip={styles.skip}
|
||||||
|
disabled={isPendingProducts || isLoading}
|
||||||
>
|
>
|
||||||
Add unlimited readings
|
{isPendingProducts || isLoading ? (
|
||||||
|
<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,3 +82,12 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ function GenderPage(): JSX.Element {
|
|||||||
|
|
||||||
const selectGender = (gender: Gender) => {
|
const selectGender = (gender: Gender) => {
|
||||||
dispatch(actions.questionnaire.update({ gender: gender.id }));
|
dispatch(actions.questionnaire.update({ gender: gender.id }));
|
||||||
if (pathName === "/epe/gender") {
|
if (pathName.includes("/epe/gender")) {
|
||||||
return navigate(routes.client.epeBirthdate());
|
return navigate(routes.client.epeBirthdate());
|
||||||
}
|
}
|
||||||
navigate(`/questionnaire/profile/flowChoice`);
|
navigate(`/questionnaire/profile/flowChoice`);
|
||||||
|
|||||||
56
src/components/pages/GetInformationPartner/index.tsx
Normal file
56
src/components/pages/GetInformationPartner/index.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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;
|
||||||
64
src/components/pages/GetInformationPartner/styles.module.css
Normal file
64
src/components/pages/GetInformationPartner/styles.module.css
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
.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,7 +12,6 @@ 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,
|
||||||
@ -22,7 +21,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 { User } from "@/api/resources/User";
|
import { createSinglePayment } from "@/services/singlePayment";
|
||||||
|
|
||||||
function PaymentWithEmailPage() {
|
function PaymentWithEmailPage() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
@ -33,6 +32,7 @@ function PaymentWithEmailPage() {
|
|||||||
const timezone = getClientTimezone();
|
const timezone = getClientTimezone();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const birthday = useSelector(selectors.selectBirthday);
|
const birthday = useSelector(selectors.selectBirthday);
|
||||||
|
const { gender } = useSelector(selectors.selectQuestionnaire);
|
||||||
const locale = i18n.language;
|
const locale = i18n.language;
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
@ -119,40 +119,11 @@ function PaymentWithEmailPage() {
|
|||||||
token,
|
token,
|
||||||
});
|
});
|
||||||
const currentProduct = productsSinglePayment.find(
|
const currentProduct = productsSinglePayment.find(
|
||||||
(product) => product.key === "compatibility.pdf"
|
(product) => product.key === "moons.pdf.aura"
|
||||||
);
|
);
|
||||||
return currentProduct;
|
return currentProduct;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSinglePayment = async (
|
|
||||||
user: User,
|
|
||||||
productId: string,
|
|
||||||
token: string,
|
|
||||||
email: string,
|
|
||||||
name: string | null
|
|
||||||
) => {
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
const authData = await authorization();
|
const authData = await authorization();
|
||||||
if (!authData) {
|
if (!authData) {
|
||||||
@ -173,7 +144,11 @@ function PaymentWithEmailPage() {
|
|||||||
productId,
|
productId,
|
||||||
token,
|
token,
|
||||||
email,
|
email,
|
||||||
name
|
name,
|
||||||
|
birthday,
|
||||||
|
returnUrl,
|
||||||
|
api,
|
||||||
|
gender
|
||||||
);
|
);
|
||||||
setPaymentIntent(paymentIntent);
|
setPaymentIntent(paymentIntent);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -202,7 +177,11 @@ function PaymentWithEmailPage() {
|
|||||||
productId,
|
productId,
|
||||||
tokenFromStore,
|
tokenFromStore,
|
||||||
userFromStore.email,
|
userFromStore.email,
|
||||||
userFromStore.profile.full_name
|
userFromStore.profile.full_name,
|
||||||
|
userFromStore.profile.birthday,
|
||||||
|
returnUrl,
|
||||||
|
api,
|
||||||
|
gender
|
||||||
);
|
);
|
||||||
setPaymentIntent(paymentIntent);
|
setPaymentIntent(paymentIntent);
|
||||||
setIsLoadingPage(false);
|
setIsLoadingPage(false);
|
||||||
|
|||||||
@ -37,6 +37,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -47,40 +48,44 @@ 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: 49.99,
|
current: 4999,
|
||||||
old: 99.99,
|
old: 9999,
|
||||||
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: 14.99,
|
current: 1499,
|
||||||
old: 29.99,
|
old: 2999,
|
||||||
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: 19.99,
|
current: 1999,
|
||||||
old: 34.99,
|
old: 3499,
|
||||||
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: 19.99,
|
current: 1999,
|
||||||
old: 29.99,
|
old: 2999,
|
||||||
discount: 30,
|
discount: 30,
|
||||||
},
|
},
|
||||||
|
productKey: "main.palmistry.guide",
|
||||||
emoji: "rised_hand.png",
|
emoji: "rised_hand.png",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -4,7 +4,10 @@ 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 ? "https://d.api.witapps.us" : "https://dev.api.witapps.us"
|
const dApiHost = isProduction
|
||||||
|
? "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";
|
||||||
@ -38,7 +41,8 @@ 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: () => [host, "palmistry", "premium-bundle"].join("/"),
|
palmistryPremiumBundle: () =>
|
||||||
|
[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("/"),
|
||||||
@ -128,6 +132,8 @@ 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: {
|
||||||
@ -311,6 +317,7 @@ 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 = [
|
||||||
@ -385,6 +392,7 @@ 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;
|
||||||
|
|||||||
37
src/services/singlePayment/index.ts
Normal file
37
src/services/singlePayment/index.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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,
|
||||||
|
gender?: string
|
||||||
|
) => {
|
||||||
|
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,
|
||||||
|
gender: gender || "",
|
||||||
|
},
|
||||||
|
partner: {
|
||||||
|
sign: "partner_cancer",
|
||||||
|
age: 26,
|
||||||
|
},
|
||||||
|
paymentInfo: {
|
||||||
|
productId,
|
||||||
|
},
|
||||||
|
return_url: returnUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user