diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index bdaaa09..87e01eb 100644 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -27,6 +27,7 @@ import CompatibilityPage from '../Compatibility' import BreathPage from '../BreathPage' import PriceListPage from '../PriceListPage' import CompatResultPage from '../CompatResultPage' +import HomePage from '../HomePage' function App(): JSX.Element { const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState(false) @@ -54,6 +55,7 @@ function App(): JSX.Element { } /> } /> } /> + } /> }> } /> } /> diff --git a/src/components/BlurringSubstrate/index.tsx b/src/components/BlurringSubstrate/index.tsx new file mode 100644 index 0000000..67f1c8e --- /dev/null +++ b/src/components/BlurringSubstrate/index.tsx @@ -0,0 +1,19 @@ +import styles from './styles.module.css' + +interface IBlurringSubstrateProps { + className?: string + style?: React.CSSProperties + children: JSX.Element + clickHandler?: () => void +} + +function BlurringSubstrate({ className, children, style, clickHandler }: IBlurringSubstrateProps): JSX.Element { + + return ( +
+ {children} +
+ ) +} + +export default BlurringSubstrate diff --git a/src/components/BlurringSubstrate/styles.module.css b/src/components/BlurringSubstrate/styles.module.css new file mode 100644 index 0000000..9455b1a --- /dev/null +++ b/src/components/BlurringSubstrate/styles.module.css @@ -0,0 +1,7 @@ +.blurring-substrate { + backdrop-filter: blur(14px); + width: fit-content; + padding: 8px; + box-shadow: inset 0px 0px 25px rgba(0,0,0,0.5); + border-radius: 18px; +} \ No newline at end of file diff --git a/src/components/BreathPage/index.tsx b/src/components/BreathPage/index.tsx index e5e0fe5..0d78b65 100644 --- a/src/components/BreathPage/index.tsx +++ b/src/components/BreathPage/index.tsx @@ -5,16 +5,10 @@ import { useApi, useApiCall } from '@/api' import { Asset } from '@/api/resources/Assets' import { useSelector } from 'react-redux' import { selectors } from '@/store' -import { getZodiacSignByDate } from '@/services/zodiac-sign' +import { getCategoryIdByZodiacSign, getZodiacSignByDate } from '@/services/zodiac-sign' import { useTranslation } from 'react-i18next' -import { AssetCategory } from '@/api/resources/AssetCategories' import { getRandomArbitrary } from '@/services/random-value' -const getCategoryIdByZodiacSign = (zodiacSign: string, categories: AssetCategory[]) => { - const categoryId = categories.find((category) => category.slug === zodiacSign.toLowerCase())?.id - return categoryId -} - function BreathPage(): JSX.Element { const { i18n } = useTranslation() const locale = i18n.language diff --git a/src/components/CompatResultPage/index.tsx b/src/components/CompatResultPage/index.tsx index 320e6f4..a659241 100644 --- a/src/components/CompatResultPage/index.tsx +++ b/src/components/CompatResultPage/index.tsx @@ -1,68 +1,73 @@ -import { useTranslation } from 'react-i18next' -import Title from '../Title' -import styles from './styles.module.css' -import { useSelector } from 'react-redux' -import { selectors } from '@/store' -import { useCallback, useState } from 'react' -import { AICompats, AIRequests, useApi, useApiCall } from '@/api' - +import { useTranslation } from "react-i18next"; +import Title from "../Title"; +import styles from "./styles.module.css"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import { useCallback, useState } from "react"; +import { AICompats, AIRequests, useApi, useApiCall } from "@/api"; function CompatResultPage(): JSX.Element { - const token = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw' - const { t } = useTranslation() - const api = useApi() - const rightUser = useSelector(selectors.selectRightUser) - const categoryId = useSelector(selectors.selectCategoryId) - const [text, setText] = useState('Loading...') - - const loadData = useCallback(async () => { - const right_bday = typeof rightUser.birthDate === 'string' ? rightUser.birthDate : `${rightUser.birthDate.year}-${rightUser.birthDate.month}-${rightUser.birthDate.day}` - const data: AICompats.Payload = { - data: { - left_name: 'John', - left_bday: '1970-01-01', - right_name: rightUser.name, - right_bday, - category_id: categoryId - }, - token - } - const aICompat = await api.getAiCompat(data) - if (aICompat.compat.body_pending) { - const loadAIRequest = async () => { - const aIRequest = await api.getAiRequest({ - body_check_path: aICompat.compat.body_check_path, - token - }) - if (aIRequest.ai_request.state !== 'ready') { - setTimeout(loadAIRequest, 3000) - } - setText(aIRequest?.ai_request?.response?.body || 'Loading...') - return aIRequest.ai_request - } - return await loadAIRequest() - } - setText(aICompat?.compat?.body || 'Loading...') - - return aICompat.compat - }, [api, rightUser, categoryId]) - - useApiCall(loadData) + const token = + "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw"; + const { t } = useTranslation(); + const api = useApi(); + const rightUser = useSelector(selectors.selectRightUser); + const categoryId = useSelector(selectors.selectCategoryId); + const [text, setText] = useState("Loading..."); + + const loadData = useCallback(async () => { + const right_bday = + typeof rightUser.birthDate === "string" + ? rightUser.birthDate + : `${rightUser.birthDate.year}-${rightUser.birthDate.month}-${rightUser.birthDate.day}`; + const data: AICompats.Payload = { + data: { + left_name: "John", + left_bday: "1970-01-01", + right_name: rightUser.name, + right_bday, + category_id: categoryId, + }, + token, + }; + const aICompat = await api.getAiCompat(data); + if (aICompat.compat.body_pending) { + const loadAIRequest = async () => { + const aIRequest = await api.getAiRequest({ + body_check_path: aICompat.compat.body_check_path, + token, + }); + if (aIRequest.ai_request.state !== "ready") { + setTimeout(loadAIRequest, 3000); + } + setText(aIRequest?.ai_request?.response?.body || "Loading..."); + return aIRequest.ai_request; + }; + return await loadAIRequest(); + } + setText(aICompat?.compat?.body || "Loading..."); + + return aICompat.compat; + }, [api, rightUser, categoryId]); + + useApiCall(loadData); return (
-
- {'46%'} - {t('you_and', {user: rightUser.name})} -
-
- {t('sign')} -

- {text} -

-
+
+ + {"46%"} + + {t("you_and", { user: rightUser.name })} +
+
+ + {t("sign")} + +

{text}

+
- ) + ); } -export default CompatResultPage +export default CompatResultPage; diff --git a/src/components/EnergyValues/index.tsx b/src/components/EnergyValues/index.tsx new file mode 100644 index 0000000..0aed0a7 --- /dev/null +++ b/src/components/EnergyValues/index.tsx @@ -0,0 +1,34 @@ +import { UserAuraStat } from '@/api/resources/Auras' +import styles from './styles.module.css' + +interface IEnergyValues { + className?: string + values: UserAuraStat[] +} + +const colors: Record = { + "feelings": "#00f0ff", + "self_control": "#e1e767", + "energy_loss": "#ff3720", + "happiness": "#ff1eff" +} + +const valueFormatter = (value: number) => { + return `${value * 100}%` +} + +function EnergyValues({ className, values }: IEnergyValues): JSX.Element { + + return ( +
+ {values.map(({ value, label, stat }, index) => ( +
+ {valueFormatter(value)} + {label} +
+ ))} +
+ ) +} + +export default EnergyValues diff --git a/src/components/EnergyValues/styles.module.css b/src/components/EnergyValues/styles.module.css new file mode 100644 index 0000000..bba3d10 --- /dev/null +++ b/src/components/EnergyValues/styles.module.css @@ -0,0 +1,14 @@ +.energy-values { + display: flex; + flex-direction: column; + gap: 4px; + width: fit-content; +} + +.energy-value { + display: flex; + flex-direction: row; + gap: 2px; + font-size: 14px; + font-weight: 600; +} diff --git a/src/components/HomePage/index.tsx b/src/components/HomePage/index.tsx new file mode 100644 index 0000000..41a51a9 --- /dev/null +++ b/src/components/HomePage/index.tsx @@ -0,0 +1,120 @@ +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import routes from "@/routes"; +import styles from "./styles.module.css"; +import { useSelector } from "react-redux"; +import { selectors } from "@/store"; +import { + getCategoryIdByZodiacSign, + getZodiacSignByDate, +} from "@/services/zodiac-sign"; +import { useApi, useApiCall } from "@/api"; +import { Asset } from "@/api/resources/Assets"; +import { useCallback, useEffect, useState } from "react"; +import { getRandomArbitrary } from "@/services/random-value"; +import BlurringSubstrate from "../BlurringSubstrate"; +import EnergyValues from "../EnergyValues"; +import { UserAura } from "@/api/resources/Auras"; + +const buttonTextFormatter = (text: string): JSX.Element => { + const sentences = text.split("."); + return ( + <> + {sentences[0]} +
+ {sentences[1]} + + ); +}; + +function HomePage(): JSX.Element { + const token = + "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw"; + const { t } = useTranslation(); + const navigate = useNavigate(); + const handleCompatibility = () => { + navigate(routes.client.compatibility()); + }; + const handleBreath = () => { + navigate(routes.client.breath()); + }; + + const { i18n } = useTranslation(); + const locale = i18n.language; + const birthdate = useSelector(selectors.selectBirthdate); + const zodiacSign = getZodiacSignByDate(birthdate); + const [asset, setAsset] = useState(); + const api = useApi(); + + const assetsData = useCallback(async () => { + const { asset_categories } = await api.getAssetCategories({ locale }); + const categoryId = getCategoryIdByZodiacSign(zodiacSign, asset_categories); + const { assets } = await api.getAssets({ category: String("10" || "1") }); + return assets; + }, [api, locale, zodiacSign]); + + const { + data: assets, + // isPending + } = useApiCall(assetsData); + + useEffect(() => { + if (assets) { + setAsset(assets[13]); + } + }, [assets]); + + const auraData = useCallback(async () => { + const { user_aura } = await api.getAuras({ token }); + return user_aura; + }, [api, token]); + + const { + data: aura, + // isPending + } = useApiCall(auraData); + + console.log(aura); + + + return ( +
+
+ +
+
+
+ + Your energy today + +
+ {aura && } +
+
+
+
+
+ + {buttonTextFormatter(t("aura-money_compatibility-button"))} + + + {buttonTextFormatter(t("aura-10_breath-button"))} + +
+
+
+ ); +} + +export default HomePage; diff --git a/src/components/HomePage/styles.module.css b/src/components/HomePage/styles.module.css new file mode 100644 index 0000000..e2b6a44 --- /dev/null +++ b/src/components/HomePage/styles.module.css @@ -0,0 +1,78 @@ +.page { + position: relative; + height: calc(100vh - 50px); + max-height: -webkit-fill-available; + flex: auto; + justify-content: space-between; + justify-items: center; + background-color: #01010b; + background-size: calc(100% + 186px); + background-position: center; + background-repeat: no-repeat; + padding: 16px 12px; +} + +.header { + position: relative; + width: 100%; +} + +.header__energies { + max-width: 180px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.header__energies-header { + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; +} + +.header__energies-title { + font-size: 14px; + color: #bbb9b8; + font-weight: 500; + width: 82px; +} + +.header__energies-aura { + position: relative; + width: 50px; + height: 50px; + background-size: 170%; + background-image: url("/goosebumps-aura.png"); + background-repeat: no-repeat; + background-position: center center; + animation: pulse 1s alternate infinite; +} + +.content__buttons { + display: flex; + flex-direction: column; + gap: 6px; + width: 300px; +} + +.content__buttons-item { + width: 100% !important; + border: solid #7b7570 2px; + border-radius: 25px !important; + text-align: center; + color: #fff; + cursor: pointer; +} + +@keyframes pulse { + 0% { + transform: scale(0.9); + } + 50% { + opacity: 1; + } + 100% { + transform: scale(1.1); + } +} diff --git a/src/locales/dev.ts b/src/locales/dev.ts index aa555fe..114f9a9 100644 --- a/src/locales/dev.ts +++ b/src/locales/dev.ts @@ -78,5 +78,7 @@ export default { people_joined_today: " people joined today", you_and: "You and ", sign: "Sign", + 'aura-10_breath-button': "Increase up to 10%. Practice for the Energy of Money", + 'aura-money_compatibility-button': "low MONEY energy. Determine who drains your energy" }, } diff --git a/src/routes.ts b/src/routes.ts index cf73899..97dddbc 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -24,6 +24,7 @@ const routes = { compatibilityResult: () => [host, 'compatibility', 'result'].join('/'), breath: () => [host, 'breath'].join('/'), priceList: () => [host, 'price-list'].join('/'), + home: () => [host, 'home'].join('/'), }, server: { user: () => [apiHost, prefix, 'user.json'].join('/'), @@ -43,6 +44,8 @@ const routes = { subscriptionReceipt: (id: string) => [apiHost, prefix, 'user', 'subscription_receipts', `${id}.json`].join('/'), compatCategories: () => [apiHost, prefix, 'ai', 'compat_categories.json'].join('/'), compat: () => [apiHost, prefix, 'ai', 'compats.json'].join('/'), + createUserCallbacks: () => [apiHost, prefix, 'user', 'callbacks.json'].join('/'), + getUserCallbacks: (id: string) => [apiHost, prefix, 'user', 'callbacks', `${id}.json`].join('/'), }, } @@ -56,6 +59,7 @@ export const entrypoints = [ routes.client.feedback(), routes.client.breath(), routes.client.compatibilityResult(), + routes.client.home(), ] export const isEntrypoint = (path: string) => entrypoints.includes(path) export const isNotEntrypoint = (path: string) => !isEntrypoint(path) @@ -76,6 +80,7 @@ export const withoutFooterRoutes = [ routes.client.breath(), routes.client.priceList(), routes.client.compatibilityResult(), + routes.client.home(), ] export const hasNoFooter = (path: string) => !withoutFooterRoutes.includes(path) diff --git a/src/services/zodiac-sign/index.ts b/src/services/zodiac-sign/index.ts index dcf818d..9a5505e 100644 --- a/src/services/zodiac-sign/index.ts +++ b/src/services/zodiac-sign/index.ts @@ -1,10 +1,34 @@ - +import { AssetCategory } from "@/api/resources/AssetCategories"; export const getZodiacSignByDate = (birthDate: string): string => { - const date = new Date(birthDate) - const day = date.getDate() - const month = date.getMonth() + 1 - const zodiac =['Capricorn', 'Aquarius', 'Pisces', 'Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo', 'Libra', 'Scorpio', 'Sagittarius', 'Capricorn'] - const last_day =[19, 18, 20, 19, 20, 20, 22, 22, 22, 22, 21, 21] - return (day > last_day[month - 1]) ? zodiac[month*1] : zodiac[month - 1] -} + const date = new Date(birthDate); + const day = date.getDate(); + const month = date.getMonth() + 1; + const zodiac = [ + "Capricorn", + "Aquarius", + "Pisces", + "Aries", + "Taurus", + "Gemini", + "Cancer", + "Leo", + "Virgo", + "Libra", + "Scorpio", + "Sagittarius", + "Capricorn", + ]; + const last_day = [19, 18, 20, 19, 20, 20, 22, 22, 22, 22, 21, 21]; + return day > last_day[month - 1] ? zodiac[month * 1] : zodiac[month - 1]; +}; + +export const getCategoryIdByZodiacSign = ( + zodiacSign: string, + categories: AssetCategory[] +) => { + const categoryId = categories.find( + (category) => category.slug === zodiacSign.toLowerCase() + )?.id; + return categoryId; +};