Merge branch 'fix/short-path' into 'develop'

fix short path

See merge request witapp/aura-webapp!92
This commit is contained in:
Daniil Chemerkin 2024-04-17 20:21:42 +00:00
commit 9383060a7c
8 changed files with 238 additions and 32 deletions

View File

@ -11,10 +11,13 @@ interface HookResult<T> {
type ApiMethod<T> = () => Promise<T>
type ApiCallState = 'idle' | 'pending' | 'success' | 'error'
export function useApiCall<T>(apiMethod: ApiMethod<T>): HookResult<T> {
export function useApiCall<T>(
apiMethod: ApiMethod<T>,
startState: ApiCallState = 'idle'
): HookResult<T> {
const [data, setData] = useState<T | null>(null)
const [error, setError] = useState<ApiError | null>(null)
const [state, setState] = useState<ApiCallState>('idle')
const [state, setState] = useState<ApiCallState>(startState)
const isPending = state === 'pending'
useEffect(() => {

View File

@ -113,7 +113,6 @@ import AddConsultationPage from "../pages/AdditionalPurchases/pages/AddConsultat
import StepsManager from "@/components/palmistry/steps-manager/steps-manager";
import Advisors from "../pages/Advisors";
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 { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement";
@ -121,6 +120,7 @@ import GetInformationPartnerPage from "../pages/GetInformationPartner";
import BirthPlacePage from "../pages/BirthPlacePage";
import LoadingPage from "../pages/LoadingPage";
import { EProductKeys, productUrls } from "@/data/products";
import SinglePaymentPage from "../pages/SinglePaymentPage";
const isProduction = import.meta.env.MODE === "production";
@ -146,7 +146,7 @@ function App(): JSX.Element {
} else {
dispatch(actions.userConfig.addIsForceShortPath(false));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const isForceShortPath = useSelector(selectors.selectIsForceShortPath);
@ -276,10 +276,10 @@ function App(): JSX.Element {
force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
no: routes.client.epePayment(),
},
}}
requiredParameters={[]}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
@ -297,7 +297,7 @@ function App(): JSX.Element {
no: routes.client.epeGender(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
no: routes.client.epePayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
@ -309,6 +309,54 @@ function App(): JSX.Element {
element={<BirthdayPage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
data: {
no: routes.client.epeGender(),
force: routes.client.epeBirthdate(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.epeEmail()}
element={
<EmailEnterPage redirectUrl={routes.client.epePayment()} />
}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
data: {
no: routes.client.epeGender(),
force: routes.client.epeBirthdate(),
},
user: {
no: routes.client.epeEmail(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.epePayment()}
element={
<SinglePaymentPage
productId={EProductKeys["moons.pdf.aura"]}
isForce={isForceShortPath}
/>
}
/>
</Route>
<Route
element={
<ShortPathOutlet
@ -323,7 +371,7 @@ function App(): JSX.Element {
force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
no: routes.client.epePayment(),
},
}}
requiredParameters={[isForceShortPath || gender, birthdate]}
@ -352,10 +400,10 @@ function App(): JSX.Element {
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[]}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
@ -373,7 +421,7 @@ function App(): JSX.Element {
no: routes.client.advisorChatGender(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
@ -395,7 +443,7 @@ function App(): JSX.Element {
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
@ -417,7 +465,7 @@ function App(): JSX.Element {
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
@ -429,6 +477,68 @@ function App(): JSX.Element {
element={<BirthPlacePage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
}}
requiredParameters={[
birthdate,
birthPlace,
isForceShortPath || gender,
]}
/>
}
>
<Route
path={routes.client.advisorChatEmail()}
element={
<EmailEnterPage
redirectUrl={routes.client.advisorChatPayment()}
isRequiredName={true}
/>
}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
user: {
no: routes.client.advisorChatEmail(),
},
}}
requiredParameters={[
birthdate,
birthPlace,
isForceShortPath || gender,
]}
/>
}
>
<Route
path={routes.client.advisorChatPayment()}
element={
<SinglePaymentPage
productId={EProductKeys["chat.aura"]}
isForce={isForceShortPath}
/>
}
/>
</Route>
<Route
path={routes.client.advisorChatSuccessPayment()}
element={<SuccessPaymentPage />}
@ -443,15 +553,14 @@ function App(): JSX.Element {
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
user: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
no: routes.client.advisorChatEmail(),
},
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[
@ -470,7 +579,7 @@ function App(): JSX.Element {
{/* Advisor short path */}
{/* Single Payment Page Short Path */}
<Route
{/* <Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
@ -489,12 +598,12 @@ function App(): JSX.Element {
}
>
<Route
path={routes.client.singlePaymentShortPath()}
path={routes.client.advisorChatPayment()}
element={<PaymentWithEmailPage />}
>
<Route path=":productId" element={<PaymentWithEmailPage />} />
</Route>
</Route>
</Route> */}
{/* Single Payment Page Short Path */}
{/* Test Routes Start */}
@ -989,9 +1098,10 @@ function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element {
error: "Something went wrong",
};
}
}, [api, productKey, token, user?.email]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [token]);
const { data, isPending } = useApiCall(loadData);
const { data, isPending } = useApiCall(loadData, "pending");
if (isPending) {
return <LoadingPage />;

View File

@ -19,7 +19,7 @@ function BirthdayPage(): JSX.Element {
const [isDisabled, setIsDisabled] = useState(true);
let nextRoute = routes.client.didYouKnow();
if (window.location.href.includes("/epe/")) {
nextRoute = routes.client.singlePaymentShortPath("moons.pdf.aura");
nextRoute = routes.client.epeEmail();
}
if (window.location.href.includes("/advisor-chat/")) {
nextRoute = routes.client.advisorChatBirthtime();

View File

@ -17,7 +17,15 @@ import routes from "@/routes";
import NameInput from "./NameInput";
import { ISubscriptionPlan } from "@/api/resources/SubscriptionPlans";
function EmailEnterPage(): JSX.Element {
interface IEmailEnterPage {
redirectUrl?: string;
isRequiredName?: boolean;
}
function EmailEnterPage({
redirectUrl = routes.client.emailConfirm(),
isRequiredName = false,
}: IEmailEnterPage): JSX.Element {
const api = useApi();
const { signUp } = useAuth();
const { t, i18n } = useTranslation();
@ -28,7 +36,7 @@ function EmailEnterPage(): JSX.Element {
const birthday = useSelector(selectors.selectBirthday);
const [isDisabled, setIsDisabled] = useState(true);
const [isValidEmail, setIsValidEmail] = useState(false);
const [isValidName, setIsValidName] = useState(true);
const [isValidName, setIsValidName] = useState(!isRequiredName);
const [isLoading, setIsLoading] = useState(false);
const [isAuth, setIsAuth] = useState(false);
const [apiError, setApiError] = useState<ApiError | null>(null);
@ -41,9 +49,11 @@ function EmailEnterPage(): JSX.Element {
const timezone = getClientTimezone();
const locale = i18n.language;
const { subPlan } = useParams();
const { gender, flowChoice, birthPlace } = useSelector(
selectors.selectQuestionnaire
);
const {
gender,
birthPlace,
// flowChoice
} = useSelector(selectors.selectQuestionnaire);
useEffect(() => {
if (subPlan) {
@ -117,9 +127,9 @@ function EmailEnterPage(): JSX.Element {
user: {
profile_attributes: {
birthday,
gender,
gender: gender.length ? gender : "male",
full_name: name,
relationship_status: flowChoice,
// relationship_status: !!flowChoice.length ? flowChoice : null,
},
birthplace_attributes: { address: birthPlace },
},
@ -147,7 +157,7 @@ function EmailEnterPage(): JSX.Element {
setIsLoading(false);
setIsAuth(true);
setTimeout(() => {
navigate(routes.client.emailConfirm());
navigate(redirectUrl);
}, 1000);
} catch (error) {
console.error(error);
@ -170,7 +180,7 @@ function EmailEnterPage(): JSX.Element {
value={name}
placeholder="Your name"
onValid={handleValidName}
onInvalid={() => setIsValidName(true)}
onInvalid={() => setIsValidName(!isRequiredName)}
/>
<EmailInput
name="email"

View File

@ -19,7 +19,7 @@ function BirthPlacePage() {
};
const handleNext = () => {
navigate(routes.client.singlePaymentShortPath("chat.aura"));
navigate(routes.client.advisorChatEmail());
};
return (

View File

@ -0,0 +1,81 @@
import Title from "@/components/Title";
import styles from "./styles.module.css";
import PaymentForm from "../PaymentWithEmailPage/PaymentForm";
import { getPriceCentsToDollars } from "@/services/price";
import { useSinglePayment } from "@/hooks/payment/useSinglePayment";
import routes from "@/routes";
import { useAuth } from "@/auth";
import Loader, { LoaderColor } from "@/components/Loader";
import { useCallback, useEffect } from "react";
import { EProductKeys } from "@/data/products";
interface ISinglePaymentPage {
productId: EProductKeys;
isForce?: boolean;
}
function SinglePaymentPage({ productId, isForce = false }: ISinglePaymentPage) {
const {
product,
paymentIntent,
isLoading: isLoadingSinglePayment,
error: errorSinglePayment,
createSinglePayment,
} = useSinglePayment();
const { user: userFromStore, token: tokenFromStore } = useAuth();
const returnUrl = `${window.location.protocol}//${
window.location.host
}${routes.client.paymentResult()}`;
const createPayment = useCallback(async () => {
if (!tokenFromStore.length || !userFromStore) {
return;
}
await createSinglePayment({
user: userFromStore,
token: tokenFromStore,
targetProductKey: productId || "",
returnUrl,
});
}, [
createSinglePayment,
productId,
returnUrl,
tokenFromStore,
userFromStore,
]);
useEffect(() => {
createPayment();
}, [createPayment]);
return (
<section className={`${styles.page} page`}>
{isLoadingSinglePayment && <Loader color={LoaderColor.Black} />}
{!isLoadingSinglePayment &&
paymentIntent &&
"paymentIntent" in paymentIntent &&
!!tokenFromStore.length && (
<>
<Title variant="h1" className={styles.title}>
{getPriceCentsToDollars(product?.amount || 0)}$
</Title>
<PaymentForm
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
clientSecret={paymentIntent.paymentIntent.data.client_secret}
returnUrl={`${returnUrl}?redirect_type=${product?.key}&force=${isForce}`}
/>
</>
)}
{errorSinglePayment?.error && (
<Title variant="h3" style={{ color: "red", margin: 0 }}>
Something went wrong:{" "}
{errorSinglePayment?.error?.length && errorSinglePayment?.error}
</Title>
)}
</section>
);
}
export default SinglePaymentPage;

View File

@ -128,6 +128,7 @@ const routes = {
// Email - Pay - Email
epeGender: () => [host, "epe", "gender"].join("/"),
epeBirthdate: () => [host, "epe", "birthdate"].join("/"),
epeEmail: () => [host, "epe", "email"].join("/"),
epePayment: () => [host, "epe", "payment"].join("/"),
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),
epeFailPayment: () => [host, "epe", "fail-payment"].join("/"),
@ -138,6 +139,7 @@ const routes = {
advisorChatBirthtime: () => [host, "advisor-chat", "birthtime"].join("/"),
advisorChatBirthPlace: () =>
[host, "advisor-chat", "birth-place"].join("/"),
advisorChatEmail: () => [host, "advisor-chat", "email"].join("/"),
advisorChatPayment: () => [host, "advisor-chat", "payment"].join("/"),
advisorChatSuccessPayment: () =>
[host, "advisor-chat", "success-payment"].join("/"),