Epe short path

This commit is contained in:
Денис Катаев 2024-04-12 22:52:44 +00:00 committed by Daniil Chemerkin
parent 79966d3b4e
commit e9afdd802d
8 changed files with 316 additions and 127 deletions

View File

@ -120,6 +120,7 @@ import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement";
import GetInformationPartnerPage from "../pages/GetInformationPartner"; import GetInformationPartnerPage from "../pages/GetInformationPartner";
import BirthPlacePage from "../pages/BirthPlacePage"; import BirthPlacePage from "../pages/BirthPlacePage";
import LoadingPage from "../pages/LoadingPage"; import LoadingPage from "../pages/LoadingPage";
import { EProductKeys, productUrls } from "@/data/products";
const isProduction = import.meta.env.MODE === "production"; const isProduction = import.meta.env.MODE === "production";
@ -137,6 +138,24 @@ function App(): JSX.Element {
const { token, user, signUp, logout } = useAuth(); const { token, user, signUp, logout } = useAuth();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const jwtToken = searchParams.get("token"); const jwtToken = searchParams.get("token");
const isForce = searchParams.get("force");
if (isForce === "true") {
dispatch(actions.userConfig.addIsForceShortPath(true));
}
if (isForce === "false") {
dispatch(actions.userConfig.addIsForceShortPath(false));
}
const isForceShortPath = useSelector(selectors.selectIsForceShortPath);
const { gender: genderFromStore } = useSelector(
selectors.selectQuestionnaire
);
const birthdateFromStore = useSelector(selectors.selectBirthdate);
const { birthPlace: birthPlaceFromStore } = useSelector(
selectors.selectQuestionnaire
);
const gender = user?.profile?.gender || genderFromStore;
const birthdate = user?.profile?.birthday || birthdateFromStore;
const birthPlace = user?.profile?.birthplace || birthPlaceFromStore;
useEffect(() => { useEffect(() => {
// api.getAppConfig({ bundleId: "auraweb" }), // api.getAppConfig({ bundleId: "auraweb" }),
@ -239,26 +258,6 @@ function App(): JSX.Element {
} }
}, [dispatch]); }, [dispatch]);
// useEffect(() => {
// const motion = window.matchMedia("(prefers-reduced-motion: no-preference)");
// if (motion.matches) {
// const scheme = document.querySelector('meta[name="theme-color"]');
// console.log(document.querySelectorAll("section.page")[0]);
// let hue = 0;
// let color;
// const backgroundColor =
// window.getComputedStyle(document.querySelectorAll("section.page")[0])
// .backgroundColor || "#ffffff";
// scheme?.setAttribute("content", backgroundColor);
// setInterval(() => {
// color = `hsl(${(hue += 5)} 50% 30%)`;
// document.body.style.background = color;
// scheme?.setAttribute("content", color);
// }, 50);
// }
// }, []);
return ( return (
<Routes> <Routes>
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}> <Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
@ -266,28 +265,73 @@ function App(): JSX.Element {
{/* Email - Pay - Email */} {/* Email - Pay - Email */}
<Route <Route
element={ element={
<CheckIsAuthOutlet <ShortPathOutlet
redirectUrl={routes.client.singlePaymentShortPath( productKey={EProductKeys["moons.pdf.aura"]}
"moons.pdf.aura" redirectUrls={{
)} user: {
pageType={EIsAuthPageType.public} force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
},
}}
requiredParameters={[]}
/>
}
>
<Route
path={routes.client.epeGender()}
element={<GenderPage productKey={EProductKeys["moons.pdf.aura"]} />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
data: {
no: routes.client.epeGender(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
},
}}
requiredParameters={[isForceShortPath || gender]}
/> />
} }
> >
<Route path={routes.client.epeGender()} element={<GenderPage />} />
<Route <Route
path={routes.client.epeBirthdate()} path={routes.client.epeBirthdate()}
element={<BirthdayPage />} element={<BirthdayPage />}
/> />
</Route> </Route>
{/* <Route
path={routes.client.epePayment()}
element={<PaymentWithEmailPage />}
/> */}
<Route <Route
path={routes.client.epeSuccessPayment()} element={
element={<SuccessPaymentPage />} <ShortPathOutlet
/> productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
user: {
no: routes.client.epeGender(),
force: routes.client.epeBirthdate(),
},
data: {
no: routes.client.epeGender(),
force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("moons.pdf.aura"),
},
}}
requiredParameters={[isForceShortPath || gender, birthdate]}
isProductPage={true}
/>
}
>
<Route
path={routes.client.epeSuccessPayment()}
element={<SuccessPaymentPage />}
/>
</Route>
<Route <Route
path={routes.client.epeFailPayment()} path={routes.client.epeFailPayment()}
element={<FailPaymentPage />} element={<FailPaymentPage />}
@ -297,40 +341,89 @@ function App(): JSX.Element {
{/* Advisor short path */} {/* Advisor short path */}
<Route <Route
element={ element={
<CheckPurchasedSingleProductOutlet <ShortPathOutlet
productKey="chat.aura" productKey={EProductKeys["chat.aura"]}
isProductPage={false} redirectUrls={{
failedUrl={routes.client.advisorChatPrivate( user: {
"asst_WWkAlT4Ovs6gKRy6VEn9LqNS" force: routes.client.advisorChatBirthdate(),
)} },
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
},
}}
requiredParameters={[]}
/> />
} }
> >
<Route <Route
element={ path={routes.client.advisorChatGender()}
<CheckIsAuthOutlet element={<GenderPage productKey={EProductKeys["chat.aura"]} />}
redirectUrl={routes.client.singlePaymentShortPath("chat.aura")} />
pageType={EIsAuthPageType.public} </Route>
/> <Route
} element={
> <ShortPathOutlet
<Route productKey={EProductKeys["chat.aura"]}
path={routes.client.advisorChatGender()} redirectUrls={{
element={<GenderPage />} data: {
no: routes.client.advisorChatGender(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
},
}}
requiredParameters={[isForceShortPath || gender]}
/> />
<Route }
path={routes.client.advisorChatBirthdate()} >
element={<BirthdayPage />} <Route
path={routes.client.advisorChatBirthdate()}
element={<BirthdayPage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/> />
<Route }
path={routes.client.advisorChatBirthtime()} >
element={<BirthtimePage />} <Route
path={routes.client.advisorChatBirthtime()}
element={<BirthtimePage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/> />
<Route }
path={routes.client.advisorChatBirthPlace()} >
element={<BirthPlacePage />} <Route
/> path={routes.client.advisorChatBirthPlace()}
</Route> element={<BirthPlacePage />}
/>
</Route> </Route>
<Route <Route
path={routes.client.advisorChatSuccessPayment()} path={routes.client.advisorChatSuccessPayment()}
@ -340,13 +433,29 @@ function App(): JSX.Element {
path={routes.client.advisorChatFailPayment()} path={routes.client.advisorChatFailPayment()}
element={<FailPaymentPage />} element={<FailPaymentPage />}
/> />
<Route <Route
element={ element={
<CheckPurchasedSingleProductOutlet <ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
user: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.singlePaymentShortPath("chat.aura"),
},
}}
requiredParameters={[
birthdate,
birthPlace,
isForceShortPath || gender,
]}
isProductPage={true} isProductPage={true}
failedUrl={routes.client.advisorChatGender()}
productKey="chat.aura"
/> />
} }
> >
@ -358,10 +467,29 @@ function App(): JSX.Element {
{/* Single Payment Page Short Path */} {/* Single Payment Page Short Path */}
<Route <Route
path={routes.client.singlePaymentShortPath()} element={
element={<PaymentWithEmailPage />} <ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
}}
requiredParameters={[
birthdate,
birthPlace,
isForceShortPath || gender,
]}
/>
}
> >
<Route path=":productId" element={<PaymentWithEmailPage />} /> <Route
path={routes.client.singlePaymentShortPath()}
element={<PaymentWithEmailPage />}
>
<Route path=":productId" element={<PaymentWithEmailPage />} />
</Route>
</Route> </Route>
{/* Single Payment Page Short Path */} {/* Single Payment Page Short Path */}
@ -668,18 +796,9 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
const homeConfig = useSelector(selectors.selectHome); const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar; const showNavbarFooter = homeConfig.isShowNavbar;
const mainRef = useRef<HTMLDivElement>(null); const mainRef = useRef<HTMLDivElement>(null);
// console.log(
// mainRef.current?.querySelectorAll("section.page, .page, section")
// );
useSchemeColorByElement(mainRef.current, "section.page, .page, section", [ useSchemeColorByElement(mainRef.current, "section.page, .page, section", [
location, location,
]); ]);
// useEffect(() => {
// console.log(
// "###$",
// mainRef.current?.querySelectorAll("section.page, .page, section")[0]
// );
// }, [location]);
const birthdate = useSelector(selectors.selectBirthdate); const birthdate = useSelector(selectors.selectBirthdate);
const dataItems = useMemo(() => [birthdate], [birthdate]); const dataItems = useMemo(() => [birthdate], [birthdate]);
@ -788,43 +907,63 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
); );
} }
enum EIsAuthPageType { // enum EIsAuthPageType {
private, // private,
public, // public,
// }
// interface ICheckIsAuthOutletProps {
// redirectUrl: string;
// pageType: EIsAuthPageType;
// }
// function CheckIsAuthOutlet({
// redirectUrl,
// pageType,
// }: ICheckIsAuthOutletProps): JSX.Element {
// const { user } = useAuth();
// if (user && pageType === EIsAuthPageType.public) {
// return <Navigate to={redirectUrl} replace={true} />;
// }
// if (!user && pageType === EIsAuthPageType.private) {
// return <Navigate to={redirectUrl} replace={true} />;
// }
// return <Outlet />;
// }
interface IShortPathOutletProps {
productKey: EProductKeys;
requiredParameters: unknown[];
isProductPage?: boolean;
redirectUrls: {
user?: {
yes?: string;
no?: string;
force?: string;
};
data?: {
yes?: string;
no?: string;
force?: string;
};
purchasedProduct?: {
yes?: string;
no?: string;
force?: string;
};
force?: {
yes?: string;
no?: string;
force?: string;
};
};
} }
interface ICheckIsAuthOutletProps { function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element {
redirectUrl: string; const { productKey, requiredParameters, redirectUrls, isProductPage } = props;
pageType: EIsAuthPageType;
}
function CheckIsAuthOutlet({
redirectUrl,
pageType,
}: ICheckIsAuthOutletProps): JSX.Element {
const { user } = useAuth();
if (user && pageType === EIsAuthPageType.public) {
return <Navigate to={redirectUrl} replace={true} />;
}
if (!user && pageType === EIsAuthPageType.private) {
return <Navigate to={redirectUrl} replace={true} />;
}
return <Outlet />;
}
interface ICheckPurchasedSingleProductOutletProps {
productKey: string;
isProductPage: boolean;
failedUrl: string;
}
function CheckPurchasedSingleProductOutlet({
productKey,
isProductPage,
failedUrl,
}: ICheckPurchasedSingleProductOutletProps): JSX.Element {
const { user, token } = useAuth(); const { user, token } = useAuth();
const api = useApi(); const api = useApi();
const isForce = useSelector(selectors.selectIsForceShortPath);
const loadData = useCallback(async () => { const loadData = useCallback(async () => {
if (!token?.length || !user?.email || !productKey?.length) if (!token?.length || !user?.email || !productKey?.length)
@ -851,22 +990,48 @@ function CheckPurchasedSingleProductOutlet({
const { data, isPending } = useApiCall(loadData); const { data, isPending } = useApiCall(loadData);
if (!data || isPending) { if (isPending) {
return <LoadingPage />; return <LoadingPage />;
} }
if ( const isPurchasedProduct = !!(data && "active" in data && data.active);
isProductPage &&
(!("active" in data) || !data.active || !token.length || !user?.email)
) {
return <Navigate to={failedUrl} replace={true} />;
}
if (!isProductPage && data && "active" in data && data.active) { const isUser = !!user && !!token.length;
return <Navigate to={failedUrl} replace={true} />; const isFullData = requiredParameters.every((item) => !!item);
}
return <Outlet />; if (!isFullData) {
if (isForce && redirectUrls.data?.force) {
return <Navigate to={redirectUrls.data.force} replace={true} />;
}
if (redirectUrls.data?.no && !isForce) {
return <Navigate to={redirectUrls.data.no} replace={true} />;
}
return <Outlet />;
}
if (!isUser) {
if (isForce && redirectUrls.user?.force) {
return <Navigate to={redirectUrls.user.force} replace={true} />;
}
if (redirectUrls.user?.no && !isForce) {
return <Navigate to={redirectUrls.user.no} replace={true} />;
}
return <Outlet />;
}
if (!isPurchasedProduct) {
if (isForce && redirectUrls.purchasedProduct?.force) {
return (
<Navigate to={redirectUrls.purchasedProduct.force} replace={true} />
);
}
if (redirectUrls.purchasedProduct?.no && !isForce) {
return <Navigate to={redirectUrls.purchasedProduct.no} replace={true} />;
}
return <Outlet />;
}
if (isProductPage) {
return <Outlet />;
}
return <Navigate to={productUrls[productKey]} replace={true} />;
} }
function AuthorizedUserOutlet(): JSX.Element { function AuthorizedUserOutlet(): JSX.Element {

View File

@ -111,7 +111,7 @@ function AdvisorChatPage() {
const setExternalChatIdAssistant = async (threadId: string) => { const setExternalChatIdAssistant = async (threadId: string) => {
await api.setExternalChatIdAssistant({ await api.setExternalChatIdAssistant({
token, token,
chatId: String(id), chatId: String(assistant?.id || 1),
ai_assistant_chat: { ai_assistant_chat: {
external_id: threadId, external_id: threadId,
}, },

View File

@ -1,17 +1,21 @@
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import Title from "@/components/Title"; import Title from "@/components/Title";
import { Gender, genders } from "@/data"; import { Gender, genders } from "@/data";
import { EProductKeys } from "@/data/products";
import routes from "@/routes"; import routes from "@/routes";
import { actions } from "@/store"; import { actions } from "@/store";
import { useEffect } from "react"; import { useEffect } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
function GenderPage(): JSX.Element { interface IGenderPageProps {
productKey?: EProductKeys;
}
function GenderPage({ productKey }: IGenderPageProps): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { targetId } = useParams(); const { targetId } = useParams();
const pathName = window.location.pathname;
useEffect(() => { useEffect(() => {
const isShowTryApp = targetId === "i"; const isShowTryApp = targetId === "i";
@ -20,10 +24,10 @@ 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.includes("/epe/gender")) { if (productKey === EProductKeys["moons.pdf.aura"]) {
return navigate(routes.client.epeBirthdate()); return navigate(routes.client.epeBirthdate());
} }
if (pathName.includes("/advisor-chat/gender")) { if (productKey === EProductKeys["chat.aura"]) {
return navigate(routes.client.advisorChatBirthdate()); return navigate(routes.client.advisorChatBirthdate());
} }
navigate(`/questionnaire/profile/flowChoice`); navigate(`/questionnaire/profile/flowChoice`);

View File

@ -147,6 +147,7 @@ function PaymentWithEmailPage() {
if (!tokenFromStore.length || !userFromStore) { if (!tokenFromStore.length || !userFromStore) {
return; return;
} }
await createSinglePayment({ await createSinglePayment({
user: userFromStore, user: userFromStore,
token: tokenFromStore, token: tokenFromStore,
@ -163,7 +164,8 @@ function PaymentWithEmailPage() {
useEffect(() => { useEffect(() => {
handleAuthUser(); handleAuthUser();
}, [handleAuthUser]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return ( return (
<div className={`${styles.page} page`}> <div className={`${styles.page} page`}>

View File

@ -1,5 +1,11 @@
import routes from "@/routes"; import routes from "@/routes";
export enum EProductKeys {
"chat.aura" = "chat.aura",
"moons.pdf.aura" = "moons.pdf.aura",
"default" = "default",
}
interface IProductUrls { interface IProductUrls {
[key: string]: string; [key: string]: string;
} }

View File

@ -74,8 +74,8 @@ export const useSinglePayment = () => {
} }
return false; return false;
} catch (error) { } catch (error) {
return false;
console.error(error); console.error(error);
return false;
} }
}, },
[api] [api]

View File

@ -46,6 +46,7 @@ import userConfig, {
actions as userConfigActions, actions as userConfigActions,
selectUserDeviceType, selectUserDeviceType,
selectIsShowTryApp, selectIsShowTryApp,
selectIsForceShortPath,
} from "./userConfig"; } from "./userConfig";
import compatibilities, { import compatibilities, {
actions as compatibilitiesActions, actions as compatibilitiesActions,
@ -106,6 +107,7 @@ export const selectors = {
selectQuestionnaire, selectQuestionnaire,
selectUserDeviceType, selectUserDeviceType,
selectIsShowTryApp, selectIsShowTryApp,
selectIsForceShortPath,
selectOpenAiToken, selectOpenAiToken,
...formSelectors, ...formSelectors,
}; };

View File

@ -9,11 +9,13 @@ export enum EUserDeviceType {
interface IUserConfig { interface IUserConfig {
deviceType: EUserDeviceType; deviceType: EUserDeviceType;
isShowTryApp: boolean; isShowTryApp: boolean;
isForceShortPath: boolean;
} }
const initialState: IUserConfig = { const initialState: IUserConfig = {
deviceType: EUserDeviceType.ios, deviceType: EUserDeviceType.ios,
isShowTryApp: false, isShowTryApp: false,
isForceShortPath: false,
}; };
const userConfigSlice = createSlice({ const userConfigSlice = createSlice({
@ -31,6 +33,10 @@ const userConfigSlice = createSlice({
state.isShowTryApp = action.payload; state.isShowTryApp = action.payload;
return state; return state;
}, },
addIsForceShortPath(state, action: PayloadAction<boolean>) {
state.isForceShortPath = action.payload;
return state;
},
}, },
extraReducers: (builder) => builder.addCase("reset", () => initialState), extraReducers: (builder) => builder.addCase("reset", () => initialState),
}); });
@ -44,4 +50,8 @@ export const selectIsShowTryApp = createSelector(
(state: { userConfig: IUserConfig }) => state.userConfig.isShowTryApp, (state: { userConfig: IUserConfig }) => state.userConfig.isShowTryApp,
(userConfig) => userConfig (userConfig) => userConfig
); );
export const selectIsForceShortPath = createSelector(
(state: { userConfig: IUserConfig }) => state.userConfig.isForceShortPath,
(userConfig) => userConfig
);
export default userConfigSlice.reducer; export default userConfigSlice.reducer;