diff --git a/public/navbar-icons/Aura.svg b/public/navbar-icons/Aura.svg new file mode 100644 index 0000000..7643edd --- /dev/null +++ b/public/navbar-icons/Aura.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/navbar-icons/Breath.svg b/public/navbar-icons/Breath.svg new file mode 100644 index 0000000..9427620 --- /dev/null +++ b/public/navbar-icons/Breath.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/navbar-icons/Compatibility.svg b/public/navbar-icons/Compatibility.svg new file mode 100644 index 0000000..e9a2bbd --- /dev/null +++ b/public/navbar-icons/Compatibility.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/navbar-icons/moon.svg b/public/navbar-icons/moon.svg new file mode 100644 index 0000000..3112bbb --- /dev/null +++ b/public/navbar-icons/moon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index d5d25ee..9a542da 100644 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -1,43 +1,56 @@ -import { useState } from 'react' +import { useState } from "react"; import { - Routes, Route, Navigate, Outlet, useLocation, useNavigate -} from 'react-router-dom' -import { useAuth } from '@/auth' -import { useSelector } from 'react-redux' -import { selectors } from '@/store' -import routes, { hasNavigation, getRouteBy, hasNoFooter, hasNoHeader } 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' + Routes, + Route, + Navigate, + Outlet, + useLocation, + useNavigate, +} 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, +} 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"; function App(): JSX.Element { - const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState(false) - const navigate = useNavigate() + const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState(false); + const navigate = useNavigate(); const closeSpecialOfferAttention = () => { - setIsSpecialOfferOpen(false) - navigate(routes.client.emailEnter()) - } + setIsSpecialOfferOpen(false); + navigate(routes.client.emailEnter()); + }; return ( @@ -45,69 +58,175 @@ function App(): JSX.Element { } /> } /> } /> - } /> - } /> + } + /> + + } + /> } /> } /> } /> } /> } /> - } /> - } /> + } + /> + } + /> } /> } /> } /> - } /> - } /> + } + /> + } + /> } /> - }> - } /> - + } + /> + }> } /> - ) + ); } interface LayoutProps { - setIsSpecialOfferOpen: React.Dispatch> + setIsSpecialOfferOpen: React.Dispatch>; } function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element { - const location = useLocation() - const showNavbar = hasNavigation(location.pathname) - const showFooter = hasNoFooter(location.pathname) - const showHeader = hasNoHeader(location.pathname) - const [isMenuOpen, setIsMenuOpen] = useState(false) - const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true) + 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 [isMenuOpen, setIsMenuOpen] = useState(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 ( -
- { showHeader ?
setIsMenuOpen(true)} clickCross={changeIsSpecialOfferOpen}/> : null } -
- { showFooter ?
: null } - { showNavbar ? setIsMenuOpen(false)} /> : null} +
+ {showHeader ? ( +
setIsMenuOpen(true)} + clickCross={changeIsSpecialOfferOpen} + /> + ) : null} +
+ +
+ {showFooter ?
: null} + {showNavbar ? ( + setIsMenuOpen(false)} /> + ) : null} + {showNavbarFooter && hasNavbarFooter(location.pathname) ? ( + + ) : null}
- ) + ); } function PrivateOutlet(): JSX.Element { - const { user } = useAuth() - return user ? : + const { user } = useAuth(); + return user ? ( + + ) : ( + + ); } function SkipStep(): JSX.Element { - const { user } = useAuth() - return user ? : + const { user } = useAuth(); + return user ? ( + + ) : ( + + ); } function MainPage(): JSX.Element { - const status = useSelector(selectors.selectStatus) - return + const status = useSelector(selectors.selectStatus); + return ; } function ProtectWallpaperPage(): JSX.Element { - const status = useSelector(selectors.selectStatus) - return status === 'subscribed' ? : + const status = useSelector(selectors.selectStatus); + return (); + return status === "subscribed" ? ( + + ) : ( + + ); } -export default App +export default App; diff --git a/src/components/BreathPage/index.tsx b/src/components/BreathPage/index.tsx index fc1319f..eb1b251 100644 --- a/src/components/BreathPage/index.tsx +++ b/src/components/BreathPage/index.tsx @@ -2,8 +2,8 @@ import styles from "./styles.module.css"; import { useCallback, useEffect, useRef, useState } from "react"; import { UserCallbacks, useApi, useApiCall } from "@/api"; import { Asset } from "@/api/resources/Assets"; -import { useDispatch } from "react-redux"; -import { actions } from "@/store"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; import { useTranslation } from "react-i18next"; import FullScreenModal from "../FullScreenModal"; import StartBreathModalChild from "../StartBreathModalChild"; @@ -24,6 +24,8 @@ function BreathPage(): JSX.Element { const api = useApi(); const dispatch = useDispatch(); const navigate = useNavigate(); + const homeConfig = useSelector(selectors.selectHome); + const showNavbarFooter = homeConfig.isShowNavbar; const assetsData = useCallback(async () => { const { assets } = await api.getAssets({ @@ -116,7 +118,7 @@ function BreathPage(): JSX.Element { return ( <> -
+
{ - const timeOut = setTimeout(() => { - setIsOpenModal(false) - }, 5000) - - return () => { - clearTimeout(timeOut) - } - }, []) - const handleNext = () => { - dispatch( - actions.siteConfig.update({ - home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true }, - }) - ); if (homeConfig.pathFromHome === EPathsFromHome.breath) { + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true }, + }) + ); return navigate(routes.client.home()); } if (homeConfig.pathFromHome === EPathsFromHome.compatibility) { @@ -87,10 +77,24 @@ function CompatResultPage(): JSX.Element { useApiCall(loadData); + const getPaddingBottomPage = () => { + if (homeConfig.pathFromHome === EPathsFromHome.compatibility && showNavbarFooter) return "246px"; + if (showNavbarFooter) return "164px"; + return "108px"; + } + return ( -
+
- + { + setIsOpenModal(false); + }} + /> {text !== "Loading..." && (
@@ -106,7 +110,7 @@ function CompatResultPage(): JSX.Element {
{text !== "Loading..." && homeConfig.pathFromHome === EPathsFromHome.compatibility && ( -
+

{t("now-you-know")}

@@ -120,7 +124,11 @@ function CompatResultPage(): JSX.Element { )} {text !== "Loading..." && homeConfig.pathFromHome === EPathsFromHome.breath && ( - )} diff --git a/src/components/Compatibility/index.tsx b/src/components/Compatibility/index.tsx index 58c1a94..f8a0565 100644 --- a/src/components/Compatibility/index.tsx +++ b/src/components/Compatibility/index.tsx @@ -9,8 +9,8 @@ import { IDate } from "@/services/date"; import { AICompatCategories, useApi, useApiCall } from "@/api"; import { useNavigate } from "react-router-dom"; import routes from "@/routes"; -import { useDispatch } from "react-redux"; -import { actions } from "@/store"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; function CompatibilityPage(): JSX.Element { const { t, i18n } = useTranslation(); @@ -22,6 +22,8 @@ function CompatibilityPage(): JSX.Element { const [name, setName] = useState(""); const [selectedDate, setSelectedDate] = useState(""); const [compatCategory, setCompatCategory] = useState(1); + const homeConfig = useSelector(selectors.selectHome); + const showNavbarFooter = homeConfig.isShowNavbar; const handleNext = () => { if (isDisabled) return; @@ -67,7 +69,7 @@ function CompatibilityPage(): JSX.Element { }; return ( -
+
{/* {t("compatibility")} diff --git a/src/components/CompatibilityLoading/index.tsx b/src/components/CompatibilityLoading/index.tsx index 45315a7..d12970a 100644 --- a/src/components/CompatibilityLoading/index.tsx +++ b/src/components/CompatibilityLoading/index.tsx @@ -1,16 +1,80 @@ +import { useEffect, useState } from "react"; import Title from "../Title"; +import ProgressBarLine from "../ui/ProgressBarLine"; import styles from "./styles.module.css"; +import Spinner from "../ui/Spinner"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; -// interface ICompatibilityLoadingProps { -// onEndLoading: () => void; -// } +interface ICompatibilityLoadingProps { + 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 ( - <section className={`${styles.container}`}> + <section className={`${styles.container}`} style={{ paddingBottom: showNavbarFooter ? '48px' : '16px'}}> <Title variant="h3" className={styles.title}> - Analysis of you with Viktor Ershov + Analysis of you with {secondPerson} + {progressBars.map((progressBar, index) => ( +
+ + {progressBar.label} + +
+ + + {getProgressValue(index, progress)}% + +
+
+ ))} +
); } diff --git a/src/components/CompatibilityLoading/styles.module.css b/src/components/CompatibilityLoading/styles.module.css index a3d1079..67a700b 100644 --- a/src/components/CompatibilityLoading/styles.module.css +++ b/src/components/CompatibilityLoading/styles.module.css @@ -1,12 +1,39 @@ .container { - padding: 16px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; + padding: 16px 32px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .title { - color: #fd3761; - font-weight: 600; + color: #fd3761; + 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); } \ No newline at end of file diff --git a/src/components/CreateProfilePage/index.tsx b/src/components/CreateProfilePage/index.tsx index 6f2c7bb..b1a2151 100644 --- a/src/components/CreateProfilePage/index.tsx +++ b/src/components/CreateProfilePage/index.tsx @@ -22,6 +22,14 @@ function CreateProfilePage(): JSX.Element { y: auraCoordinates.Y - 125 }) + useEffect(() => { + document.body.classList.add('fixed-page'); + + return () => { + document.body.classList.remove('fixed-page'); + }; + }) + useEffect(() => { setTimeout(() => { setAuraCoordinatesCounted( diff --git a/src/components/CreateProfilePage/styles.module.css b/src/components/CreateProfilePage/styles.module.css index 142c687..ace19e9 100644 --- a/src/components/CreateProfilePage/styles.module.css +++ b/src/components/CreateProfilePage/styles.module.css @@ -1,5 +1,6 @@ .page { height: calc(100vh - 50px); + max-height: -webkit-fill-available; flex: auto !important; background-color: #000; color: #fff; @@ -9,6 +10,7 @@ -ms-user-select: none; -o-user-select: none; user-select: none; + overflow: hidden; } .progressbar { diff --git a/src/components/Header/styles.module.css b/src/components/Header/styles.module.css index 09ab45f..26705e5 100644 --- a/src/components/Header/styles.module.css +++ b/src/components/Header/styles.module.css @@ -23,7 +23,16 @@ 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; top: 33%; right: 28px; diff --git a/src/components/HomePage/index.tsx b/src/components/HomePage/index.tsx index 852c504..d315eca 100644 --- a/src/components/HomePage/index.tsx +++ b/src/components/HomePage/index.tsx @@ -17,9 +17,8 @@ import { actions, selectors } from "@/store"; import { getRandomArbitrary } from "@/services/random-value"; import Title from "../Title"; import { UserDailyForecast } from "@/api/resources/UserDailyForecasts"; -import { download } from "@/services/download"; import { EPathsFromHome } from "@/store/siteConfig"; -import NavbarHome, { INavbarHomeItems } from "../NavbarHome"; +import { buildFilename, saveFile } from "../WallpaperPage/utils"; const buttonTextFormatter = (text: string): JSX.Element => { @@ -57,34 +56,6 @@ function HomePage(): JSX.Element { ); 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(); @@ -136,7 +107,7 @@ function HomePage(): JSX.Element { const downloadImg = () => { if (!asset) return; - download(asset.url.replace("http://", "https://"), asset.asset_data.metadata.filename || "image.png"); + saveFile(asset.url, buildFilename('1')); }; return ( @@ -199,7 +170,6 @@ function HomePage(): JSX.Element { ))}
- {isShowNavbar && } ); } diff --git a/src/components/NavbarHome/index.tsx b/src/components/NavbarFooter/index.tsx similarity index 51% rename from src/components/NavbarHome/index.tsx rename to src/components/NavbarFooter/index.tsx index 81070d9..52684de 100644 --- a/src/components/NavbarHome/index.tsx +++ b/src/components/NavbarFooter/index.tsx @@ -13,7 +13,7 @@ interface INavbarHomeProps { items: INavbarHomeItems[]; } -function NavbarHome({ items }: INavbarHomeProps): JSX.Element { +function NavbarFooter({ items }: INavbarHomeProps): JSX.Element { return (
{items.map((item, index) => ( @@ -28,14 +28,32 @@ function NavbarHome({ items }: INavbarHomeProps): JSX.Element { to={item.path} onClick={item.onClick} > -
- + {/* {item.title} + /> */}
-

{item.title}

+

+ {item.title} +

))} @@ -43,4 +61,4 @@ function NavbarHome({ items }: INavbarHomeProps): JSX.Element { ); } -export default NavbarHome; +export default NavbarFooter; diff --git a/src/components/NavbarHome/styles.module.css b/src/components/NavbarFooter/styles.module.css similarity index 83% rename from src/components/NavbarHome/styles.module.css rename to src/components/NavbarFooter/styles.module.css index c6463a6..5d5730a 100644 --- a/src/components/NavbarHome/styles.module.css +++ b/src/components/NavbarFooter/styles.module.css @@ -8,6 +8,7 @@ justify-content: space-evenly; position: fixed; bottom: 0; + z-index: 9999; } .navbar-item { @@ -31,9 +32,13 @@ } .navbar-item__image-container { - flex: 1; + /* flex: 1; */ display: flex; align-items: center; + width: 30px; + height: 30px; + mask-size: contain; + -webkit-mask-size: contain; } .navbar-item__image { diff --git a/src/components/UserCallbacksPage/index.tsx b/src/components/UserCallbacksPage/index.tsx index 5797228..4fa9526 100644 --- a/src/components/UserCallbacksPage/index.tsx +++ b/src/components/UserCallbacksPage/index.tsx @@ -14,14 +14,15 @@ function UserCallbacksPage(): JSX.Element { const statChanges = useSelector(selectors.selectUserCallbacksPrevStat); const text = useSelector(selectors.selectUserCallbacksDescription); const homeConfig = useSelector(selectors.selectHome); + const showNavbarFooter = homeConfig.isShowNavbar; const handleNext = () => { - dispatch( - actions.siteConfig.update({ - home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true }, - }) - ); if (homeConfig.pathFromHome === EPathsFromHome.compatibility) { + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true }, + }) + ); return navigate(routes.client.home()); } 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 ( -
+
@@ -60,12 +70,20 @@ function UserCallbacksPage(): JSX.Element { <p className={styles["result-container__text"]}>{text}</p> </div> {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")} </button> )} {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")} </button> )} diff --git a/src/components/WallpaperPage/index.tsx b/src/components/WallpaperPage/index.tsx index db94d90..ba60163 100644 --- a/src/components/WallpaperPage/index.tsx +++ b/src/components/WallpaperPage/index.tsx @@ -1,61 +1,77 @@ -import { useCallback } from 'react' -import { useTranslation } from 'react-i18next' -import { useAuth } from '@/auth' -import { useApi, useApiCall, Assets, DailyForecasts } from '@/api' -import { saveFile, buildFilename } from './utils' -import Loader, { LoaderColor } from '../Loader' -import './styles.css' +import { useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { useAuth } from "@/auth"; +import { useApi, useApiCall, Assets, DailyForecasts } from "@/api"; +import { saveFile, buildFilename } from "./utils"; +import Loader, { LoaderColor } from "../Loader"; +import "./styles.css"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import { getCategoryIdByZodiacSign, getZodiacSignByDate } from "@/services/zodiac-sign"; -type Forecasts = DailyForecasts.Forecast[] -type PersonalAssets = Assets.Asset[] +type Forecasts = DailyForecasts.Forecast[]; +type PersonalAssets = Assets.Asset[]; interface WallpaperData { - assets: PersonalAssets - forecasts: Forecasts + assets: PersonalAssets; + forecasts: Forecasts; } function WallpaperPage(): JSX.Element { - const api = useApi() - const { t } = useTranslation() - const { user, token } = useAuth() - const category = user?.profile.sign?.sign || '' - const loadData = useCallback(() => { + const api = useApi(); + const { t, i18n } = useTranslation(); + const locale = i18n.language; + const token = + "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([ - api.getAssets({ category }), + api.getAssets({ category: String(categoryId || "1"), }), api.getDailyForecasts({ token }), - ]) - .then(([{ assets }, { user_daily_forecast }]) => ({ + ]).then(([{ assets }, { user_daily_forecast }]) => ({ assets, forecasts: user_daily_forecast.forecasts, - })) - }, [api, category, token]) - const { data, isPending } = useApiCall<WallpaperData>(loadData) - const forecasts = data ? data.forecasts : [] - const asset = data ? data.assets.at(0) : null + })); + }, [api, token, locale, zodiacSign]); + const { data, isPending } = useApiCall<WallpaperData>(loadData); + const forecasts = data ? data.forecasts : []; + 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 ( - <section className='wallpaper-page'> - <div className='wallpaper-image'> + <section className="wallpaper-page"> + <div className="wallpaper-image"> {asset ? <img src={asset.url} alt={category} /> : null} - {asset ? <div className='btn-download' onClick={handleClick} /> : null} - {isPending ? <Loader color={LoaderColor.White}/> : null} + {asset ? <div className="btn-download" onClick={handleClick} /> : null} + {isPending ? <Loader color={LoaderColor.White} /> : null} </div> - <div className='wallpaper-content'> + <div className="wallpaper-content"> {isPending ? null : ( <> - <h1 className='wallpaper-title'>{t('analysis_background')}</h1> + <h1 className="wallpaper-title">{t("analysis_background")}</h1> {forecasts.map((forecast) => ( - <div key={forecast.category_name} className='wallpaper-forecast'> - <h2 className='wallpaper-subtitle'>{forecast.category}</h2> - <p className='wallpaper-text'>{forecast.body}</p> + <div key={forecast.category_name} className="wallpaper-forecast"> + <h2 className="wallpaper-subtitle">{forecast.category}</h2> + <p className="wallpaper-text">{forecast.body}</p> </div> ))} </> )} </div> </section> - ) + ); } -export default WallpaperPage +export default WallpaperPage; diff --git a/src/components/ui/ProgressBarLine/index.tsx b/src/components/ui/ProgressBarLine/index.tsx new file mode 100644 index 0000000..38e738c --- /dev/null +++ b/src/components/ui/ProgressBarLine/index.tsx @@ -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; diff --git a/src/components/ui/ProgressBarLine/styles.module.css b/src/components/ui/ProgressBarLine/styles.module.css new file mode 100644 index 0000000..0bfc06f --- /dev/null +++ b/src/components/ui/ProgressBarLine/styles.module.css @@ -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; +} \ No newline at end of file diff --git a/src/components/ui/Spinner/index.tsx b/src/components/ui/Spinner/index.tsx new file mode 100644 index 0000000..317340c --- /dev/null +++ b/src/components/ui/Spinner/index.tsx @@ -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; diff --git a/src/components/ui/Spinner/styles.module.css b/src/components/ui/Spinner/styles.module.css new file mode 100644 index 0000000..4c741d9 --- /dev/null +++ b/src/components/ui/Spinner/styles.module.css @@ -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; + } +} diff --git a/src/index.css b/src/index.css index 2b45277..cec9a22 100644 --- a/src/index.css +++ b/src/index.css @@ -128,3 +128,10 @@ a,button,div,input,select,textarea { .CircularProgressbar { position: relative; } + +.fixed-page { + position: fixed; + left: 0; + top: 0; + width: 100%; +} \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index 30e83d8..d3e6924 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -67,8 +67,7 @@ const routes = { [apiHost, prefix, "user", "callbacks.json"].join("/"), getUserCallbacks: (id: string) => [apiHost, prefix, "user", "callbacks", `${id}.json`].join("/"), - getTranslations: () => - [apiHost, "api/v2", "t.json"].join("/"), + getTranslations: () => [apiHost, "api/v2", "t.json"].join("/"), }, }; @@ -87,7 +86,10 @@ export const entrypoints = [ ]; export const isEntrypoint = (path: string) => entrypoints.includes(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) => withNavigationRoutes.includes(path); export const hasNoNavigation = (path: string) => !hasNavigation(path); @@ -115,6 +117,17 @@ export const withoutFooterRoutes = [ export const hasNoFooter = (path: string) => !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 = [ routes.client.compatibility(), routes.client.subscription(),