feat: loading compatibility page, navbar, wallpaper page, fix styles, fix create profile page,
This commit is contained in:
parent
3cb9df55e1
commit
dea56a0175
10
public/navbar-icons/Aura.svg
Normal file
10
public/navbar-icons/Aura.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<svg width="85" height="85" viewBox="0 0 85 85" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_15_551)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M77.0489 75.6872C62.1443 66.5238 55.0039 70.6846 55.6277 88.1698C47.3013 72.7818 39.037 72.815 30.8347 88.2693C31.3179 70.78 24.1442 66.6766 9.31347 75.9592C18.4769 61.0545 14.316 53.9141 -3.16936 54.538C12.2187 46.2115 12.1854 37.9472 -3.26923 29.7448C14.2206 30.2281 18.324 23.0543 9.04098 8.22364C23.9459 17.387 31.0864 13.2261 30.4625 -4.25926C38.789 11.129 47.0534 11.0957 55.2555 -4.35895C54.7722 13.1308 61.946 17.2342 76.7769 7.95127C67.6135 22.8562 71.7743 29.9967 89.2595 29.3728C73.8715 37.6991 73.9047 45.9635 89.359 54.1658C71.8697 53.6825 67.7663 60.8563 77.0489 75.6872ZM57.9336 67.7485C50.4888 59.8154 45.525 61.1448 43.0422 71.7367C40.5614 61.1442 35.598 59.8137 28.1518 67.7454C31.2997 57.3318 27.6665 53.6979 17.2521 56.8437C25.185 49.399 23.8555 44.4353 13.2635 41.9525C23.8558 39.4717 25.1863 34.5083 17.2548 27.0621C27.6685 30.21 31.3025 26.5767 28.1566 16.1623C35.6013 24.0953 40.565 22.7658 43.0477 12.1738C45.5286 22.7661 50.4921 24.0966 57.9381 16.1651C54.7904 26.5788 58.4238 30.2127 68.8382 27.0668C60.9051 34.5115 62.2345 39.4753 72.8264 41.958C62.2339 44.4389 60.9035 49.4024 68.8352 56.8484C58.4215 53.7007 54.7876 57.3341 57.9336 67.7485Z" fill="#F23F57"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_15_551">
|
||||||
|
<rect width="85" height="85" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
3
public/navbar-icons/Breath.svg
Normal file
3
public/navbar-icons/Breath.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="84" height="54" viewBox="0 0 84 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M70.4542 25.0242C66.9834 32.9381 62.7944 37.9726 56.2641 41.7247C65.6934 33.4491 70.9208 16.6773 67.2495 6.31468C62.8102 6.42848 58.9952 7.71791 55.1007 11.0959C58.7065 19.2235 58.5585 30.5961 55.115 38.5333C54.5119 39.9242 52.2216 42.3195 49.8506 45.0397C56.0821 37.8878 57.7536 16.0647 47.8578 5.00866C46.2062 2.96009 44.2618 1.23063 42 0C39.7382 1.23063 37.7939 2.96009 36.1425 5.00866C26.2466 16.0647 27.918 37.8876 34.1496 45.0397C31.7784 42.3195 29.4883 39.9242 28.8853 38.5333C25.4415 30.5961 25.2935 19.2235 28.8994 11.0959C25.0049 7.71791 21.19 6.42848 16.7506 6.31468C13.0792 16.6773 18.3067 33.4491 27.7361 41.7247C21.2057 37.9726 17.0166 32.9381 13.5458 25.0242C9.22441 21.2831 2.91309 20.8145 0 21.7503C4.1265 47.4759 30.1028 53.5577 42 53.5577C53.8972 53.5577 79.8735 47.4759 84 21.7503C81.0869 20.8145 74.7756 21.2831 70.4542 25.0242Z" fill="#DEDEDE"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 980 B |
3
public/navbar-icons/Compatibility.svg
Normal file
3
public/navbar-icons/Compatibility.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M39 77.962C60.3354 77.962 78 60.2677 78 38.981C78 17.6561 60.297 0 38.9617 0C17.6647 0 0 17.6561 0 38.981C0 60.2677 17.7029 77.962 39 77.962ZM29.5176 21.5542C33.7617 21.5542 37.0117 23.9618 39 27.5542C40.95 23.9618 44.2764 21.5542 48.4822 21.5542C55.1351 21.5542 59.9912 26.5988 59.9912 33.5924C59.9912 43.9109 48.9795 53.3504 40.95 58.5861C40.338 59.0447 39.5734 59.5414 39.0764 59.5414C38.5794 59.5414 37.7 59.0064 37.0117 58.5861C28.9441 53.465 18.0088 43.9109 18.0088 33.5924C18.0088 26.5988 22.8265 21.5542 29.5176 21.5542Z" fill="white" fill-opacity="0.85"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 677 B |
10
public/navbar-icons/moon.svg
Normal file
10
public/navbar-icons/moon.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<svg width="70" height="78" viewBox="0 0 70 78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_7_30)">
|
||||||
|
<path d="M30.2249 72.3565C42.8536 72.3565 53.1385 66.0859 57.7911 55.2166C58.3159 53.9973 58.246 52.9175 57.6163 52.2904C57.1266 51.7678 56.1469 51.6982 55.0976 52.0813C52.1939 53.2311 48.9054 53.7883 45.0925 53.7883C29.2454 53.7883 19.0305 43.8947 19.0305 28.427C19.0305 24.4904 19.7651 20.0661 20.9545 17.6624C21.5492 16.4431 21.5492 15.3631 20.9895 14.7361C20.3948 14.0393 19.3103 13.9348 17.9461 14.4574C7.20641 18.7075 0 29.925 0 42.6754C0 59.6062 12.5587 72.3565 30.2249 72.3565ZM56.5316 40.5154C57.1965 40.5154 57.6514 40.0627 57.7213 39.366C58.8754 30.0643 59.3304 29.8205 68.8107 28.2877C69.5454 28.1832 70 27.8 70 27.138C70 26.4762 69.5454 26.0581 68.9504 25.9536C59.4002 24.1421 58.8754 24.1769 57.7213 14.8754C57.6514 14.1787 57.1965 13.7258 56.5316 13.7258C55.9022 13.7258 55.4473 14.1787 55.3423 14.8406C54.153 24.2814 53.803 24.5949 44.1131 25.9536C43.5181 26.0233 43.0636 26.4762 43.0636 27.138C43.0636 27.7651 43.5181 28.1832 44.1131 28.2877C53.803 30.134 54.1179 30.134 55.3423 39.4356C55.4473 40.0627 55.9022 40.5154 56.5316 40.5154ZM39.8102 16.9308C40.23 16.9308 40.4399 16.6869 40.5098 16.3037C41.5941 10.4859 41.5594 10.3466 47.6463 9.19696C48.031 9.12729 48.3108 8.88343 48.3108 8.46541C48.3108 8.04736 48.031 7.8035 47.6463 7.73383C41.5594 6.51452 41.7693 6.37518 40.5098 0.627066C40.4399 0.243859 40.23 0 39.8102 0C39.3904 0 39.1453 0.243859 39.0755 0.627066C37.8511 6.37518 38.061 6.51452 31.974 7.73383C31.5542 7.8035 31.3094 8.04736 31.3094 8.46541C31.3094 8.88343 31.5542 9.12729 31.974 9.19696C38.061 10.4163 37.9911 10.4859 39.0755 16.3037C39.1453 16.6869 39.3904 16.9308 39.8102 16.9308Z" fill="white" fill-opacity="0.85"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_7_30">
|
||||||
|
<rect width="70" height="78" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@ -1,43 +1,56 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Routes, Route, Navigate, Outlet, useLocation, useNavigate
|
Routes,
|
||||||
} from 'react-router-dom'
|
Route,
|
||||||
import { useAuth } from '@/auth'
|
Navigate,
|
||||||
import { useSelector } from 'react-redux'
|
Outlet,
|
||||||
import { selectors } from '@/store'
|
useLocation,
|
||||||
import routes, { hasNavigation, getRouteBy, hasNoFooter, hasNoHeader } from '@/routes'
|
useNavigate,
|
||||||
import BirthdayPage from '../BirthdayPage'
|
} from "react-router-dom";
|
||||||
import BirthtimePage from '../BirthtimePage'
|
import { useAuth } from "@/auth";
|
||||||
import CreateProfilePage from '../CreateProfilePage'
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import EmailEnterPage from '../EmailEnterPage'
|
import { actions, selectors } from "@/store";
|
||||||
import SubscriptionPage from '../SubscriptionPage'
|
import routes, {
|
||||||
import PaymentPage from '../PaymentPage'
|
hasNavigation,
|
||||||
import WallpaperPage from '../WallpaperPage'
|
getRouteBy,
|
||||||
import StaticPage from '../StaticPage'
|
hasNoFooter,
|
||||||
import NotFoundPage from '../NotFoundPage'
|
hasNoHeader,
|
||||||
import Header from '../Header'
|
hasNavbarFooter,
|
||||||
import Navbar from '../Navbar'
|
} from "@/routes";
|
||||||
import Footer from '../Footer'
|
import BirthdayPage from "../BirthdayPage";
|
||||||
import './styles.css'
|
import BirthtimePage from "../BirthtimePage";
|
||||||
import DidYouKnowPage from '../DidYouKnowPage'
|
import CreateProfilePage from "../CreateProfilePage";
|
||||||
import FreePeriodInfoPage from '../FreePeriodInfoPage'
|
import EmailEnterPage from "../EmailEnterPage";
|
||||||
import AttentionPage from '../AttentionPage'
|
import SubscriptionPage from "../SubscriptionPage";
|
||||||
import FeedbackPage from '../FeedbackPage'
|
import PaymentPage from "../PaymentPage";
|
||||||
import CompatibilityPage from '../Compatibility'
|
import WallpaperPage from "../WallpaperPage";
|
||||||
import BreathPage from '../BreathPage'
|
import StaticPage from "../StaticPage";
|
||||||
import PriceListPage from '../PriceListPage'
|
import NotFoundPage from "../NotFoundPage";
|
||||||
import CompatResultPage from '../CompatResultPage'
|
import Header from "../Header";
|
||||||
import HomePage from '../HomePage'
|
import Navbar from "../Navbar";
|
||||||
import UserCallbacksPage from '../UserCallbacksPage'
|
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";
|
||||||
|
|
||||||
function App(): JSX.Element {
|
function App(): JSX.Element {
|
||||||
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false)
|
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const closeSpecialOfferAttention = () => {
|
const closeSpecialOfferAttention = () => {
|
||||||
setIsSpecialOfferOpen(false)
|
setIsSpecialOfferOpen(false);
|
||||||
navigate(routes.client.emailEnter())
|
navigate(routes.client.emailEnter());
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -45,69 +58,175 @@ function App(): JSX.Element {
|
|||||||
<Route path={routes.client.root()} element={<MainPage />} />
|
<Route path={routes.client.root()} element={<MainPage />} />
|
||||||
<Route path={routes.client.birthday()} element={<BirthdayPage />} />
|
<Route path={routes.client.birthday()} element={<BirthdayPage />} />
|
||||||
<Route path={routes.client.didYouKnow()} element={<DidYouKnowPage />} />
|
<Route path={routes.client.didYouKnow()} element={<DidYouKnowPage />} />
|
||||||
<Route path={routes.client.freePeriodInfo()} element={<FreePeriodInfoPage />} />
|
<Route
|
||||||
<Route path={routes.client.attention()} element={<AttentionPage isOpenModal={isSpecialOfferOpen} onCloseSpecialOffer={closeSpecialOfferAttention} />} />
|
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.feedback()} element={<FeedbackPage />} />
|
||||||
<Route path={routes.client.birthtime()} element={<BirthtimePage />} />
|
<Route path={routes.client.birthtime()} element={<BirthtimePage />} />
|
||||||
<Route path={routes.client.createProfile()} element={<SkipStep />} />
|
<Route path={routes.client.createProfile()} element={<SkipStep />} />
|
||||||
<Route path={routes.client.emailEnter()} element={<EmailEnterPage />} />
|
<Route path={routes.client.emailEnter()} element={<EmailEnterPage />} />
|
||||||
<Route path={routes.client.static()} element={<StaticPage />} />
|
<Route path={routes.client.static()} element={<StaticPage />} />
|
||||||
<Route path={routes.client.compatibility()} element={<CompatibilityPage />} />
|
<Route
|
||||||
<Route path={routes.client.compatibilityResult()} element={<CompatResultPage />} />
|
path={routes.client.compatibility()}
|
||||||
|
element={<CompatibilityPage />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={routes.client.compatibilityResult()}
|
||||||
|
element={<CompatResultPage />}
|
||||||
|
/>
|
||||||
<Route path={routes.client.breath()} element={<BreathPage />} />
|
<Route path={routes.client.breath()} element={<BreathPage />} />
|
||||||
<Route path={routes.client.priceList()} element={<PriceListPage />} />
|
<Route path={routes.client.priceList()} element={<PriceListPage />} />
|
||||||
<Route path={routes.client.home()} element={<HomePage />} />
|
<Route path={routes.client.home()} element={<HomePage />} />
|
||||||
<Route path={routes.client.breathResult()} element={<UserCallbacksPage />} />
|
<Route
|
||||||
<Route path={routes.client.subscription()} element={<SubscriptionPage />} />
|
path={routes.client.breathResult()}
|
||||||
|
element={<UserCallbacksPage />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={routes.client.subscription()}
|
||||||
|
element={<SubscriptionPage />}
|
||||||
|
/>
|
||||||
<Route path={routes.client.paymentMethod()} element={<PaymentPage />} />
|
<Route path={routes.client.paymentMethod()} element={<PaymentPage />} />
|
||||||
<Route element={<PrivateOutlet />}>
|
<Route
|
||||||
<Route path={routes.client.wallpaper()} element={<ProtectWallpaperPage />} />
|
path={routes.client.wallpaper()}
|
||||||
</Route>
|
element={<ProtectWallpaperPage />}
|
||||||
|
/>
|
||||||
|
<Route element={<PrivateOutlet />}></Route>
|
||||||
<Route path="*" element={<NotFoundPage />} />
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
setIsSpecialOfferOpen: React.Dispatch<React.SetStateAction<boolean>>
|
setIsSpecialOfferOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
||||||
const location = useLocation()
|
const location = useLocation();
|
||||||
const showNavbar = hasNavigation(location.pathname)
|
const navigate = useNavigate();
|
||||||
const showFooter = hasNoFooter(location.pathname)
|
const dispatch = useDispatch();
|
||||||
const showHeader = hasNoHeader(location.pathname)
|
const showNavbar = hasNavigation(location.pathname);
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false)
|
const showFooter = hasNoFooter(location.pathname);
|
||||||
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true)
|
const showHeader = hasNoHeader(location.pathname);
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
||||||
|
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
|
||||||
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
|
||||||
|
const handleCompatibility = () => {
|
||||||
|
dispatch(
|
||||||
|
actions.siteConfig.update({
|
||||||
|
home: {
|
||||||
|
pathFromHome: EPathsFromHome.compatibility,
|
||||||
|
isShowNavbar: showNavbarFooter,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
navigate(routes.client.compatibility());
|
||||||
|
};
|
||||||
|
const handleBreath = () => {
|
||||||
|
dispatch(
|
||||||
|
actions.siteConfig.update({
|
||||||
|
home: {
|
||||||
|
pathFromHome: EPathsFromHome.breath,
|
||||||
|
isShowNavbar: showNavbarFooter,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
navigate(routes.client.breath());
|
||||||
|
};
|
||||||
|
|
||||||
|
const navbarItems: INavbarHomeItems[] = [
|
||||||
|
{
|
||||||
|
title: "Breathing",
|
||||||
|
path: routes.client.breath(),
|
||||||
|
image: "Breath.svg",
|
||||||
|
onClick: handleBreath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Aura",
|
||||||
|
path: routes.client.home(),
|
||||||
|
image: "Aura.svg",
|
||||||
|
active: true,
|
||||||
|
onClick: () => null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Compatibility",
|
||||||
|
path: routes.client.compatibility(),
|
||||||
|
image: "Compatibility.svg",
|
||||||
|
onClick: handleCompatibility,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "My Moon",
|
||||||
|
path: routes.client.wallpaper(),
|
||||||
|
image: "moon.svg",
|
||||||
|
onClick: () => null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='container'>
|
<div className="container">
|
||||||
{ showHeader ? <Header openMenu={() => setIsMenuOpen(true)} clickCross={changeIsSpecialOfferOpen}/> : null }
|
{showHeader ? (
|
||||||
<main className='content'><Outlet /></main>
|
<Header
|
||||||
{ showFooter ? <Footer color={showNavbar ? 'black' : 'white'}/> : null }
|
openMenu={() => setIsMenuOpen(true)}
|
||||||
{ showNavbar ? <Navbar isOpen={isMenuOpen} closeMenu={() => setIsMenuOpen(false)} /> : null}
|
clickCross={changeIsSpecialOfferOpen}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<main className="content">
|
||||||
|
<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>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrivateOutlet(): JSX.Element {
|
function PrivateOutlet(): JSX.Element {
|
||||||
const { user } = useAuth()
|
const { user } = useAuth();
|
||||||
return user ? <Outlet /> : <Navigate to={routes.client.root()} replace={true} />
|
return user ? (
|
||||||
|
<Outlet />
|
||||||
|
) : (
|
||||||
|
<Navigate to={routes.client.root()} replace={true} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SkipStep(): JSX.Element {
|
function SkipStep(): JSX.Element {
|
||||||
const { user } = useAuth()
|
const { user } = useAuth();
|
||||||
return user ? <Navigate to={routes.client.emailEnter()} replace={true} /> : <CreateProfilePage />
|
return user ? (
|
||||||
|
<Navigate to={routes.client.emailEnter()} replace={true} />
|
||||||
|
) : (
|
||||||
|
<CreateProfilePage />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MainPage(): JSX.Element {
|
function MainPage(): JSX.Element {
|
||||||
const status = useSelector(selectors.selectStatus)
|
const status = useSelector(selectors.selectStatus);
|
||||||
return <Navigate to={getRouteBy(status)} replace={true} />
|
return <Navigate to={getRouteBy(status)} replace={true} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProtectWallpaperPage(): JSX.Element {
|
function ProtectWallpaperPage(): JSX.Element {
|
||||||
const status = useSelector(selectors.selectStatus)
|
const status = useSelector(selectors.selectStatus);
|
||||||
return status === 'subscribed' ? <WallpaperPage /> : <Navigate to={getRouteBy(status)} replace={true} />
|
return (<WallpaperPage />);
|
||||||
|
return status === "subscribed" ? (
|
||||||
|
<WallpaperPage />
|
||||||
|
) : (
|
||||||
|
<Navigate to={getRouteBy(status)} replace={true} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import styles from "./styles.module.css";
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { UserCallbacks, useApi, useApiCall } from "@/api";
|
import { UserCallbacks, useApi, useApiCall } from "@/api";
|
||||||
import { Asset } from "@/api/resources/Assets";
|
import { Asset } from "@/api/resources/Assets";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { actions } from "@/store";
|
import { actions, selectors } from "@/store";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import FullScreenModal from "../FullScreenModal";
|
import FullScreenModal from "../FullScreenModal";
|
||||||
import StartBreathModalChild from "../StartBreathModalChild";
|
import StartBreathModalChild from "../StartBreathModalChild";
|
||||||
@ -24,6 +24,8 @@ function BreathPage(): JSX.Element {
|
|||||||
const api = useApi();
|
const api = useApi();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
|
||||||
const assetsData = useCallback(async () => {
|
const assetsData = useCallback(async () => {
|
||||||
const { assets } = await api.getAssets({
|
const { assets } = await api.getAssets({
|
||||||
@ -116,7 +118,7 @@ function BreathPage(): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className={`${styles.page} page`} ref={pageRef}>
|
<section className={`${styles.page} page`} ref={pageRef} style={{ paddingBottom: showNavbarFooter ? '48px' : '16px'}}>
|
||||||
<canvas
|
<canvas
|
||||||
style={{ display: isOpenModal ? "hidden" : "block" }}
|
style={{ display: isOpenModal ? "hidden" : "block" }}
|
||||||
className={`${styles["leo-apng"]} ${
|
className={`${styles["leo-apng"]} ${
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Title from "../Title";
|
|||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { actions, selectors } from "@/store";
|
import { actions, selectors } from "@/store";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { AICompats, AIRequests, useApi, useApiCall } from "@/api";
|
import { AICompats, AIRequests, useApi, useApiCall } from "@/api";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
@ -22,27 +22,17 @@ function CompatResultPage(): JSX.Element {
|
|||||||
const rightUser = useSelector(selectors.selectRightUser);
|
const rightUser = useSelector(selectors.selectRightUser);
|
||||||
const categoryId = useSelector(selectors.selectCategoryId);
|
const categoryId = useSelector(selectors.selectCategoryId);
|
||||||
const homeConfig = useSelector(selectors.selectHome);
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
const [text, setText] = useState("Loading...");
|
const [text, setText] = useState("Loading...");
|
||||||
const [isOpenModal, setIsOpenModal] = useState(true);
|
const [isOpenModal, setIsOpenModal] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timeOut = setTimeout(() => {
|
|
||||||
setIsOpenModal(false)
|
|
||||||
}, 5000)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearTimeout(timeOut)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
|
if (homeConfig.pathFromHome === EPathsFromHome.breath) {
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.siteConfig.update({
|
actions.siteConfig.update({
|
||||||
home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true },
|
home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (homeConfig.pathFromHome === EPathsFromHome.breath) {
|
|
||||||
return navigate(routes.client.home());
|
return navigate(routes.client.home());
|
||||||
}
|
}
|
||||||
if (homeConfig.pathFromHome === EPathsFromHome.compatibility) {
|
if (homeConfig.pathFromHome === EPathsFromHome.compatibility) {
|
||||||
@ -87,10 +77,24 @@ function CompatResultPage(): JSX.Element {
|
|||||||
|
|
||||||
useApiCall<AICompats.ICompat | AIRequests.IAiRequest>(loadData);
|
useApiCall<AICompats.ICompat | AIRequests.IAiRequest>(loadData);
|
||||||
|
|
||||||
|
const getPaddingBottomPage = () => {
|
||||||
|
if (homeConfig.pathFromHome === EPathsFromHome.compatibility && showNavbarFooter) return "246px";
|
||||||
|
if (showNavbarFooter) return "164px";
|
||||||
|
return "108px";
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section
|
||||||
|
className={`${styles.page} page`}
|
||||||
|
style={{ paddingBottom: getPaddingBottomPage() }}
|
||||||
|
>
|
||||||
<FullScreenModal isOpen={isOpenModal}>
|
<FullScreenModal isOpen={isOpenModal}>
|
||||||
<CompatibilityLoading />
|
<CompatibilityLoading
|
||||||
|
secondPerson={rightUser.name}
|
||||||
|
onEndLoading={() => {
|
||||||
|
setIsOpenModal(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{text !== "Loading..." && (
|
{text !== "Loading..." && (
|
||||||
<div className={styles.cross} onClick={handleNext}></div>
|
<div className={styles.cross} onClick={handleNext}></div>
|
||||||
@ -106,7 +110,7 @@ function CompatResultPage(): JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
{text !== "Loading..." &&
|
{text !== "Loading..." &&
|
||||||
homeConfig.pathFromHome === EPathsFromHome.compatibility && (
|
homeConfig.pathFromHome === EPathsFromHome.compatibility && (
|
||||||
<div className={styles["button-container"]}>
|
<div className={styles["button-container"]} style={{ bottom: showNavbarFooter ? "75px" : "0" }}>
|
||||||
<p className={styles["button-container__text"]}>
|
<p className={styles["button-container__text"]}>
|
||||||
{t("now-you-know")}
|
{t("now-you-know")}
|
||||||
</p>
|
</p>
|
||||||
@ -120,7 +124,11 @@ function CompatResultPage(): JSX.Element {
|
|||||||
)}
|
)}
|
||||||
{text !== "Loading..." &&
|
{text !== "Loading..." &&
|
||||||
homeConfig.pathFromHome === EPathsFromHome.breath && (
|
homeConfig.pathFromHome === EPathsFromHome.breath && (
|
||||||
<button className={styles["button-green"]} onClick={handleNext}>
|
<button
|
||||||
|
className={styles["button-green"]}
|
||||||
|
onClick={handleNext}
|
||||||
|
style={{ bottom: showNavbarFooter ? "88px" : "24px" }}
|
||||||
|
>
|
||||||
{t("use-all-power")}
|
{t("use-all-power")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -9,8 +9,8 @@ import { IDate } from "@/services/date";
|
|||||||
import { AICompatCategories, useApi, useApiCall } from "@/api";
|
import { AICompatCategories, useApi, useApiCall } from "@/api";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import routes from "@/routes";
|
import routes from "@/routes";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { actions } from "@/store";
|
import { actions, selectors } from "@/store";
|
||||||
|
|
||||||
function CompatibilityPage(): JSX.Element {
|
function CompatibilityPage(): JSX.Element {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
@ -22,6 +22,8 @@ function CompatibilityPage(): JSX.Element {
|
|||||||
const [name, setName] = useState<string>("");
|
const [name, setName] = useState<string>("");
|
||||||
const [selectedDate, setSelectedDate] = useState<string | IDate>("");
|
const [selectedDate, setSelectedDate] = useState<string | IDate>("");
|
||||||
const [compatCategory, setCompatCategory] = useState(1);
|
const [compatCategory, setCompatCategory] = useState(1);
|
||||||
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
if (isDisabled) return;
|
if (isDisabled) return;
|
||||||
@ -67,7 +69,7 @@ function CompatibilityPage(): JSX.Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section className={`${styles.page} page`} style={{ paddingBottom: showNavbarFooter ? '48px' : '16px'}}>
|
||||||
<div className={styles.cross} onClick={handleNext}></div>
|
<div className={styles.cross} onClick={handleNext}></div>
|
||||||
{/* <Title variant="h1" className={styles.title}>
|
{/* <Title variant="h1" className={styles.title}>
|
||||||
{t("compatibility")}
|
{t("compatibility")}
|
||||||
|
|||||||
@ -1,16 +1,80 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
import Title from "../Title";
|
import Title from "../Title";
|
||||||
|
import ProgressBarLine from "../ui/ProgressBarLine";
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
|
import Spinner from "../ui/Spinner";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { selectors } from "@/store";
|
||||||
|
|
||||||
// interface ICompatibilityLoadingProps {
|
interface ICompatibilityLoadingProps {
|
||||||
// onEndLoading: () => void;
|
secondPerson: string;
|
||||||
// }
|
onEndLoading: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const progressBars = [
|
||||||
|
{
|
||||||
|
label: "Analysis of me",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Analysis of the second person",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "General compatibility",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Identifying compatibility issues",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getProgressValue = (index: number, value: number) => {
|
||||||
|
const integerDivision = Math.floor(value / 100);
|
||||||
|
if (integerDivision > index) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
if (integerDivision === index) {
|
||||||
|
return value % 100;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CompatibilityLoading({secondPerson, onEndLoading}: ICompatibilityLoadingProps): JSX.Element {
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (progress >= progressBars.length * 100) {
|
||||||
|
return onEndLoading()
|
||||||
|
}
|
||||||
|
const interval = setTimeout(() => {
|
||||||
|
setProgress((prevProgress) => {
|
||||||
|
return prevProgress + 1;
|
||||||
|
});
|
||||||
|
}, 50);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(interval);
|
||||||
|
}
|
||||||
|
}, [progress, onEndLoading]);
|
||||||
|
|
||||||
function CompatibilityLoading(): JSX.Element {
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.container}`}>
|
<section className={`${styles.container}`} style={{ paddingBottom: showNavbarFooter ? '48px' : '16px'}}>
|
||||||
<Title variant="h3" className={styles.title}>
|
<Title variant="h3" className={styles.title}>
|
||||||
Analysis of you with Viktor Ershov
|
Analysis of you with {secondPerson}
|
||||||
</Title>
|
</Title>
|
||||||
|
{progressBars.map((progressBar, index) => (
|
||||||
|
<div className={styles["progress-bar"]} key={index}>
|
||||||
|
<Title variant="h4" className={styles["progress-bar__label"]}>
|
||||||
|
{progressBar.label}
|
||||||
|
</Title>
|
||||||
|
<div className={styles["progress-bar__container"]}>
|
||||||
|
<ProgressBarLine containerClassName={styles["progress-bar__line"]} value={getProgressValue(index, progress)} delay={50} />
|
||||||
|
<span className={styles["progress-bar__percentage"]}>
|
||||||
|
{getProgressValue(index, progress)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Spinner width="40px" strokeWidth={3} />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
.container {
|
.container {
|
||||||
padding: 16px;
|
padding: 16px 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -9,4 +9,31 @@
|
|||||||
.title {
|
.title {
|
||||||
color: #fd3761;
|
color: #fd3761;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar__label {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar__container {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar__line {
|
||||||
|
width: calc(100% - 56px);
|
||||||
}
|
}
|
||||||
@ -22,6 +22,14 @@ function CreateProfilePage(): JSX.Element {
|
|||||||
y: auraCoordinates.Y - 125
|
y: auraCoordinates.Y - 125
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.classList.add('fixed-page');
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.classList.remove('fixed-page');
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setAuraCoordinatesCounted(
|
setAuraCoordinatesCounted(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
.page {
|
.page {
|
||||||
height: calc(100vh - 50px);
|
height: calc(100vh - 50px);
|
||||||
|
max-height: -webkit-fill-available;
|
||||||
flex: auto !important;
|
flex: auto !important;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -9,6 +10,7 @@
|
|||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
-o-user-select: none;
|
-o-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progressbar {
|
.progressbar {
|
||||||
|
|||||||
@ -23,7 +23,16 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__menu-btn, .cross {
|
.header__menu-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: calc((100% - 40px) / 2);
|
||||||
|
right: 28px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cross {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 33%;
|
top: 33%;
|
||||||
right: 28px;
|
right: 28px;
|
||||||
|
|||||||
@ -17,9 +17,8 @@ import { actions, selectors } from "@/store";
|
|||||||
import { getRandomArbitrary } from "@/services/random-value";
|
import { getRandomArbitrary } from "@/services/random-value";
|
||||||
import Title from "../Title";
|
import Title from "../Title";
|
||||||
import { UserDailyForecast } from "@/api/resources/UserDailyForecasts";
|
import { UserDailyForecast } from "@/api/resources/UserDailyForecasts";
|
||||||
import { download } from "@/services/download";
|
|
||||||
import { EPathsFromHome } from "@/store/siteConfig";
|
import { EPathsFromHome } from "@/store/siteConfig";
|
||||||
import NavbarHome, { INavbarHomeItems } from "../NavbarHome";
|
import { buildFilename, saveFile } from "../WallpaperPage/utils";
|
||||||
|
|
||||||
|
|
||||||
const buttonTextFormatter = (text: string): JSX.Element => {
|
const buttonTextFormatter = (text: string): JSX.Element => {
|
||||||
@ -58,34 +57,6 @@ function HomePage(): JSX.Element {
|
|||||||
navigate(routes.client.breath());
|
navigate(routes.client.breath());
|
||||||
};
|
};
|
||||||
|
|
||||||
const navbarHomeItems: INavbarHomeItems[] = [
|
|
||||||
{
|
|
||||||
title: 'Breathing',
|
|
||||||
path: routes.client.breath(),
|
|
||||||
image: 'Breath.png',
|
|
||||||
onClick: handleBreath
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Aura',
|
|
||||||
path: routes.client.home(),
|
|
||||||
image: 'Aura.png',
|
|
||||||
active: true,
|
|
||||||
onClick: () => null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Compatibility',
|
|
||||||
path: routes.client.compatibility(),
|
|
||||||
image: 'Compatibility.png',
|
|
||||||
onClick: handleCompatibility
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'My Moon',
|
|
||||||
path: routes.client.home(),
|
|
||||||
image: 'moon.png',
|
|
||||||
onClick: () => null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const locale = i18n.language;
|
const locale = i18n.language;
|
||||||
@ -136,7 +107,7 @@ function HomePage(): JSX.Element {
|
|||||||
|
|
||||||
const downloadImg = () => {
|
const downloadImg = () => {
|
||||||
if (!asset) return;
|
if (!asset) return;
|
||||||
download(asset.url.replace("http://", "https://"), asset.asset_data.metadata.filename || "image.png");
|
saveFile(asset.url, buildFilename('1'));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -199,7 +170,6 @@ function HomePage(): JSX.Element {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isShowNavbar && <NavbarHome items={navbarHomeItems} />}
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ interface INavbarHomeProps {
|
|||||||
items: INavbarHomeItems[];
|
items: INavbarHomeItems[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavbarHome({ items }: INavbarHomeProps): JSX.Element {
|
function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className={`${styles["container"]}`}>
|
<div className={`${styles["container"]}`}>
|
||||||
{items.map((item, index) => (
|
{items.map((item, index) => (
|
||||||
@ -28,14 +28,32 @@ function NavbarHome({ items }: INavbarHomeProps): JSX.Element {
|
|||||||
to={item.path}
|
to={item.path}
|
||||||
onClick={item.onClick}
|
onClick={item.onClick}
|
||||||
>
|
>
|
||||||
<div className={styles["navbar-item__image-container"]}>
|
<div
|
||||||
<img
|
className={styles["navbar-item__image-container"]}
|
||||||
|
style={{
|
||||||
|
backgroundColor:
|
||||||
|
item.path === location.pathname ? "#ff2c57" : "#fff",
|
||||||
|
mask: `url('./navbar-icons/${item.image}')`,
|
||||||
|
WebkitMask: `url('./navbar-icons/${item.image}')`,
|
||||||
|
WebkitMaskSize: "contain",
|
||||||
|
WebkitMaskRepeat: "no-repeat",
|
||||||
|
WebkitMaskPosition: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <img
|
||||||
className={styles["navbar-item__image"]}
|
className={styles["navbar-item__image"]}
|
||||||
src={`./navbar-icons/${item.image}`}
|
src={`./navbar-icons/${item.image}`}
|
||||||
|
style={{ }}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</div>
|
||||||
<p>{item.title}</p>
|
<p
|
||||||
|
style={{
|
||||||
|
color: item.path === location.pathname ? "#ff2c57" : "#fff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@ -43,4 +61,4 @@ function NavbarHome({ items }: INavbarHomeProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NavbarHome;
|
export default NavbarFooter;
|
||||||
@ -8,6 +8,7 @@
|
|||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-item {
|
.navbar-item {
|
||||||
@ -31,9 +32,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar-item__image-container {
|
.navbar-item__image-container {
|
||||||
flex: 1;
|
/* flex: 1; */
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
mask-size: contain;
|
||||||
|
-webkit-mask-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-item__image {
|
.navbar-item__image {
|
||||||
@ -14,14 +14,15 @@ function UserCallbacksPage(): JSX.Element {
|
|||||||
const statChanges = useSelector(selectors.selectUserCallbacksPrevStat);
|
const statChanges = useSelector(selectors.selectUserCallbacksPrevStat);
|
||||||
const text = useSelector(selectors.selectUserCallbacksDescription);
|
const text = useSelector(selectors.selectUserCallbacksDescription);
|
||||||
const homeConfig = useSelector(selectors.selectHome);
|
const homeConfig = useSelector(selectors.selectHome);
|
||||||
|
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
|
if (homeConfig.pathFromHome === EPathsFromHome.compatibility) {
|
||||||
dispatch(
|
dispatch(
|
||||||
actions.siteConfig.update({
|
actions.siteConfig.update({
|
||||||
home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true },
|
home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (homeConfig.pathFromHome === EPathsFromHome.compatibility) {
|
|
||||||
return navigate(routes.client.home());
|
return navigate(routes.client.home());
|
||||||
}
|
}
|
||||||
if (homeConfig.pathFromHome === EPathsFromHome.breath) {
|
if (homeConfig.pathFromHome === EPathsFromHome.breath) {
|
||||||
@ -29,8 +30,17 @@ function UserCallbacksPage(): JSX.Element {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPaddingBottomPage = () => {
|
||||||
|
if (homeConfig.pathFromHome === EPathsFromHome.compatibility && showNavbarFooter) return "246px";
|
||||||
|
if (showNavbarFooter) return "164px";
|
||||||
|
return "108px";
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section
|
||||||
|
className={`${styles.page} page`}
|
||||||
|
style={{ paddingBottom: getPaddingBottomPage() }}
|
||||||
|
>
|
||||||
<div className={styles.cross} onClick={handleNext}></div>
|
<div className={styles.cross} onClick={handleNext}></div>
|
||||||
<div className={styles["title-container"]}>
|
<div className={styles["title-container"]}>
|
||||||
<Title variant="h3" className={styles.percent}>
|
<Title variant="h3" className={styles.percent}>
|
||||||
@ -60,12 +70,20 @@ function UserCallbacksPage(): JSX.Element {
|
|||||||
<p className={styles["result-container__text"]}>{text}</p>
|
<p className={styles["result-container__text"]}>{text}</p>
|
||||||
</div>
|
</div>
|
||||||
{homeConfig.pathFromHome === EPathsFromHome.breath && (
|
{homeConfig.pathFromHome === EPathsFromHome.breath && (
|
||||||
<button className={`${styles.button} ${styles['button-red']}`} onClick={handleNext}>
|
<button
|
||||||
|
className={`${styles.button} ${styles["button-red"]}`}
|
||||||
|
onClick={handleNext}
|
||||||
|
style={{ bottom: showNavbarFooter ? "88px" : "24px" }}
|
||||||
|
>
|
||||||
{t("aura.breath_compatibility.button")}
|
{t("aura.breath_compatibility.button")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{homeConfig.pathFromHome === EPathsFromHome.compatibility && (
|
{homeConfig.pathFromHome === EPathsFromHome.compatibility && (
|
||||||
<button className={styles.button} onClick={handleNext}>
|
<button
|
||||||
|
className={styles.button}
|
||||||
|
onClick={handleNext}
|
||||||
|
style={{ bottom: showNavbarFooter ? "88px" : "24px" }}
|
||||||
|
>
|
||||||
{t("use-all-power")}
|
{t("use-all-power")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,61 +1,77 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from "react";
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAuth } from '@/auth'
|
import { useAuth } from "@/auth";
|
||||||
import { useApi, useApiCall, Assets, DailyForecasts } from '@/api'
|
import { useApi, useApiCall, Assets, DailyForecasts } from "@/api";
|
||||||
import { saveFile, buildFilename } from './utils'
|
import { saveFile, buildFilename } from "./utils";
|
||||||
import Loader, { LoaderColor } from '../Loader'
|
import Loader, { LoaderColor } from "../Loader";
|
||||||
import './styles.css'
|
import "./styles.css";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { selectors } from "@/store";
|
||||||
|
import { getCategoryIdByZodiacSign, getZodiacSignByDate } from "@/services/zodiac-sign";
|
||||||
|
|
||||||
type Forecasts = DailyForecasts.Forecast[]
|
type Forecasts = DailyForecasts.Forecast[];
|
||||||
type PersonalAssets = Assets.Asset[]
|
type PersonalAssets = Assets.Asset[];
|
||||||
interface WallpaperData {
|
interface WallpaperData {
|
||||||
assets: PersonalAssets
|
assets: PersonalAssets;
|
||||||
forecasts: Forecasts
|
forecasts: Forecasts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function WallpaperPage(): JSX.Element {
|
function WallpaperPage(): JSX.Element {
|
||||||
const api = useApi()
|
const api = useApi();
|
||||||
const { t } = useTranslation()
|
const { t, i18n } = useTranslation();
|
||||||
const { user, token } = useAuth()
|
const locale = i18n.language;
|
||||||
const category = user?.profile.sign?.sign || ''
|
const token =
|
||||||
const loadData = useCallback(() => {
|
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw";
|
||||||
|
|
||||||
|
const {
|
||||||
|
user,
|
||||||
|
// token
|
||||||
|
} = useAuth();
|
||||||
|
const birthdate = useSelector(selectors.selectBirthdate);
|
||||||
|
const zodiacSign = getZodiacSignByDate(birthdate);
|
||||||
|
const category = user?.profile.sign?.sign || "";
|
||||||
|
console.log(category);
|
||||||
|
|
||||||
|
const loadData = useCallback(async () => {
|
||||||
|
const { asset_categories } = await api.getAssetCategories({ locale });
|
||||||
|
const categoryId = getCategoryIdByZodiacSign(zodiacSign, asset_categories);
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
api.getAssets({ category }),
|
api.getAssets({ category: String(categoryId || "1"), }),
|
||||||
api.getDailyForecasts({ token }),
|
api.getDailyForecasts({ token }),
|
||||||
])
|
]).then(([{ assets }, { user_daily_forecast }]) => ({
|
||||||
.then(([{ assets }, { user_daily_forecast }]) => ({
|
|
||||||
assets,
|
assets,
|
||||||
forecasts: user_daily_forecast.forecasts,
|
forecasts: user_daily_forecast.forecasts,
|
||||||
}))
|
}));
|
||||||
}, [api, category, token])
|
}, [api, token, locale, zodiacSign]);
|
||||||
const { data, isPending } = useApiCall<WallpaperData>(loadData)
|
const { data, isPending } = useApiCall<WallpaperData>(loadData);
|
||||||
const forecasts = data ? data.forecasts : []
|
const forecasts = data ? data.forecasts : [];
|
||||||
const asset = data ? data.assets.at(0) : null
|
const asset = data ? data.assets.at(0) : null;
|
||||||
|
|
||||||
const handleClick = () => asset && saveFile(asset.url, buildFilename(category))
|
const handleClick = () =>
|
||||||
|
asset && saveFile(asset.url, buildFilename(category));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className='wallpaper-page'>
|
<section className="wallpaper-page">
|
||||||
<div className='wallpaper-image'>
|
<div className="wallpaper-image">
|
||||||
{asset ? <img src={asset.url} alt={category} /> : null}
|
{asset ? <img src={asset.url} alt={category} /> : null}
|
||||||
{asset ? <div className='btn-download' onClick={handleClick} /> : null}
|
{asset ? <div className="btn-download" onClick={handleClick} /> : null}
|
||||||
{isPending ? <Loader color={LoaderColor.White} /> : null}
|
{isPending ? <Loader color={LoaderColor.White} /> : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='wallpaper-content'>
|
<div className="wallpaper-content">
|
||||||
{isPending ? null : (
|
{isPending ? null : (
|
||||||
<>
|
<>
|
||||||
<h1 className='wallpaper-title'>{t('analysis_background')}</h1>
|
<h1 className="wallpaper-title">{t("analysis_background")}</h1>
|
||||||
{forecasts.map((forecast) => (
|
{forecasts.map((forecast) => (
|
||||||
<div key={forecast.category_name} className='wallpaper-forecast'>
|
<div key={forecast.category_name} className="wallpaper-forecast">
|
||||||
<h2 className='wallpaper-subtitle'>{forecast.category}</h2>
|
<h2 className="wallpaper-subtitle">{forecast.category}</h2>
|
||||||
<p className='wallpaper-text'>{forecast.body}</p>
|
<p className="wallpaper-text">{forecast.body}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WallpaperPage
|
export default WallpaperPage;
|
||||||
|
|||||||
17
src/components/ui/ProgressBarLine/index.tsx
Normal file
17
src/components/ui/ProgressBarLine/index.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import styles from "./styles.module.css";
|
||||||
|
|
||||||
|
interface IProgressBarLineProps {
|
||||||
|
value: number
|
||||||
|
delay: number
|
||||||
|
containerClassName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProgressBarLine({ value, delay, containerClassName }: IProgressBarLineProps): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className={`${styles.container} ${containerClassName || ""}`}>
|
||||||
|
<div className={styles.line} style={{ width: `${value}%`, transitionDuration: `${delay}ms` }}></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProgressBarLine;
|
||||||
14
src/components/ui/ProgressBarLine/styles.module.css
Normal file
14
src/components/ui/ProgressBarLine/styles.module.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
background-color: #908e95;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #db4263;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition-property: width;
|
||||||
|
}
|
||||||
34
src/components/ui/Spinner/index.tsx
Normal file
34
src/components/ui/Spinner/index.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import styles from "./styles.module.css";
|
||||||
|
|
||||||
|
interface ISpinnerProps {
|
||||||
|
width?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
strokeColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Spinner({
|
||||||
|
width = "30px",
|
||||||
|
strokeWidth = 5,
|
||||||
|
strokeColor = "#db4263",
|
||||||
|
}: ISpinnerProps): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
className={styles.spinner}
|
||||||
|
viewBox="0 0 50 50"
|
||||||
|
width={width}
|
||||||
|
height={width}
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
className={styles.path}
|
||||||
|
cx="25"
|
||||||
|
cy="25"
|
||||||
|
r="20"
|
||||||
|
fill="none"
|
||||||
|
stroke={strokeColor}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
></circle>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Spinner;
|
||||||
34
src/components/ui/Spinner/styles.module.css
Normal file
34
src/components/ui/Spinner/styles.module.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.spinner {
|
||||||
|
animation: rotate 2s linear infinite;
|
||||||
|
/* z-index: 2;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin: -25px 0 0 -25px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.path {
|
||||||
|
stroke-linecap: round;
|
||||||
|
animation: dash 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dash {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 1, 150;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 90, 150;
|
||||||
|
stroke-dashoffset: -35;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 90, 150;
|
||||||
|
stroke-dashoffset: -124;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -128,3 +128,10 @@ a,button,div,input,select,textarea {
|
|||||||
.CircularProgressbar {
|
.CircularProgressbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fixed-page {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@ -67,8 +67,7 @@ const routes = {
|
|||||||
[apiHost, prefix, "user", "callbacks.json"].join("/"),
|
[apiHost, prefix, "user", "callbacks.json"].join("/"),
|
||||||
getUserCallbacks: (id: string) =>
|
getUserCallbacks: (id: string) =>
|
||||||
[apiHost, prefix, "user", "callbacks", `${id}.json`].join("/"),
|
[apiHost, prefix, "user", "callbacks", `${id}.json`].join("/"),
|
||||||
getTranslations: () =>
|
getTranslations: () => [apiHost, "api/v2", "t.json"].join("/"),
|
||||||
[apiHost, "api/v2", "t.json"].join("/"),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,7 +86,10 @@ export const entrypoints = [
|
|||||||
];
|
];
|
||||||
export const isEntrypoint = (path: string) => entrypoints.includes(path);
|
export const isEntrypoint = (path: string) => entrypoints.includes(path);
|
||||||
export const isNotEntrypoint = (path: string) => !isEntrypoint(path);
|
export const isNotEntrypoint = (path: string) => !isEntrypoint(path);
|
||||||
export const withNavigationRoutes = [routes.client.wallpaper()];
|
export const withNavigationRoutes = [
|
||||||
|
routes.client.wallpaper(),
|
||||||
|
// routes.client.home(),
|
||||||
|
];
|
||||||
export const hasNavigation = (path: string) =>
|
export const hasNavigation = (path: string) =>
|
||||||
withNavigationRoutes.includes(path);
|
withNavigationRoutes.includes(path);
|
||||||
export const hasNoNavigation = (path: string) => !hasNavigation(path);
|
export const hasNoNavigation = (path: string) => !hasNavigation(path);
|
||||||
@ -115,6 +117,17 @@ export const withoutFooterRoutes = [
|
|||||||
export const hasNoFooter = (path: string) =>
|
export const hasNoFooter = (path: string) =>
|
||||||
!withoutFooterRoutes.includes(path);
|
!withoutFooterRoutes.includes(path);
|
||||||
|
|
||||||
|
export const withNavbarFooterRoutes = [
|
||||||
|
routes.client.home(),
|
||||||
|
routes.client.compatibility(),
|
||||||
|
routes.client.compatibilityResult(),
|
||||||
|
routes.client.breath(),
|
||||||
|
routes.client.breathResult(),
|
||||||
|
routes.client.wallpaper(),
|
||||||
|
];
|
||||||
|
export const hasNavbarFooter = (path: string) =>
|
||||||
|
withNavbarFooterRoutes.includes(path);
|
||||||
|
|
||||||
export const withoutHeaderRoutes = [
|
export const withoutHeaderRoutes = [
|
||||||
routes.client.compatibility(),
|
routes.client.compatibility(),
|
||||||
routes.client.subscription(),
|
routes.client.subscription(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user