w-aura/src/components/App/index.tsx
Daniil Chemerkin f5551a0c42 Develop
2024-06-02 00:51:18 +00:00

1190 lines
37 KiB
TypeScript
Executable File

import {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from "react";
import {
Routes,
Route,
Navigate,
Outlet,
useLocation,
useNavigate,
useSearchParams,
} from "react-router-dom";
import { useAuth } from "@/auth";
import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import routes, {
hasNavigation,
getRouteBy,
hasNoFooter,
hasNoHeader,
hasNavbarFooter,
hasFullDataModal,
} from "@/routes";
import BirthdayPage from "../BirthdayPage";
import BirthtimePage from "../BirthtimePage";
import CreateProfilePage from "../CreateProfilePage";
import EmailEnterPage from "../EmailEnterPage";
import SubscriptionPage from "../SubscriptionPage";
import PaymentPage from "../PaymentPage";
import WallpaperPage from "../WallpaperPage";
import StaticPage from "../StaticPage";
import NotFoundPage from "../NotFoundPage";
import Header from "../Header";
import Navbar from "../Navbar";
import Footer from "../Footer";
import "./styles.css";
import DidYouKnowPage from "../DidYouKnowPage";
import FreePeriodInfoPage from "../FreePeriodInfoPage";
import AttentionPage from "../AttentionPage";
import FeedbackPage from "../FeedbackPage";
import CompatibilityPage from "../Compatibility";
import BreathPage from "../BreathPage";
import PriceListPage from "../PriceListPage";
import CompatResultPage from "../CompatResultPage";
import HomePage from "../HomePage";
import UserCallbacksPage from "../UserCallbacksPage";
import NavbarFooter, { INavbarHomeItems } from "../NavbarFooter";
import { EPathsFromHome } from "@/store/siteConfig";
import parseAPNG, { APNG } from "apng-js";
import { useApi, useApiCall } from "@/api";
import { Asset } from "@/api/resources/Assets";
import PaymentResultPage from "../PaymentPage/results";
import PaymentSuccessPage from "../PaymentPage/results/SuccessPage";
import PaymentFailPage from "../PaymentPage/results/ErrorPage";
import AuthPage from "../AuthPage";
import AuthResultPage from "../AuthResultPage";
import MagicBallPage from "../pages/MagicBall";
import BestiesHoroscopeResult from "../pages/BestiesHoroscopeResult";
import PredictionMoonResult from "../pages/PredictionMoonResult";
import MyHoroscopeResult from "../pages/MyHoroscopeResult";
import ThermalResult from "../pages/ThermalResult";
import MoonPhaseTrackerResult from "../pages/MoonPhaseTrackerResult";
import EnergyVampirismResult from "../pages/EnergyVampirismResult";
import NameHoroscopeResult from "../pages/NameHoroscopeResult";
import GenderPage from "../pages/Gender";
import QuestionnairePage from "../pages/Questionnaire";
import GoalSetupPage from "../pages/GoalSetup";
import HyperPersonalizedAstrologyPage from "../pages/HyperPersonalizedAstrologyPage";
import NoBirthtimePage from "../pages/NoBirthtime";
import LoadingInRelationshipPage from "../pages/LoadingInRelationship";
import QuestionnaireIntermediatePage from "../pages/QuestionnaireIntermediate";
import RelationshipAlmostTherePage from "../pages/RelationshipAlmostThere";
import Modal from "../Modal";
import FullDataModal from "../FullDataModal";
import SingleZodiacInfoPage from "../pages/SingleZodiacInfo";
import ProblemsPage from "../pages/Problems";
import WorksRouterPage from "../pages/WorksRouter";
import NotAlonePage from "../pages/NotAlone";
import AlmostTherePage from "../pages/AlmostThere";
import AllRightPage from "../pages/AllRight";
import PartnerRightPlacePage from "../pages/PartnerRightPlace";
import PartnerThingPage from "../pages/PartnerThing";
import PartnerTotallyNormalPage from "../pages/PartnerTotallyNormal";
import WithHeartPage from "../pages/WithHeart";
import WithHeadPage from "../pages/WithHead";
import BothPage from "../pages/Both";
import RelationshipZodiacInfoPage from "../pages/RelationshipZodiacInfo";
import Satisfied from "../pages/Satisfied";
import AboutUsPage from "../pages/AboutUs";
import LoadingProfilePage from "../pages/LoadingProfile";
import EmailConfirmPage from "../pages/EmailConfirm";
import OnboardingPage from "../pages/Onboarding";
import TrialChoicePage from "../pages/TrialChoice";
import TrialPaymentPage from "../pages/TrialPayment";
import ReactGA from "react-ga4";
import AdditionalDiscount from "../pages/AdditionalDiscount";
import TrialPaymentWithDiscount from "../pages/TrialPaymentWithDiscount";
import MarketingLanding from "../pages/EmailLetters/MarketingLanding";
import MarketingTrialPayment from "../pages/EmailLetters/MarketingTrialPayment";
import { ScrollToTop } from "@/hooks/scrollToTop";
import { EUserDeviceType } from "@/store/userConfig";
import TryAppPage from "../pages/TryApp";
import AdditionalPurchases from "../pages/AdditionalPurchases";
import AddReportPage from "../pages/AdditionalPurchases/pages/AddReport";
import UnlimitedReadingsPage from "../pages/AdditionalPurchases/pages/UnlimitedReadings";
import AddConsultationPage from "../pages/AdditionalPurchases/pages/AddConsultation";
import StepsManager from "@/components/palmistry/steps-manager/steps-manager";
import Advisors from "../pages/Advisors";
import AdvisorChatPage from "../pages/AdvisorChat";
import SuccessPaymentPage from "../pages/SinglePaymentPage/ResultPayment/SuccessPaymentPage";
import FailPaymentPage from "../pages/SinglePaymentPage/ResultPayment/FailPaymentPage";
import { useSchemeColorByElement } from "@/hooks/useSchemeColorByElement";
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";
import ABDesignV1Routes from "@/routerComponents/ABDesign/v1";
const isProduction = import.meta.env.MODE === "production";
if (isProduction) {
ReactGA.initialize("G-00S3ECJGSJ");
}
function App(): JSX.Element {
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
const [leoApng, setLeoApng] = useState<Error | APNG>(Error);
const [padLockApng, setPadLockApng] = useState<Error | APNG>(Error);
const navigate = useNavigate();
const api = useApi();
const dispatch = useDispatch();
const { token, user, signUp, logout } = useAuth();
const [searchParams] = useSearchParams();
const jwtToken = searchParams.get("token");
const isForce = searchParams.get("force");
useEffect(() => {
if (isForce === "true") {
dispatch(actions.userConfig.addIsForceShortPath(true));
} else {
dispatch(actions.userConfig.addIsForceShortPath(false));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
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;
useLayoutEffect(() => {
dispatch(actions.paywalls.resetIsMustUpdate());
}, [dispatch]);
useEffect(() => {
// api.getAppConfig({ bundleId: "auraweb" }),
dispatch(
actions.siteConfig.update({
openAiToken: "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",
})
);
}, [dispatch]);
useEffect(() => {
if (!isProduction) return;
ReactGA.send({
hitType: "pageview",
page: document.location.pathname + document.location.search,
title: "Custom Title",
});
}, []);
const closeSpecialOfferAttention = () => {
setIsSpecialOfferOpen(false);
navigate(routes.client.auth());
};
const assetsData = useCallback(async () => {
const { assets } = await api.getAssets({
category: String("au"),
});
return assets;
}, [api]);
const { data } = useApiCall<Asset[]>(assetsData);
// jwt auth
useLayoutEffect(() => {
(async () => {
if (!jwtToken) return;
logout();
try {
const { token } = await api.getRealToken({ token: jwtToken });
const { user } = await api.getUser({ token });
signUp(token, user);
} catch (error) {
console.log("Error of get real token or get user: ");
console.error(error);
}
})();
}, [api, jwtToken, logout, signUp]);
useEffect(() => {
(async () => {
if (!token.length || !user) return;
const {
user: { has_subscription },
} = await api.getSubscriptionStatus({
token,
});
const { subscription: subscriptionStatusNew } =
await api.getSubscriptionStatusNew({ token });
if ((has_subscription || subscriptionStatusNew) && user) {
return dispatch(actions.status.update("subscribed"));
}
if (!has_subscription && !subscriptionStatusNew && user) {
return dispatch(actions.status.update("unsubscribed"));
}
if (!user) {
return dispatch(actions.status.update("lead"));
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch, api, token]);
useEffect(() => {
async function getApng() {
if (!data) return;
const response = await fetch(
data.find((item) => item.key === "au.apng.leo")?.url || ""
);
const arrayBuffer = await response.arrayBuffer();
setLeoApng(parseAPNG(arrayBuffer));
}
getApng();
}, [data]);
useEffect(() => {
(async () => {
const response = await fetch("/padlock_icon_animation_closing.png");
const arrayBuffer = await response.arrayBuffer();
setPadLockApng(parseAPNG(arrayBuffer));
})();
}, []);
useEffect(() => {
if (!user) return;
dispatch(actions.form.addEmail(user.email));
}, [dispatch, user]);
// set user device type
useEffect(() => {
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
if (isIOS) {
dispatch(actions.userConfig.addDeviceType(EUserDeviceType.ios));
} else {
dispatch(actions.userConfig.addDeviceType(EUserDeviceType.android));
}
}, [dispatch]);
return (
<Routes>
<Route path="*" element={<ABDesignV1Routes />} />
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
<Route path={routes.client.loadingPage()} element={<LoadingPage />} />
{/* Email - Pay - Email */}
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
user: {
force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.epePayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.epeGender()}
element={<GenderPage productKey={EProductKeys["moons.pdf.aura"]} />}
>
<Route path=":targetId" element={<GenderPage />} />
</Route>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
data: {
no: routes.client.epeGender(),
},
purchasedProduct: {
no: routes.client.epePayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.epeBirthdate()}
element={<BirthdayPage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["moons.pdf.aura"]}
redirectUrls={{
data: {
no: routes.client.epeGender(),
force: routes.client.epeBirthdate(),
},
purchasedProduct: {
no: routes.client.epePayment(),
},
}}
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
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.epePayment(),
},
}}
requiredParameters={[isForceShortPath || gender, birthdate]}
isProductPage={true}
/>
}
>
<Route
path={routes.client.epeSuccessPayment()}
element={<SuccessPaymentPage />}
/>
</Route>
<Route
path={routes.client.epeFailPayment()}
element={<FailPaymentPage />}
/>
{/* Email - Pay - Email */}
{/* Advisor short path */}
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
user: {
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.advisorChatGender()}
element={<GenderPage productKey={EProductKeys["chat.aura"]} />}
>
<Route path=":targetId" element={<GenderPage />} />
</Route>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
},
purchasedProduct: {
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[isForceShortPath || gender]}
/>
}
>
<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.advisorChatPayment(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/>
}
>
<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.advisorChatPayment(),
},
}}
requiredParameters={[birthdate, isForceShortPath || gender]}
/>
}
>
<Route
path={routes.client.advisorChatBirthPlace()}
element={<BirthPlacePage />}
/>
</Route>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.advisorChatPayment(),
},
}}
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 />}
/>
<Route
path={routes.client.advisorChatFailPayment()}
element={<FailPaymentPage />}
/>
<Route
element={
<ShortPathOutlet
productKey={EProductKeys["chat.aura"]}
redirectUrls={{
user: {
no: routes.client.advisorChatEmail(),
},
data: {
no: routes.client.advisorChatGender(),
force: routes.client.advisorChatBirthdate(),
},
purchasedProduct: {
no: routes.client.advisorChatPayment(),
},
}}
requiredParameters={[
birthdate,
birthPlace,
isForceShortPath || gender,
]}
isProductPage={true}
/>
}
>
<Route path={`${routes.client.advisorChatPrivate()}`}>
<Route path=":id" element={<AdvisorChatPage />} />
</Route>
</Route>
{/* Advisor short path */}
{/* Test Routes Start */}
<Route path={routes.client.notFound()} element={<NotFoundPage />} />
<Route path={routes.client.gender()} element={<GenderPage />}>
<Route path=":targetId" element={<GenderPage />} />
</Route>
<Route path={routes.client.tryApp()} element={<TryAppPage />} />
<Route
path={routes.client.questionnaire()}
element={<QuestionnairePage />}
>
<Route path=":stepId" element={<QuestionnairePage />}>
<Route path=":question" element={<QuestionnairePage />} />
</Route>
</Route>
<Route path={routes.client.goalSetup()} element={<GoalSetupPage />} />
<Route
path={routes.client.hyperPersonalizedAstrology()}
element={<HyperPersonalizedAstrologyPage />}
/>
<Route path={routes.client.noTime()} element={<NoBirthtimePage />} />
<Route
path={routes.client.loadingInRelationship()}
element={<LoadingInRelationshipPage />}
/>
<Route
path={routes.client.worksRouter()}
element={<WorksRouterPage />}
/>
<Route
path={routes.client.worksForUs()}
element={<QuestionnaireIntermediatePage />}
/>
<Route
path={routes.client.worksTraits()}
element={<QuestionnaireIntermediatePage />}
/>
<Route path={routes.client.notAlone()} element={<NotAlonePage />} />
<Route path={routes.client.allRight()} element={<AllRightPage />} />
<Route
path={routes.client.almostThere()}
element={<AlmostTherePage />}
/>
<Route
path={routes.client.relationshipAlmostThere()}
element={<RelationshipAlmostTherePage />}
/>
<Route
path={routes.client.singleZodiacInfo()}
element={<SingleZodiacInfoPage />}
/>
<Route path={routes.client.problems()} element={<ProblemsPage />} />
<Route
path={routes.client.partnerRightPlace()}
element={<PartnerRightPlacePage />}
/>
<Route
path={routes.client.partnerThing()}
element={<PartnerThingPage />}
/>
<Route
path={routes.client.partnerTotallyNormal()}
element={<PartnerTotallyNormalPage />}
/>
<Route path={routes.client.withHeart()} element={<WithHeartPage />} />
<Route path={routes.client.withHead()} element={<WithHeadPage />} />
<Route path={routes.client.both()} element={<BothPage />} />
<Route
path={routes.client.relationshipZodiacInfo()}
element={<RelationshipZodiacInfoPage />}
/>
<Route path={routes.client.satisfiedResult()} element={<Satisfied />} />
<Route path={routes.client.aboutUs()} element={<AboutUsPage />} />
<Route
path={routes.client.loadingProfile()}
element={<LoadingProfilePage />}
/>
<Route
path={routes.client.emailConfirm()}
element={<EmailConfirmPage />}
/>
<Route path={routes.client.onboarding()} element={<OnboardingPage />} />
<Route
path={routes.client.additionalDiscount()}
element={<AdditionalDiscount />}
/>
<Route
path={routes.client.trialPaymentWithDiscount()}
element={<TrialPaymentWithDiscount />}
/>
<Route
path={routes.client.trialChoice()}
element={<TrialChoicePage />}
/>
<Route
path={routes.client.trialPayment()}
element={<TrialPaymentPage />}
>
<Route path=":subPlan" element={<TrialPaymentPage />} />
</Route>
{/* Test Routes End */}
{/* Email Letters */}
<Route
path={routes.client.email("marketing-landing")}
element={<MarketingLanding />}
/>
<Route
path={routes.client.email("marketing-trial-payment")}
element={<MarketingTrialPayment />}
/>
{/* Email Letters End */}
{/* Additional Purchases */}
<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 />}
>
<Route path=":id" element={<PaymentResultPage />} />
</Route>
<Route
path={routes.client.paymentSuccess()}
element={<PaymentSuccessPage />}
/>
<Route
path={routes.client.paymentFail()}
element={<PaymentFailPage />}
/>
<Route element={<AuthorizedUserOutlet />}>
<Route path={routes.client.root()} element={<MainPage />} />
<Route path={routes.client.birthday()} element={<BirthdayPage />} />
<Route
path={routes.client.didYouKnow()}
element={<DidYouKnowPage />}
/>
<Route
path={routes.client.freePeriodInfo()}
element={<FreePeriodInfoPage />}
/>
<Route
path={routes.client.attention()}
element={
<AttentionPage
isOpenModal={isSpecialOfferOpen}
onCloseSpecialOffer={closeSpecialOfferAttention}
/>
}
/>
<Route path={routes.client.feedback()} element={<FeedbackPage />} />
<Route path={routes.client.birthtime()} element={<BirthtimePage />} />
<Route path={routes.client.createProfile()} element={<SkipStep />} />
<Route
path={routes.client.emailEnter()}
element={<EmailEnterPage />}
/>
<Route
path={routes.client.auth()}
element={<AuthPage padLockApng={padLockApng} />}
/>
<Route
path={routes.client.authResult()}
element={<AuthResultPage />}
/>
<Route path={routes.client.static()} element={<StaticPage />} />
<Route path={routes.client.priceList()} element={<PriceListPage />} />
</Route>
<Route element={<AuthorizedUserOutlet />}>
<Route
path={routes.client.subscription()}
element={<SubscriptionPage />}
>
<Route path=":subPlan" element={<SubscriptionPage />} />
</Route>
</Route>
<Route element={<PrivateOutlet />}>
<Route element={<AuthorizedUserOutlet />}>
<Route
path={routes.client.paymentMethod()}
element={<PaymentPage />}
/>
</Route>
<Route element={<PrivateSubscriptionOutlet />}>
<Route path={routes.client.home()} element={<HomePage />} />
<Route
path={routes.client.compatibility()}
element={<CompatibilityPage />}
/>
<Route
path={routes.client.compatibilityResult()}
element={<CompatResultPage />}
/>
<Route
path={routes.client.breath()}
element={<BreathPage leoApng={leoApng} />}
/>
<Route
path={routes.client.breathResult()}
element={<UserCallbacksPage />}
/>
<Route
path={routes.client.wallpaper()}
element={<WallpaperPage />}
/>
<Route path={routes.client.advisors()} element={<Advisors />} />
<Route path={routes.client.advisors()}>
<Route path=":id" element={<AdvisorChatPage />} />
</Route>
<Route
path={routes.client.magicBall()}
element={<MagicBallPage />}
/>
<Route
path={routes.client.horoscopeBestiesResult()}
element={<BestiesHoroscopeResult />}
/>
<Route
path={routes.client.predictionMoonResult()}
element={<PredictionMoonResult />}
/>
<Route
path={routes.client.myHoroscopeResult()}
element={<MyHoroscopeResult />}
/>
<Route
path={routes.client.thermalResult()}
element={<ThermalResult />}
/>
<Route
path={routes.client.moonPhaseTracker()}
element={<MoonPhaseTrackerResult />}
/>
<Route
path={routes.client.energyVampirismResult()}
element={<EnergyVampirismResult />}
/>
<Route
path={routes.client.nameHoroscopeResult()}
element={<NameHoroscopeResult />}
/>
</Route>
</Route>
<Route path="/palmistry" element={<StepsManager />} />
<Route path="/palmistry/:step" element={<StepsManager />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
);
}
interface LayoutProps {
setIsSpecialOfferOpen: React.Dispatch<React.SetStateAction<boolean>>;
}
function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
const location = useLocation();
const navigate = useNavigate();
const dispatch = useDispatch();
const showNavbar = hasNavigation(location.pathname);
const showFooter = hasNoFooter(location.pathname);
const showHeader = hasNoHeader(location.pathname);
const isRouteFullDataModal = hasFullDataModal(location.pathname);
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar;
const mainRef = useRef<HTMLDivElement>(null);
useSchemeColorByElement(mainRef.current, "section.page, .page, section", [
location,
]);
const birthdate = useSelector(selectors.selectBirthdate);
const dataItems = useMemo(() => [birthdate], [birthdate]);
const [isShowFullDataModal, setIsShowFullDataModal] =
useState<boolean>(false);
useEffect(() => {
setIsShowFullDataModal(getIsShowFullDataModal(dataItems));
}, [dataItems]);
const onCloseFullDataModal = (_birthDate: string) => {
dispatch(actions.form.addDate(_birthDate));
setIsShowFullDataModal(getIsShowFullDataModal(dataItems));
};
const handleCompatibility = () => {
dispatch(
actions.siteConfig.update({
home: {
pathFromHome: EPathsFromHome.navbar,
isShowNavbar: showNavbarFooter,
},
})
);
navigate(routes.client.compatibility());
};
const handleBreath = () => {
dispatch(
actions.siteConfig.update({
home: {
pathFromHome: EPathsFromHome.navbar,
isShowNavbar: showNavbarFooter,
},
})
);
navigate(routes.client.breath());
};
const navbarItems: INavbarHomeItems[] = [
{
title: "Breathing",
path: routes.client.breath(),
paths: [routes.client.breath(), routes.client.breathResult()],
image: "Breath.svg",
onClick: handleBreath,
},
{
title: "Aura",
path: routes.client.home(),
paths: [routes.client.home()],
image: "Aura.svg",
active: true,
onClick: () => null,
},
{
title: "Compatibility",
path: routes.client.compatibility(),
paths: [
routes.client.compatibility(),
routes.client.compatibilityResult(),
],
image: "Compatibility.svg",
onClick: handleCompatibility,
},
{
title: "Advisors",
path: routes.client.advisors(),
paths: [routes.client.advisors()],
image: "moon.svg",
onClick: () => null,
},
{
title: "My Moon",
path: routes.client.wallpaper(),
paths: [routes.client.wallpaper()],
image: "moon.svg",
onClick: () => null,
},
];
return (
<div className="container">
<ScrollToTop />
{showHeader ? (
<Header
openMenu={() => setIsMenuOpen(true)}
clickCross={changeIsSpecialOfferOpen}
/>
) : null}
{isRouteFullDataModal && (
<Modal open={isShowFullDataModal} isCloseButtonVisible={false}>
<FullDataModal onClose={onCloseFullDataModal} />
</Modal>
)}
<main className="content" ref={mainRef}>
<Outlet />
</main>
{showFooter ? <Footer color={showNavbar ? "black" : "white"} /> : null}
{showNavbar ? (
<Navbar isOpen={isMenuOpen} closeMenu={() => setIsMenuOpen(false)} />
) : null}
{showNavbarFooter && hasNavbarFooter(location.pathname) ? (
<NavbarFooter items={navbarItems} />
) : null}
</div>
);
}
// enum EIsAuthPageType {
// private,
// 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;
};
};
}
function ShortPathOutlet(props: IShortPathOutletProps): JSX.Element {
const { productKey, requiredParameters, redirectUrls, isProductPage } = props;
const { user, token } = useAuth();
const api = useApi();
const isForce = useSelector(selectors.selectIsForceShortPath);
const loadData = useCallback(async () => {
if (!token?.length || !user?.email || !productKey?.length)
return {
status: "error",
error: "Missing params",
};
try {
const purchased = await api.checkProductPurchased({
email: user?.email || "",
productKey,
token,
});
return purchased;
} catch (error) {
console.error(error);
return {
status: "error",
error: "Something went wrong",
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [token]);
const { data, isPending } = useApiCall(loadData, "pending");
if (isPending) {
return <LoadingPage />;
}
const isPurchasedProduct = !!(data && "active" in data && data.active);
const isUser = !!user && !!token.length;
const isFullData = requiredParameters.every((item) => !!item);
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 {
const status = useSelector(selectors.selectStatus);
const { user } = useAuth();
return user && status === "subscribed" ? (
<Navigate to={routes.client.home()} replace={true} />
) : (
<Outlet />
);
}
function PrivateOutlet(): JSX.Element {
const { user } = useAuth();
return user ? (
<Outlet />
) : (
<Navigate to={routes.client.root()} replace={true} />
);
}
function PrivateSubscriptionOutlet(): JSX.Element {
const isProduction = import.meta.env.MODE === "production";
const status = useSelector(selectors.selectStatus);
return status === "subscribed" || !isProduction ? (
<Outlet />
) : (
<Navigate to={getRouteBy(status)} replace={true} />
);
}
function getIsShowFullDataModal(dataItems: Array<unknown> = []): boolean {
let hasNoDataItem = false;
for (const item of dataItems) {
if (!item) {
hasNoDataItem = true;
break;
}
}
return hasNoDataItem;
}
function SkipStep(): JSX.Element {
const { user } = useAuth();
return user ? (
<Navigate to={routes.client.emailEnter()} replace={true} />
) : (
<CreateProfilePage />
);
}
function MainPage(): JSX.Element {
const status = useSelector(selectors.selectStatus);
return <Navigate to={getRouteBy(status)} replace={true} />;
}
export default App;