feat: add special welcome offer page
This commit is contained in:
parent
9ce9a90031
commit
1832036710
@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import {
|
import {
|
||||||
Routes, Route, Navigate, Outlet, useLocation
|
Routes, Route, Navigate, Outlet, useLocation, useNavigate
|
||||||
} from 'react-router-dom'
|
} from 'react-router-dom'
|
||||||
import { useAuth } from '../../auth'
|
import { useAuth } from '../../auth'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
@ -25,14 +25,22 @@ import AttentionPage from '../AttentionPage'
|
|||||||
import FeedbackPage from '../FeedbackPage'
|
import FeedbackPage from '../FeedbackPage'
|
||||||
|
|
||||||
function App(): JSX.Element {
|
function App(): JSX.Element {
|
||||||
|
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const closeSpecialOffer = () => {
|
||||||
|
setIsSpecialOfferOpen(false)
|
||||||
|
navigate(routes.client.emailEnter())
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<Layout />}>
|
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
|
||||||
<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 path={routes.client.freePeriodInfo()} element={<FreePeriodInfoPage />} />
|
||||||
<Route path={routes.client.attention()} element={<AttentionPage />} />
|
<Route path={routes.client.attention()} element={<AttentionPage isOpenModal={isSpecialOfferOpen} onCloseSpecialOffer={closeSpecialOffer} />} />
|
||||||
<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 />} />
|
||||||
@ -49,14 +57,19 @@ function App(): JSX.Element {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Layout(): JSX.Element {
|
interface LayoutProps {
|
||||||
|
setIsSpecialOfferOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const showNavbar = hasNavigation(location.pathname)
|
const showNavbar = hasNavigation(location.pathname)
|
||||||
const showFooter = hasNoFooter(location.pathname)
|
const showFooter = hasNoFooter(location.pathname)
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false)
|
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false)
|
||||||
|
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true)
|
||||||
return (
|
return (
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
<Header openMenu={() => setIsMenuOpen(true)}/>
|
<Header openMenu={() => setIsMenuOpen(true)} clickCross={changeIsSpecialOfferOpen}/>
|
||||||
<main className='content'><Outlet /></main>
|
<main className='content'><Outlet /></main>
|
||||||
{ showFooter ? <Footer color={showNavbar ? 'black' : 'white'}/> : null }
|
{ showFooter ? <Footer color={showNavbar ? 'black' : 'white'}/> : null }
|
||||||
{ showNavbar ? <Navbar isOpen={isMenuOpen} closeMenu={() => setIsMenuOpen(false)} /> : null}
|
{ showNavbar ? <Navbar isOpen={isMenuOpen} closeMenu={() => setIsMenuOpen(false)} /> : null}
|
||||||
|
|||||||
@ -4,8 +4,14 @@ import Title from '../Title'
|
|||||||
import routes from '../../routes'
|
import routes from '../../routes'
|
||||||
import styles from './styles.module.css'
|
import styles from './styles.module.css'
|
||||||
import CheckboxWithText from '../CheckboxWithText'
|
import CheckboxWithText from '../CheckboxWithText'
|
||||||
|
import SpecialWelcomeOffer from '../SpecialWelcomeOffer'
|
||||||
|
|
||||||
function AttentionPage(): JSX.Element {
|
interface AttentionPageProps {
|
||||||
|
isOpenModal: boolean
|
||||||
|
onCloseSpecialOffer?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function AttentionPage({ isOpenModal, onCloseSpecialOffer }: AttentionPageProps): JSX.Element {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const handleNext = () => navigate(routes.client.feedback())
|
const handleNext = () => navigate(routes.client.feedback())
|
||||||
@ -18,6 +24,7 @@ function AttentionPage(): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section className={`${styles.page} page`}>
|
||||||
|
<SpecialWelcomeOffer open={isOpenModal} onClose={onCloseSpecialOffer} />
|
||||||
<img className={styles.icon} src="/stop-icon.png" alt="stop" />
|
<img className={styles.icon} src="/stop-icon.png" alt="stop" />
|
||||||
<Title variant='h2'>{t('attention')}</Title>
|
<Title variant='h2'>{t('attention')}</Title>
|
||||||
<p className={styles.text}>{t('attention_page_text')}</p>
|
<p className={styles.text}>{t('attention_page_text')}</p>
|
||||||
|
|||||||
@ -7,17 +7,24 @@ import styles from './styles.module.css'
|
|||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { selectors } from '../../store'
|
import { selectors } from '../../store'
|
||||||
import { getZodiacSignByDate } from '../../zodiac-sign'
|
import { getZodiacSignByDate } from '../../zodiac-sign'
|
||||||
|
import SpecialWelcomeOffer from '../SpecialWelcomeOffer'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
function DidYouKnowPage(): JSX.Element {
|
function DidYouKnowPage(): JSX.Element {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const handleNext = () => navigate(routes.client.freePeriodInfo())
|
const handleNext = () => navigate(routes.client.freePeriodInfo())
|
||||||
|
const [isOpenModal, setIsOpenModal] = useState(false)
|
||||||
|
const handleSpecialOffer = () => {
|
||||||
|
setIsOpenModal(true)
|
||||||
|
}
|
||||||
const birthdate = useSelector(selectors.selectBirthdate)
|
const birthdate = useSelector(selectors.selectBirthdate)
|
||||||
const zodiacSign = getZodiacSignByDate(birthdate)
|
const zodiacSign = getZodiacSignByDate(birthdate)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`${styles.page} page`}>
|
<section className={`${styles.page} page`}>
|
||||||
|
<SpecialWelcomeOffer open={isOpenModal} />
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Title variant='h1'>{t('did_you_know')}</Title>
|
<Title variant='h1'>{t('did_you_know')}</Title>
|
||||||
<p className={styles.zodiacInfo}>
|
<p className={styles.zodiacInfo}>
|
||||||
@ -28,7 +35,7 @@ function DidYouKnowPage(): JSX.Element {
|
|||||||
<MainButton onClick={handleNext}>
|
<MainButton onClick={handleNext}>
|
||||||
{t('learn_about_my_energy')}
|
{t('learn_about_my_energy')}
|
||||||
</MainButton>
|
</MainButton>
|
||||||
<span className={styles.skip}>{t('skip_for_now')}</span>
|
<span className={styles.skip} onClick={handleSpecialOffer}>{t('skip_for_now')}</span>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useNavigate, useLocation } from 'react-router-dom'
|
import { useNavigate, useLocation } from 'react-router-dom'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import routes, { hasNavigation, isNotEntrypoint } from '../../routes'
|
import routes, { hasCrossButton, hasNavigation, isNotEntrypoint } from '../../routes'
|
||||||
import BackButton from './BackButton'
|
import BackButton from './BackButton'
|
||||||
import iconUrl from './icon.png'
|
import iconUrl from './icon.png'
|
||||||
import menuUrl from './menu.png'
|
import menuUrl from './menu.png'
|
||||||
import './styles.css'
|
import styles from './styles.module.css'
|
||||||
|
|
||||||
type HeaderProps = {
|
type HeaderProps = {
|
||||||
openMenu: () => void
|
openMenu?: () => void
|
||||||
|
showBack?: boolean
|
||||||
|
showCross?: boolean
|
||||||
|
clickCross?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function Header({ openMenu }: HeaderProps): JSX.Element {
|
function Header({ openMenu, showBack, showCross, clickCross = () => {undefined}, ...props }: HeaderProps & React.HTMLAttributes<HTMLDivElement>): JSX.Element {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@ -19,6 +22,7 @@ function Header({ openMenu }: HeaderProps): JSX.Element {
|
|||||||
const [isNavigated, setIsNavigated] = useState<boolean>(false);
|
const [isNavigated, setIsNavigated] = useState<boolean>(false);
|
||||||
const showBackButton = isNotEntrypoint(location.pathname)
|
const showBackButton = isNotEntrypoint(location.pathname)
|
||||||
const showMenuButton = hasNavigation(location.pathname)
|
const showMenuButton = hasNavigation(location.pathname)
|
||||||
|
const showCrossButton = hasCrossButton(location.pathname)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!initialPath) {
|
if (!initialPath) {
|
||||||
@ -38,11 +42,12 @@ function Header({ openMenu }: HeaderProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="header">
|
<header className={styles.header} {...props}>
|
||||||
{ showBackButton ? <BackButton className="pa" onClick={goBack} /> : null }
|
{ (showBackButton || showBack) ? <BackButton className='pa' onClick={goBack} /> : null }
|
||||||
<img src={iconUrl} alt="logo" width="40" height="40" />
|
<img src={iconUrl} alt="logo" width="40" height="40" />
|
||||||
<span className="header__title">{t('app_name')}</span>
|
<span className={styles["header__title"]}>{t('app_name')}</span>
|
||||||
{showMenuButton ? <div className="header__menu-btn" onClick={openMenu}>
|
{(showCrossButton || showCross) ? <img className={styles.cross} src="/cross.png" alt="Cross" onClick={clickCross} /> : null}
|
||||||
|
{showMenuButton ? <div className={styles["header__menu-btn"]} onClick={openMenu}>
|
||||||
<img src={menuUrl} alt="menu" width="40" height="40" />
|
<img src={menuUrl} alt="menu" width="40" height="40" />
|
||||||
</div> : null}
|
</div> : null}
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -23,11 +23,16 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__menu-btn {
|
.header__menu-btn, .cross {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 33%;
|
||||||
right: 28px;
|
right: 28px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cross {
|
||||||
|
height: 33%;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
26
src/components/ModalTop/index.tsx
Normal file
26
src/components/ModalTop/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { ReactNode } from 'react'
|
||||||
|
import styles from './styles.module.css'
|
||||||
|
import Header from '../Header'
|
||||||
|
|
||||||
|
interface ModalProps {
|
||||||
|
children: ReactNode
|
||||||
|
open?: boolean
|
||||||
|
onClose?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function ModalTop({ open, children, onClose }: ModalProps): JSX.Element {
|
||||||
|
const handleClose = (event: React.MouseEvent) => {
|
||||||
|
if (event.target !== event.currentTarget) return
|
||||||
|
onClose?.()
|
||||||
|
}
|
||||||
|
if (!open) return <></>
|
||||||
|
return (
|
||||||
|
<div className={styles.modal} onClick={handleClose}>
|
||||||
|
<div className={styles['modal-content']}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalTop
|
||||||
44
src/components/ModalTop/styles.module.css
Normal file
44
src/components/ModalTop/styles.module.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.modal {
|
||||||
|
background: rgb(14 14 14 / 80%);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 100vw;
|
||||||
|
z-index: 2000;
|
||||||
|
animation: appearanceBackground .6s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 0 0 16px 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
animation: appearance 0.6s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes appearance {
|
||||||
|
0% {
|
||||||
|
margin-top: -100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes appearanceBackground {
|
||||||
|
0% {
|
||||||
|
background: transparent;
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
background: rgb(14 14 14 / 80%);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/components/SpecialWelcomeOffer/index.tsx
Normal file
42
src/components/SpecialWelcomeOffer/index.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Title from '../Title'
|
||||||
|
import routes from '../../routes'
|
||||||
|
import styles from './styles.module.css'
|
||||||
|
import ModalTop from '../ModalTop'
|
||||||
|
import Header from '../Header'
|
||||||
|
|
||||||
|
interface ModalTopProps {
|
||||||
|
open: boolean
|
||||||
|
onClose?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function SpecialWelcomeOffer({ open, onClose }: ModalTopProps): JSX.Element {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const handleNext = () => {
|
||||||
|
navigate(routes.client.emailEnter())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{open ? (
|
||||||
|
<ModalTop open={open} onClose={onClose || handleNext}>
|
||||||
|
<Header showBack={true} showCross={true} clickCross={onClose || handleNext} />
|
||||||
|
<div className={styles.content}>
|
||||||
|
<span className={styles['welcome-offer']}>{t('special_welcome_offer')}</span>
|
||||||
|
<Title variant='h1'>{t('get_100_off')}</Title>
|
||||||
|
<div className={styles['discount-container']}>
|
||||||
|
<span className={styles['red-price']}>$9.99</span>
|
||||||
|
<span className={styles['price']}>$0.00</span>
|
||||||
|
</div>
|
||||||
|
<button className={styles.button} onClick={onClose || handleNext}>{t('get_discount')}</button>
|
||||||
|
</div>
|
||||||
|
</ModalTop>
|
||||||
|
): null}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SpecialWelcomeOffer
|
||||||
40
src/components/SpecialWelcomeOffer/styles.module.css
Normal file
40
src/components/SpecialWelcomeOffer/styles.module.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 24px 64px 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-offer {
|
||||||
|
color: #717171;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discount-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 16px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-price {
|
||||||
|
color: red;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background-color: #78d180;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 26px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border: none;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
@ -62,5 +62,8 @@ export default {
|
|||||||
attention_page_text: "There are significant deviations in your energy, this is a fairly rare occurrence and few people have encountered something like this. Therefore, we cannot provide you with a full report as you may not be prepared for this.",
|
attention_page_text: "There are significant deviations in your energy, this is a fairly rare occurrence and few people have encountered something like this. Therefore, we cannot provide you with a full report as you may not be prepared for this.",
|
||||||
not_ready_for_information: "I understand that I may not be ready for this information.",
|
not_ready_for_information: "I understand that I may not be ready for this information.",
|
||||||
feedback: "I couldn`t believe me eyes when I saw what was revealed about my energy; it was truly shocking. Everything that was mentioned really happened in my life, and I understood the reasons and especially who was behind it. Everything was very beneficial and spot on, without any excess or unnecessary details. Thanks for the assistance; this analysis greatly helped me in my life. I recommend it to everyone. Special thanks to Aura!",
|
feedback: "I couldn`t believe me eyes when I saw what was revealed about my energy; it was truly shocking. Everything that was mentioned really happened in my life, and I understood the reasons and especially who was behind it. Everything was very beneficial and spot on, without any excess or unnecessary details. Thanks for the assistance; this analysis greatly helped me in my life. I recommend it to everyone. Special thanks to Aura!",
|
||||||
|
get_100_off: "Get 100% off - Today only",
|
||||||
|
special_welcome_offer: "Special welcome offer!",
|
||||||
|
get_discount: "Get discount",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,9 @@ export const withNavigationRoutes = [routes.client.wallpaper()]
|
|||||||
export const hasNavigation = (path: string) => withNavigationRoutes.includes(path)
|
export const hasNavigation = (path: string) => withNavigationRoutes.includes(path)
|
||||||
export const hasNoNavigation = (path: string) => !hasNavigation(path)
|
export const hasNoNavigation = (path: string) => !hasNavigation(path)
|
||||||
|
|
||||||
|
export const withCrossButtonRoutes = [routes.client.attention()]
|
||||||
|
export const hasCrossButton = (path: string) => withCrossButtonRoutes.includes(path)
|
||||||
|
|
||||||
export const withoutFooterRoutes = [
|
export const withoutFooterRoutes = [
|
||||||
routes.client.didYouKnow(),
|
routes.client.didYouKnow(),
|
||||||
routes.client.freePeriodInfo(),
|
routes.client.freePeriodInfo(),
|
||||||
|
|||||||
@ -2,18 +2,21 @@ import { combineReducers, configureStore, createAction } from '@reduxjs/toolkit'
|
|||||||
import token, { actions as tokenActions, selectToken } from './token'
|
import token, { actions as tokenActions, selectToken } from './token'
|
||||||
import user, { actions as userActions, selectUser } from './user'
|
import user, { actions as userActions, selectUser } from './user'
|
||||||
import form, { actions as formActions, selectors as formSelectors } from './form'
|
import form, { actions as formActions, selectors as formSelectors } from './form'
|
||||||
|
import aura, { actions as auraActions } from './aura'
|
||||||
import subscriptionPlans, { actions as subscriptionPlasActions, selectPlanById } from './subscriptionPlan'
|
import subscriptionPlans, { actions as subscriptionPlasActions, selectPlanById } from './subscriptionPlan'
|
||||||
import status, { actions as userStatusActions, selectStatus } from './status'
|
import status, { actions as userStatusActions, selectStatus } from './status'
|
||||||
import { loadStore, backupStore } from './storageHelper'
|
import { loadStore, backupStore } from './storageHelper'
|
||||||
|
import { selectAuraCoordinates } from './aura'
|
||||||
|
|
||||||
const preloadedState = loadStore()
|
const preloadedState = loadStore()
|
||||||
export const reducer = combineReducers({ token, user, form, status, subscriptionPlans })
|
export const reducer = combineReducers({ token, user, form, status, subscriptionPlans, aura })
|
||||||
export const actions = {
|
export const actions = {
|
||||||
token: tokenActions,
|
token: tokenActions,
|
||||||
user: userActions,
|
user: userActions,
|
||||||
form: formActions,
|
form: formActions,
|
||||||
status: userStatusActions,
|
status: userStatusActions,
|
||||||
subscriptionPlan: subscriptionPlasActions,
|
subscriptionPlan: subscriptionPlasActions,
|
||||||
|
aura: auraActions,
|
||||||
reset: createAction('reset'),
|
reset: createAction('reset'),
|
||||||
}
|
}
|
||||||
export const selectors = {
|
export const selectors = {
|
||||||
@ -21,6 +24,7 @@ export const selectors = {
|
|||||||
selectUser,
|
selectUser,
|
||||||
selectStatus,
|
selectStatus,
|
||||||
selectPlanById,
|
selectPlanById,
|
||||||
|
selectAuraCoordinates,
|
||||||
...formSelectors,
|
...formSelectors,
|
||||||
}
|
}
|
||||||
export type RootState = ReturnType<typeof reducer>
|
export type RootState = ReturnType<typeof reducer>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user