Preview/additional purchases

This commit is contained in:
Денис Катаев 2024-04-03 11:17:58 +00:00 committed by Daniil Chemerkin
parent a033e4c542
commit f088690aa5
18 changed files with 570 additions and 97 deletions

Binary file not shown.

View File

@ -67,6 +67,7 @@ const api = {
runThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
getStatusRunThread: createMethod<OpenAI.PayloadRunThread, OpenAI.ResponseGetStatusRunThread>(OpenAI.createRequest),
getListRuns: createMethod<OpenAI.PayloadGetListRuns, OpenAI.ResponseGetListRuns>(OpenAI.createRequest),
// Single payment
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
}

View File

@ -109,6 +109,7 @@ import AdvisorChatPage from "../pages/AdvisorChat";
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
import GetInformationPartnerPage from "../pages/GetInformationPartner";
const isProduction = import.meta.env.MODE === "production";
@ -233,9 +234,18 @@ function App(): JSX.Element {
{/* Email - Pay - Email */}
<Route path={routes.client.epeGender()} element={<GenderPage />} />
<Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} />
<Route path={routes.client.epePayment()} element={<PaymentWithEmailPage />} />
<Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} />
<Route path={routes.client.epeFailPayment()} element={<FailPaymentPage />} />
<Route
path={routes.client.epePayment()}
element={<PaymentWithEmailPage />}
/>
<Route
path={routes.client.epeSuccessPayment()}
element={<SuccessPaymentPage />}
/>
<Route
path={routes.client.epeFailPayment()}
element={<FailPaymentPage />}
/>
{/* Email - Pay - Email */}
{/* Test Routes Start */}
@ -351,19 +361,29 @@ function App(): JSX.Element {
{/* Email Letters End */}
{/* Additional Purchases */}
<Route element={<AdditionalPurchases />}>
<Route path={routes.client.addReport()} element={<AddReportPage />} />
<Route
path={routes.client.unlimitedReadings()}
element={<UnlimitedReadingsPage />}
/>
<Route
path={routes.client.addConsultation()}
element={<AddConsultationPage />}
/>
<Route element={<PrivateOutlet />}>
<Route element={<AdditionalPurchases />}>
<Route
path={routes.client.addReport()}
element={<AddReportPage />}
/>
<Route
path={routes.client.unlimitedReadings()}
element={<UnlimitedReadingsPage />}
/>
<Route
path={routes.client.addConsultation()}
element={<AddConsultationPage />}
/>
</Route>
</Route>
{/* Additional Purchases End */}
<Route
path={routes.client.getInformationPartner()}
element={<GetInformationPartnerPage />}
/>
<Route
path={routes.client.paymentResult()}
element={<PaymentResultPage />}

View File

@ -27,7 +27,11 @@ function PaymentSuccessPage(): JSX.Element {
<Title variant="h1">{t("auweb.pay_good.title")}</Title>
<p>{t("auweb.pay_good.text1")}</p>
</div>
<MainButton className={styles.button} onClick={handleNext}>
<MainButton
className={styles.button}
onClick={handleNext}
id="success-payment"
>
{t("auweb.pay_good.button")}
</MainButton>
</section>

View File

@ -6,6 +6,7 @@ interface IFooterButtonProps {
classNameButton?: string;
classNameSkip?: string;
children?: React.ReactNode;
disabled?: boolean;
onClick: () => void;
onClickSkip: () => void;
}
@ -17,11 +18,13 @@ function FooterButton({
classNameContainer = "",
classNameButton = "",
classNameSkip = "",
disabled = false,
}: IFooterButtonProps) {
return (
<div className={`${styles.container} ${classNameContainer}`}>
<MainButton
className={`${styles.button} ${classNameButton}`}
disabled={disabled}
onClick={onClick}
>
{children}

View File

@ -1,6 +1,7 @@
import { ISignUpOffer } from "@/data/additionalPurchases";
import styles from "./styles.module.css";
import CheckMark from "./check-mark-1.svg";
import { getPriceCentsToDollars } from "@/services/price";
interface ISignUpOfferProps extends ISignUpOffer {
isActive: boolean;
@ -31,9 +32,14 @@ function SignUpOffer(props: ISignUpOfferProps) {
)}
<div className={styles["price-container"]}>
<span className={styles.price}>
<span className={styles["current-price"]}>${current}</span> ({" "}
{id === "ultra-pack" ? "regular price" : "was"}{" "}
<span className={styles["old-price"]}>${old}</span> )
<span className={styles["current-price"]}>
${getPriceCentsToDollars(current || 0)}
</span>{" "}
( {id === "ultra-pack" ? "regular price" : "was"}{" "}
<span className={styles["old-price"]}>
${getPriceCentsToDollars(old || 0)}
</span>{" "}
)
</span>
{id !== "ultra-pack" && (
<div className={styles["discount-container"]}>

View File

@ -5,14 +5,93 @@ import PaymentAddress from "../../components/PaymentAddress";
import FooterButton from "../../components/FooterButton";
import { useNavigate } from "react-router-dom";
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() {
const navigate = useNavigate();
const handleNext = () => {
navigate(routes.client.home());
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.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 (
<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}>
More for you
</Title>
@ -27,11 +106,22 @@ function AddConsultationPage() {
This is a non-recuring payment.
</p>
<PaymentAddress />
{isError && (
<p className={styles.error}>
Something went wrong. Please try again later.
</p>
)}
<FooterButton
onClick={handleNext}
onClickSkip={handleNext}
children="Get my consultation"
/>
onClick={handleClick}
onClickSkip={handleClickSkip}
disabled={isPendingProducts || isLoading}
>
{isPendingProducts || isLoading ? (
<Loader color={LoaderColor.White} />
) : (
"Get my consultation"
)}
</FooterButton>
</div>
);
}

View File

@ -36,3 +36,12 @@
line-height: 140%;
color: rgb(79, 79, 79);
}
.error {
max-width: 526px;
margin-left: auto;
margin-right: auto;
text-align: center;
font-size: 14px;
color: red;
}

View File

@ -3,22 +3,102 @@ import ThankYouBanner from "../../components/ThankYouBanner";
import styles from "./styles.module.css";
import { signUpOffers } from "@/data/additionalPurchases";
import SignUpOffer from "../../components/SignUpOffer";
import { useState } from "react";
import { useCallback, useState } from "react";
import { useNavigate } from "react-router-dom";
import FooterButton from "../../components/FooterButton";
import routes from "@/routes";
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() {
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());
};
return (
<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 />
<Title variant="h2" className={styles.title}>
Choose your sign-up offer 🔥
@ -27,26 +107,33 @@ function AddReportPage() {
Available only now
</Title>
<div className={styles["offers-container"]}>
{signUpOffers.map((offer, index) => (
<SignUpOffer
key={index}
id={offer.id}
title={offer.title}
subtitle={offer.subtitle}
price={offer.price}
emoji={offer.emoji}
isActive={offer.id === activeOffer}
onClick={() => setActiveOffer(offer.id)}
/>
))}
{!isPendingProducts &&
signUpOffers.map((offer, index) => (
<SignUpOffer
key={index}
isActive={offer.id === activeOffer.id}
onClick={() => setActiveOffer(offer)}
{...offer}
/>
))}
{isPendingProducts && <Loader color={LoaderColor.Black} />}
</div>
<p className={styles.description}>
*You will be charged for the add-on services or offers selected at the
time of purchase. This is a non-recuring payment.
</p>
{isError && (
<p className={`${styles.description} ${styles.error}`}>
Something went wrong. Please try again later.
</p>
)}
<PaymentAddress />
<FooterButton onClick={handleClick} onClickSkip={handleClick}>
Get my copy
<FooterButton
onClick={handleClick}
onClickSkip={handleClickSkip}
disabled={isPendingProducts || isLoading}
>
{isLoading ? <Loader color={LoaderColor.White} /> : "Get my copy"}
</FooterButton>
</div>
);

View File

@ -34,6 +34,10 @@
margin-bottom: 0;
}
.modal-title {
margin-bottom: 16px;
}
.subtitle {
font-size: 18px;
text-align: center;
@ -56,3 +60,7 @@
margin-bottom: 20px;
color: rgb(79, 79, 79);
}
.error {
color: red;
}

View File

@ -9,26 +9,105 @@ import SliderNextArrow from "../../components/SliderNextArrow";
import SliderPrevArrow from "../../components/SliderPrevArrow";
import routes from "@/routes";
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() {
const navigate = useNavigate();
const handleClick = () => {
navigate(routes.client.addConsultation());
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 sliderSettings = {
dots: false,
infinite: false,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
className: styles["slider-container"],
nextArrow: <SliderNextArrow />,
prevArrow: <SliderPrevArrow />,
const handleClickSkip = () => {
navigate(routes.client.addConsultation());
};
return (
<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}>
<FirstSlide />
<div className={styles.slider}>
@ -54,14 +133,24 @@ function UnlimitedReadingsPage() {
</li>
))}
</ul>
{isError && (
<p className={styles.error}>
Something went wrong. Please try again later.
</p>
)}
<FooterButton
onClick={handleClick}
onClickSkip={handleClick}
onClickSkip={handleClickSkip}
classNameContainer={styles["buttons-container"]}
classNameButton={styles.button}
classNameSkip={styles.skip}
disabled={isPendingProducts || isLoading}
>
Add unlimited readings
{isPendingProducts || isLoading ? (
<Loader color={LoaderColor.White} />
) : (
"Add unlimited readings"
)}
</FooterButton>
<p className={styles.policy}>
Please note: In addition to your subscription, your account will be

View File

@ -82,3 +82,12 @@
height: 189px;
object-fit: contain;
}
.error {
max-width: 526px;
margin-left: auto;
margin-right: auto;
text-align: center;
font-size: 14px;
color: red;
}

View 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;

View 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;
}

View File

@ -12,7 +12,6 @@ import { getClientTimezone } from "@/locales";
import ErrorText from "@/components/ErrorText";
import Title from "@/components/Title";
import NameInput from "@/components/EmailEnterPage/NameInput";
import { getZodiacSignByDate } from "@/services/zodiac-sign";
import {
ResponseGet,
ResponsePost,
@ -22,7 +21,7 @@ import { useNavigate } from "react-router-dom";
import routes from "@/routes";
import PaymentForm from "./PaymentForm";
import { getPriceCentsToDollars } from "@/services/price";
import { User } from "@/api/resources/User";
import { createSinglePayment } from "@/services/singlePayment";
function PaymentWithEmailPage() {
const { t, i18n } = useTranslation();
@ -125,36 +124,6 @@ function PaymentWithEmailPage() {
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,
gender: gender,
},
partner: {
sign: "partner_cancer",
age: 26,
},
paymentInfo: {
productId,
},
return_url: returnUrl,
},
});
};
const handleClick = async () => {
const authData = await authorization();
if (!authData) {
@ -175,7 +144,11 @@ function PaymentWithEmailPage() {
productId,
token,
email,
name
name,
birthday,
returnUrl,
api,
gender
);
setPaymentIntent(paymentIntent);
setIsLoading(false);
@ -204,7 +177,11 @@ function PaymentWithEmailPage() {
productId,
tokenFromStore,
userFromStore.email,
userFromStore.profile.full_name
userFromStore.profile.full_name,
userFromStore.profile.birthday,
returnUrl,
api,
gender
);
setPaymentIntent(paymentIntent);
setIsLoadingPage(false);

View File

@ -37,6 +37,7 @@ export interface ISignUpOffer {
id: string;
title: string;
subtitle?: string;
productKey: string;
price: ISignUpOfferPrice;
emoji: string;
}
@ -47,40 +48,44 @@ export const signUpOffers: ISignUpOffer[] = [
title: "ULTRA PACK",
subtitle: "(3 in 1 + 2 secret bonus reading)",
price: {
current: 49.99,
old: 99.99,
current: 4999,
old: 9999,
discount: 50,
},
productKey: "main.ultra.pack",
emoji: "star_struck.png",
},
{
id: "numerology-analyses",
title: "NUMEROLOGY ANALYSIS",
price: {
current: 14.99,
old: 29.99,
current: 1499,
old: 2999,
discount: 50,
},
productKey: "main.numerology.analysis",
emoji: "input_numbers.png",
},
{
id: "tarot-reading",
title: "TAROT READING",
price: {
current: 19.99,
old: 34.99,
current: 1999,
old: 3499,
discount: 45,
},
productKey: "main.tarot.reading",
emoji: "sunset.png",
},
{
id: "palmistry-guide",
title: "PALMISTRY GUIDE",
price: {
current: 19.99,
old: 29.99,
current: 1999,
old: 2999,
discount: 30,
},
productKey: "main.palmistry.guide",
emoji: "rised_hand.png",
},
];

View File

@ -4,7 +4,10 @@ const isProduction = import.meta.env.MODE === "production";
const host = "";
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 prefix = "api/v1";
const openAIHost = " https://api.openai.com";
@ -38,7 +41,8 @@ const routes = {
palmistryPaywall: () => [host, "palmistry", "paywall"].join("/"),
palmistryPayment: () => [host, "palmistry", "payment"].join("/"),
palmistryDiscount: () => [host, "palmistry", "discount"].join("/"),
palmistryPremiumBundle: () => [host, "palmistry", "premium-bundle"].join("/"),
palmistryPremiumBundle: () =>
[host, "palmistry", "premium-bundle"].join("/"),
birthday: () => [host, "birthday"].join("/"),
didYouKnow: () => [host, "did-you-know"].join("/"),
freePeriodInfo: () => [host, "free-period"].join("/"),
@ -128,6 +132,8 @@ const routes = {
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),
epeFailPayment: () => [host, "epe", "fail-payment"].join("/"),
getInformationPartner: () => [host, "get-information-partner"].join("/"),
notFound: () => [host, "404"].join("/"),
},
server: {
@ -311,6 +317,7 @@ export const withoutFooterRoutes = [
routes.client.addConsultation(),
routes.client.advisors(),
routes.client.epeSuccessPayment(),
routes.client.getInformationPartner(),
];
export const withoutFooterPartOfRoutes = [
@ -385,6 +392,7 @@ export const withoutHeaderRoutes = [
routes.client.tryApp(),
routes.client.advisors(),
routes.client.epeSuccessPayment(),
routes.client.getInformationPartner(),
];
export const hasNoHeader = (path: string) => {
let result = true;

View 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,
},
});
};