diff --git a/src/components/BreathPage/index.tsx b/src/components/BreathPage/index.tsx index 6e28ca9..73ded5f 100644 --- a/src/components/BreathPage/index.tsx +++ b/src/components/BreathPage/index.tsx @@ -16,6 +16,7 @@ function BreathPage(): JSX.Element { const { t } = useTranslation(); const [asset, setAsset] = useState(); const [isOpenModal, setIsOpenModal] = useState(true); + const [isShowPreview, setIsShowPreview] = useState(true); const api = useApi(); const dispatch = useDispatch(); const navigate = useNavigate(); @@ -27,26 +28,33 @@ function BreathPage(): JSX.Element { return assets; }, [api]); - const { - data, - } = useApiCall(assetsData); + const { data } = useApiCall(assetsData); useEffect(() => { if (isOpenModal) return; + const previewTimeOut = setTimeout(() => { + setIsShowPreview(false); + }, 10_000); - const timeOut = setTimeout(() => { + const navigateTimeOut = setTimeout(() => { navigate(routes.client.breathResult()); - }, 50_000); + }, 60_000); return () => { - clearTimeout(timeOut); + clearTimeout(navigateTimeOut); + clearTimeout(previewTimeOut); }; }, [navigate, isOpenModal]); useEffect(() => { - if (data) { + if (!data) return; + const leoTimeOut = setTimeout(() => { setAsset(data[getRandomArbitrary(0, data?.length || 0)]); - } + }, 10_000); + + return () => { + clearTimeout(leoTimeOut); + }; }, [data, isOpenModal]); const beginBreath = () => { @@ -95,13 +103,26 @@ function BreathPage(): JSX.Element {
+ {!isOpenModal && isShowPreview && ( +
+ leo + + {t("aura.breath_relax.text")} + +
+ )} - {!isOpenModal && ( + {!isOpenModal && !isShowPreview && (
{ + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true }, + }) + ); + if (homeConfig.pathFromHome === EPathsFromHome.breath) { + return navigate(routes.client.home()); + } + if (homeConfig.pathFromHome === EPathsFromHome.compatibility) { + return navigate(routes.client.breath()); + } + }; + const loadData = useCallback(async () => { const right_bday = typeof rightUser.birthDate === "string" @@ -55,6 +75,7 @@ function CompatResultPage(): JSX.Element { return ( <section className={`${styles.page} page`}> + {text !== "Loading..." && <div className={styles.cross} onClick={handleNext}></div>} <div className={styles["title-container"]}> <Title variant="h2">{t("you_and", { user: rightUser.name })}
@@ -64,6 +85,19 @@ function CompatResultPage(): JSX.Element {

{text}

+ {text !== "Loading..." && ( +
+

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

+ +
+ )}
); } diff --git a/src/components/CompatResultPage/styles.module.css b/src/components/CompatResultPage/styles.module.css index 6ace156..ba5dc55 100644 --- a/src/components/CompatResultPage/styles.module.css +++ b/src/components/CompatResultPage/styles.module.css @@ -2,30 +2,100 @@ position: relative; height: calc(100vh - 50px); flex: auto; - max-height: -webkit-fill-available; + /* max-height: -webkit-fill-available; */ background-color: #000; color: #fff; overflow-y: scroll; + padding-bottom: 180px; } .title-container { - color: #e9445a; + color: #e9445a; } .percent { - margin-bottom: 0; + margin-bottom: 0; } .result-container { - width: 100%; + width: 100%; } .result-container__title { - width: 100%; - text-align: left; + width: 100%; + text-align: left; } .result-container__text { - white-space:pre-wrap; - line-height: 1.2; -} \ No newline at end of file + white-space: pre-wrap; + line-height: 1.2; +} + +.button-container { + position: fixed; + width: 100%; + max-width: 560px; + bottom: 0; + border-radius: 16px 16px 0 0; + background-color: rgba(128, 128, 128, 0.546); + -webkit-backdrop-filter: blur(14px); + backdrop-filter: blur(14px); + display: flex; + align-items: center; + flex-direction: column; + gap: 16px; + padding: 16px 0 24px 0; +} + +.button-container__text { + max-width: calc(100% - 64px); + text-align: center; + color: #7ce4fc; +} + +.button-container__button { + border: none; + bottom: 24px; + width: calc(100% - 64px); + max-width: 496px; + border-radius: 32px; + padding: 24px 0; + background: -moz-linear-gradient(to bottom, #2dc8e2, #2b7ed6); + background: -webkit-linear-gradient(to bottom, #2dc8e2, #2b7ed6); + background: linear-gradient(to bottom, #2dc8e2, #2b7ed6); + color: #fff; +} + +.cross { + position: absolute; + top: 24px; + right: 24px; + width: 24px; + height: 24px; + border: solid 2px #bdbdbd; + border-radius: 100%; + rotate: 45deg; + cursor: pointer; +} + +.cross::before { + content: ""; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 2px; + background-color: #bdbdbd; +} + +.cross::after { + content: ""; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 2px; + height: 10px; + background-color: #bdbdbd; +} diff --git a/src/components/Compatibility/index.tsx b/src/components/Compatibility/index.tsx index 81534db..880a814 100644 --- a/src/components/Compatibility/index.tsx +++ b/src/components/Compatibility/index.tsx @@ -22,6 +22,7 @@ function CompatibilityPage(): JSX.Element { const [name, setName] = useState(''); const [date, setDate] = useState(''); const [compatCategory, setCompatCategory] = useState(1); + const handleNext = () => { dispatch(actions.compatibility.update({ rightUser: { diff --git a/src/components/HomePage/index.tsx b/src/components/HomePage/index.tsx index b96feea..695e1c2 100644 --- a/src/components/HomePage/index.tsx +++ b/src/components/HomePage/index.tsx @@ -8,13 +8,19 @@ import { useCallback, useEffect, useState } from "react"; import BlurringSubstrate from "../BlurringSubstrate"; import EnergyValues from "../EnergyValues"; import { UserAura } from "@/api/resources/Auras"; -import { useSelector } from "react-redux"; -import { getCategoryIdByZodiacSign, getZodiacSignByDate } from "@/services/zodiac-sign"; -import { selectors } from "@/store"; +import { useDispatch, useSelector } from "react-redux"; +import { + getCategoryIdByZodiacSign, + getZodiacSignByDate, +} from "@/services/zodiac-sign"; +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"; + const buttonTextFormatter = (text: string): JSX.Element => { const sentences = text.split("."); @@ -32,12 +38,54 @@ function HomePage(): JSX.Element { "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw"; const { t } = useTranslation(); const navigate = useNavigate(); + const dispatch = useDispatch(); + const homeConfig = useSelector(selectors.selectHome); + const isShowNavbar = homeConfig.isShowNavbar; const handleCompatibility = () => { + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: EPathsFromHome.compatibility, isShowNavbar }, + }) + ); navigate(routes.client.compatibility()); }; const handleBreath = () => { + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: EPathsFromHome.breath, isShowNavbar }, + }) + ); navigate(routes.client.breath()); }; + + const navbarHomeItems: INavbarHomeItems[] = [ + { + title: 'Breathing', + path: routes.client.breath(), + image: '', + onClick: handleBreath + }, + { + title: 'Aura', + path: routes.client.home(), + image: '', + active: true, + onClick: () => null + }, + { + title: 'Compatibility', + path: routes.client.compatibility(), + image: '', + onClick: handleCompatibility + }, + { + title: 'My Moon', + path: routes.client.home(), + image: '', + onClick: () => null + } + ] + const { i18n } = useTranslation(); const locale = i18n.language; @@ -49,9 +97,11 @@ function HomePage(): JSX.Element { const assetsData = useCallback(async () => { const { asset_categories } = await api.getAssetCategories({ locale }); const categoryId = getCategoryIdByZodiacSign(zodiacSign, asset_categories); - const { assets } = await api.getAssets({ category: String(categoryId || "1") }); + const { assets } = await api.getAssets({ + category: String(categoryId || "1"), + }); return assets; - }, [api]); + }, [api, locale, zodiacSign]); const { data: assets, @@ -77,7 +127,7 @@ function HomePage(): JSX.Element { const dailyForecastData = useCallback(async () => { const { user_daily_forecast } = await api.getDailyForecasts({ token }); return user_daily_forecast; - }, [api, token]) + }, [api, token]); const { data: dailyForecast, @@ -85,14 +135,16 @@ function HomePage(): JSX.Element { } = useApiCall(dailyForecastData); const downloadImg = () => { - if( !asset ) return; - download(asset.url, 'image.png'); - } + if (!asset) return; + download(asset.url, "image.png"); + }; return (
@@ -128,18 +180,26 @@ function HomePage(): JSX.Element {
- {dailyForecast && dailyForecast.forecasts.map((forecast, index) => ( -
- - {forecast.category} - -

- {forecast.body} -

-
- ))} + {dailyForecast && + dailyForecast.forecasts.map((forecast, index) => ( +
+ + {forecast.category} + +

+ {forecast.body} +

+
+ ))}
+ {isShowNavbar && }
); } diff --git a/src/components/HomePage/styles.module.css b/src/components/HomePage/styles.module.css index acff6e7..6cf3c5a 100644 --- a/src/components/HomePage/styles.module.css +++ b/src/components/HomePage/styles.module.css @@ -97,6 +97,7 @@ border-radius: 25px !important; text-align: center; color: #fff; + background-color: #00000094; cursor: pointer; } diff --git a/src/components/NavbarHome/index.tsx b/src/components/NavbarHome/index.tsx new file mode 100644 index 0000000..2858018 --- /dev/null +++ b/src/components/NavbarHome/index.tsx @@ -0,0 +1,33 @@ +import { Link } from 'react-router-dom' +import styles from './styles.module.css' + +export interface INavbarHomeItems { + title: string + path: string + image: string + active?: boolean + onClick?: () => void +} + +interface INavbarHomeProps { + items: INavbarHomeItems[] +} + +function NavbarHome({items}: INavbarHomeProps): JSX.Element { + + + return ( +
+ {items.map((item, index) => ( +
+ + {/* {item.title} */} +

{item.title}

+ +
+ ))} +
+ ) +} + +export default NavbarHome diff --git a/src/components/NavbarHome/styles.module.css b/src/components/NavbarHome/styles.module.css new file mode 100644 index 0000000..b296e5e --- /dev/null +++ b/src/components/NavbarHome/styles.module.css @@ -0,0 +1,23 @@ +.container { + width: 100vw; + max-width: 560px; + background-color: #232322; + padding: 12px 0; + display: flex; + flex-direction: row; + justify-content: space-evenly; + position: fixed; + bottom: 0; +} + +.navbar-item { + font-size: 12px; + display: flex; + flex-direction: column; + justify-content: center; + color: #dedede; +} + +.navbar-item--active { + color: #f24058; +} \ No newline at end of file diff --git a/src/components/PriceListPage/index.tsx b/src/components/PriceListPage/index.tsx index 992998e..8ddf05b 100644 --- a/src/components/PriceListPage/index.tsx +++ b/src/components/PriceListPage/index.tsx @@ -2,8 +2,8 @@ import { useNavigate } from 'react-router-dom' import routes from '@/routes' import styles from './styles.module.css' import UserHeader from '../UserHeader' -import { useSelector } from 'react-redux' -import { selectors } from '@/store' +import { useDispatch, useSelector } from 'react-redux' +import { actions, selectors } from '@/store' import Title from '../Title' import { useTranslation } from 'react-i18next' import EmailsList from '../EmailsList' @@ -12,10 +12,17 @@ import PriceList from '../PriceList' function PriceListPage(): JSX.Element { const { t } = useTranslation() const navigate = useNavigate() + const dispatch = useDispatch(); + const homeConfig = useSelector(selectors.selectHome); const selectedPrice = useSelector(selectors.selectSelectedPrice) const email = useSelector(selectors.selectEmail) const handleNext = () => { + dispatch( + actions.siteConfig.update({ + home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: false }, + }) + ); navigate(routes.client.subscription()) } diff --git a/src/components/UserCallbacksPage/index.tsx b/src/components/UserCallbacksPage/index.tsx index 1266dc3..4e65898 100644 --- a/src/components/UserCallbacksPage/index.tsx +++ b/src/components/UserCallbacksPage/index.tsx @@ -1,15 +1,33 @@ import Title from "../Title"; import styles from "./styles.module.css"; -import { useSelector } from "react-redux"; -import { selectors } from "@/store"; +import { useDispatch, useSelector } from "react-redux"; +import { actions, selectors } from "@/store"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; +import routes from "@/routes"; +import { EPathsFromHome } from "@/store/siteConfig"; function UserCallbacksPage(): JSX.Element { + const { t } = useTranslation(); + const navigate = useNavigate(); + const dispatch = useDispatch(); const statChanges = useSelector(selectors.selectUserCallbacksPrevStat); const text = useSelector(selectors.selectUserCallbacksDescription); + const homeConfig = useSelector(selectors.selectHome); + const handleNext = () => { + dispatch(actions.siteConfig.update({ home: { pathFromHome: homeConfig.pathFromHome, isShowNavbar: true } })); + if (homeConfig.pathFromHome === EPathsFromHome.compatibility) { + return navigate(routes.client.home()); + } + if (homeConfig.pathFromHome === EPathsFromHome.breath) { + return navigate(routes.client.compatibility()); + } + }; return (
+
<> @@ -37,6 +55,9 @@ function UserCallbacksPage(): JSX.Element { </div> <p className={styles["result-container__text"]}>{text}</p> </div> + <button className={styles.button} onClick={handleNext}> + {t("use-all-power")} + </button> </section> ); } diff --git a/src/components/UserCallbacksPage/styles.module.css b/src/components/UserCallbacksPage/styles.module.css index 9fc87c2..b2a7856 100644 --- a/src/components/UserCallbacksPage/styles.module.css +++ b/src/components/UserCallbacksPage/styles.module.css @@ -1,12 +1,13 @@ .page { position: relative; height: calc(100vh - 50px); - max-height: -webkit-fill-available; + /* max-height: -webkit-fill-available; */ flex: auto; background-color: #000; color: #bababb; overflow-y: scroll; text-align: center; + padding-bottom: 114px; } .result-container__values { @@ -35,3 +36,51 @@ line-height: 1.2; margin-top: 32px; } + +.button { + position: fixed; + border: none; + bottom: 24px; + width: calc(100% - 64px); + max-width: 496px; + border-radius: 32px; + padding: 24px 0; + background: -moz-linear-gradient(to bottom, #01d400, #196e17); + background: -webkit-linear-gradient(to bottom, #01d400, #196e17); + background: linear-gradient(to bottom, #01d400, #196e17); + color: #fff; +} + +.cross { + position: absolute; + top: 24px; + right: 24px; + width: 24px; + height: 24px; + border: solid 2px #bdbdbd; + border-radius: 100%; + rotate: 45deg; + cursor: pointer; +} + +.cross::before { + content: ""; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 2px; + background-color: #bdbdbd; +} + +.cross::after { + content: ""; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 2px; + height: 10px; + background-color: #bdbdbd; +} \ No newline at end of file diff --git a/src/locales/dev.ts b/src/locales/dev.ts index ca36785..292392b 100644 --- a/src/locales/dev.ts +++ b/src/locales/dev.ts @@ -85,5 +85,9 @@ export default { "breathe-subtitle": "Breathing practice will help improve your aura. Breath in the positive energy, breathe out the negative...", "breathe-title": "Stop and breathe to help you relax and focus on what really matters.", "aura-begin_breathe-button": "BEGIN", + "aura.breath_relax.text": "Breath & Relax", + "use-all-power": "Use all the power of your Aura", + "go-through": "Go through practicing recovery", + "now-you-know": "Now you know who`s causing your financial energy loss.", }, } diff --git a/src/services/url/index.ts b/src/services/url/index.ts new file mode 100644 index 0000000..b3739fa --- /dev/null +++ b/src/services/url/index.ts @@ -0,0 +1,5 @@ +export const getQueryParam = (paramName: string) => { + const search = window.location.search; + const params = new URLSearchParams(search); + return params.get(paramName); +}; diff --git a/src/store/index.ts b/src/store/index.ts index 9985028..7ca2fcf 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -3,6 +3,7 @@ import token, { actions as tokenActions, selectToken } from './token' import user, { actions as userActions, selectUser } from './user' import form, { actions as formActions, selectors as formSelectors } from './form' import aura, { actions as auraActions } from './aura' +import siteConfig, { selectHome, actions as siteConfigActions } from './siteConfig' import payment, { actions as paymentActions } from './payment' import subscriptionPlans, { actions as subscriptionPlasActions, selectPlanById } from './subscriptionPlan' import status, { actions as userStatusActions, selectStatus } from './status' @@ -15,8 +16,9 @@ import { selectRightUser, selectCategoryId } from './compatibility' import { selectUserCallbacksDescription, selectUserCallbacksPrevStat } from './userCallbacks' + const preloadedState = loadStore() -export const reducer = combineReducers({ token, user, form, status, subscriptionPlans, aura, payment, compatibility, userCallbacks }) +export const reducer = combineReducers({ token, user, form, status, subscriptionPlans, aura, payment, compatibility, userCallbacks, siteConfig }) export const actions = { token: tokenActions, user: userActions, @@ -24,6 +26,7 @@ export const actions = { status: userStatusActions, subscriptionPlan: subscriptionPlasActions, aura: auraActions, + siteConfig: siteConfigActions, compatibility: compatibilityActions, payment: paymentActions, userCallbacks: userCallbacksActions, @@ -40,6 +43,7 @@ export const selectors = { selectSelectedPrice, selectUserCallbacksDescription, selectUserCallbacksPrevStat, + selectHome, ...formSelectors, } export type RootState = ReturnType<typeof reducer> diff --git a/src/store/siteConfig.ts b/src/store/siteConfig.ts new file mode 100644 index 0000000..e5edeef --- /dev/null +++ b/src/store/siteConfig.ts @@ -0,0 +1,39 @@ +import { createSlice, createSelector } from "@reduxjs/toolkit"; +import type { PayloadAction } from "@reduxjs/toolkit"; + +export enum EPathsFromHome { + compatibility, + breath +} + +interface ISiteConfig { + home: { + isShowNavbar: boolean; + pathFromHome: EPathsFromHome; + }; +} + +const initialState: ISiteConfig = { + home: { + isShowNavbar: false, + pathFromHome: EPathsFromHome.compatibility + }, +}; + +const siteConfigSlice = createSlice({ + name: "siteConfig", + initialState, + reducers: { + update(state, action: PayloadAction<Partial<ISiteConfig>>) { + return { ...state, ...action.payload }; + }, + }, + extraReducers: (builder) => builder.addCase("reset", () => initialState), +}); + +export const { actions } = siteConfigSlice; +export const selectHome = createSelector( + (state: { siteConfig: ISiteConfig }) => state.siteConfig.home, + (siteConfig) => siteConfig +); +export default siteConfigSlice.reducer;