diff --git a/src/components/BreathCircle/index.tsx b/src/components/BreathCircle/index.tsx
index 0461cd5..02bde89 100644
--- a/src/components/BreathCircle/index.tsx
+++ b/src/components/BreathCircle/index.tsx
@@ -11,6 +11,7 @@ function BreathCircle(): JSX.Element {
const navigate = useNavigate()
const [text, setText] = useState(t(''))
const [render, setRender] = useState(false)
+ const [counter, setCounter] = useState(0)
useEffect(() => {
@@ -29,10 +30,13 @@ function BreathCircle(): JSX.Element {
return sleep(4000)
})
.then(() => {
- handleNext()
+ setCounter((prevState) => prevState + 1)
+ if (counter === 3) {
+ handleNext()
+ }
setRender((prevState) => !prevState)
})
- }, [t, render, navigate])
+ }, [t, render, navigate, counter])
return (
diff --git a/src/components/BreathCircle/styles.module.css b/src/components/BreathCircle/styles.module.css
index 57e49ab..dd493ba 100644
--- a/src/components/BreathCircle/styles.module.css
+++ b/src/components/BreathCircle/styles.module.css
@@ -10,8 +10,8 @@
.inner-circle {
position: relative;
- width: 200px;
- height: 200px;
+ width: 240px;
+ height: 240px;
background-color: #69a8e7;
border-radius: 100%;
display: flex;
diff --git a/src/components/Compatibility/index.tsx b/src/components/Compatibility/index.tsx
index 135efe0..add1a12 100644
--- a/src/components/Compatibility/index.tsx
+++ b/src/components/Compatibility/index.tsx
@@ -10,7 +10,9 @@ import { AICompatCategories, useApi, useApiCall } from "@/api";
function CompatibilityPage(): JSX.Element {
const { t, i18n } = useTranslation();
- const [isDisabled, setIsDisabled] = useState(false);
+ const [isDisabled, setIsDisabled] = useState(true);
+ const [isDisabledName, setIsDisabledName] = useState(true);
+ const [isDisabledDate, setIsDisabledDate] = useState(true);
const [name, setName] = useState
('');
const [date, setDate] = useState('');
const [compatCategory, setCompatCategory] = useState(2);
@@ -25,13 +27,19 @@ function CompatibilityPage(): JSX.Element {
const { data } = useApiCall(loadData)
const handleValidName = (name: string) => {
- setIsDisabled(name === '');
+ setIsDisabledName(!name.length);
setName(name)
+ checkAllDisabled()
}
const handleValidDate = (date: IDate | string) => {
- setIsDisabled(date === '');
+ setIsDisabledDate(date === '');
setDate(date)
+ checkAllDisabled()
+ }
+
+ const checkAllDisabled = () => {
+ setIsDisabled(isDisabledName || isDisabledDate);
}
const changeCompatCategory = (event: React.ChangeEvent) => {
@@ -58,7 +66,7 @@ function CompatibilityPage(): JSX.Element {
value={name}
placeholder={t('name')}
onValid={handleValidName}
- onInvalid={() => setIsDisabled(true)}
+ onInvalid={() => setIsDisabledName(true)}
/>
@@ -67,7 +75,7 @@ function CompatibilityPage(): JSX.Element {
value={getDateAsString(date)}
inputClassName={styles['date-input']}
onValid={handleValidDate}
- onInvalid={() => setIsDisabled(true)}
+ onInvalid={() => setIsDisabledDate(true)}
/>
diff --git a/src/components/EmailsList/index.tsx b/src/components/EmailsList/index.tsx
index 6cb100d..29604d4 100644
--- a/src/components/EmailsList/index.tsx
+++ b/src/components/EmailsList/index.tsx
@@ -4,25 +4,45 @@ import styles from './styles.module.css'
import { useTranslation } from 'react-i18next'
import { useEffect, useRef, useState } from 'react'
-const emails: IEmailItem[] = []
+// const getEmails = (): IEmailItem[] => {
+// const emails: IEmailItem[] = []
+
+// for (let i = 0; i < 2; i++) {
+// const subList = []
+// for (let j = 0; j < 4; j++) {
+// subList.push({
+// email: getRandomName(),
+// price: 9
+// })
+// }
+// subList[getRandomArbitrary(0, 4)].price = [5, 13.67][getRandomArbitrary(0, 2)]
+// emails.push(...subList)
+// }
-for (let i = 0; i < 25; i++) {
- const sublist = []
- for (let j = 0; j < 4; j++) {
- sublist.push({
+// return emails
+// }
+
+const getEmails = (): IEmailItem[] => {
+ const emails: IEmailItem[] = []
+
+ for (let index = 0; index < 5; index++) {
+ emails.push({
email: getRandomName(),
- price: 9
+ price: [9, 9, 9, 9, 9, 5, 13.67][getRandomArbitrary(0, 7)]
})
+
}
- sublist[getRandomArbitrary(0, 4)].price = [5, 13.67][getRandomArbitrary(0, 2)]
- emails.push(...sublist)
+
+ return emails
}
+
function EmailsList(): JSX.Element {
const { t } = useTranslation()
const [countUsers, setCountUsers] = useState(752)
+ const [emails, setEmails] = useState(getEmails())
+ const [elementIdx, setElementIdx] = useState(0)
const itemsRef = useRef([]);
- let elementIdx = 0
useEffect(() => {
const randomDelay = getRandomArbitrary(3000, 5000)
@@ -30,28 +50,39 @@ function EmailsList(): JSX.Element {
setCountUsers((prevState) => prevState + 1)
}, randomDelay)
return () => clearTimeout(countUsersTimeOut)
- }, [countUsers, elementIdx])
+ }, [countUsers])
useEffect(() => {
+ const randomDelay = getRandomArbitrary(500, 5000)
+
const itemsRefInterval = setInterval(() => {
-
+ if (itemsRef.current[elementIdx - 1]) {
+ itemsRef.current[elementIdx - 1].remove()
+ }
if (itemsRef.current[elementIdx]?.style) {
- itemsRef.current[elementIdx].className = styles.hidden
+ itemsRef.current[elementIdx].classList.add(styles.hidden)
}
- elementIdx++
- }, 3000)
- return () => clearTimeout(itemsRefInterval)
- }, [elementIdx])
-
+ setEmails((prevState) => {
+ const array = prevState.slice(0)
+ array.push({
+ email: getRandomName(),
+ price: [9, 9, 9, 9, 9, 5, 13.67][getRandomArbitrary(0, 7)]
+ })
+ return array
+ })
+ setElementIdx((prevState) => prevState + 1)
+ }, randomDelay)
+ return () => clearInterval(itemsRefInterval)
+ }, [emails, elementIdx])
return (
{t('people_joined_today', { countPeoples: {countUsers} })}
{emails.map(({email, price}, idx) => (
-
itemsRef.current[idx] = el} key={idx}>
-
-
+
itemsRef.current[idx] = el} key={idx}>
+
+
))}
diff --git a/src/components/EmailsList/styles.module.css b/src/components/EmailsList/styles.module.css
index 8d2d43b..caa1086 100644
--- a/src/components/EmailsList/styles.module.css
+++ b/src/components/EmailsList/styles.module.css
@@ -13,22 +13,28 @@
font-size: 14px;
font-weight: 500;
color: #494747;
+ text-align: center;
}
.emails-container {
width: 100%;
- flex-grow: 3;
+ height: 108px;
padding: 8px 0;
display: flex;
- flex-direction: column;
+ flex-direction: column-reverse;
align-items: center;
overflow: hidden;
gap: 10px;
}
-.hidden {
- transition: all 1s ease;
- margin-top: -26px;
- opacity: 0;
- will-change: margin-top, opacity;
+.email-item {
+ margin-top: 0;
+ opacity: 1;
+ will-change: margin-top, opacity;
+}
+
+.hidden {
+ transition: all .5s ease;
+ margin-bottom: -26px;
+ opacity: 0;
}
diff --git a/src/components/FreePeriodInfoPage/index.tsx b/src/components/FreePeriodInfoPage/index.tsx
index 959506d..c186bf1 100644
--- a/src/components/FreePeriodInfoPage/index.tsx
+++ b/src/components/FreePeriodInfoPage/index.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import Title from '../Title'
import routes from '@/routes'
import styles from './styles.module.css'
-import { useCallback } from 'react'
+import { MouseEventHandler, TouchEventHandler, useCallback } from 'react'
import { useDispatch } from 'react-redux'
import { actions } from '@/store'
@@ -19,15 +19,27 @@ function FreePeriodInfoPage(): JSX.Element {
}
}))
}, [dispatch])
- const handleNext = (e: any) => {
- const X = e.clientX || Math.round(e.touches[0].clientX)
- const Y = e.clientY || Math.round(e.touches[0].clientY)
- updateCoordinates(X, Y)
+
+ const handleNext = () => {
navigate(routes.client.createProfile())
}
+ const mouseDown: MouseEventHandler = (e) => {
+ const X = e.clientX
+ const Y = e.clientY
+ updateCoordinates(X, Y)
+ handleNext()
+ }
+
+ const touchStart: TouchEventHandler = (e) => {
+ const X = e.touches[0].clientX
+ const Y = e.touches[0].clientY
+ updateCoordinates(X, Y)
+ handleNext()
+ }
+
return (
-
+
{t('touch_screen')}
diff --git a/src/components/PriceItem/index.tsx b/src/components/PriceItem/index.tsx
index 95adcb1..9279bb9 100644
--- a/src/components/PriceItem/index.tsx
+++ b/src/components/PriceItem/index.tsx
@@ -22,15 +22,21 @@ const removeAfterDot = (value: string): string => {
}
interface PriceItemProps {
- click: () => void
+ active: boolean
+ click: () => void
}
-function PriceItem({ id, value, click }: IPrice & PriceItemProps): JSX.Element {
- console.log(id);
+function PriceItem({ id, value, active, click }: IPrice & PriceItemProps): JSX.Element {
const _price = new Price(roundToWhole(value), currency, locale)
+ const compatClassName = () => {
+ const isPopular = id === 3
+ const isActive = active
+ return `${styles.container} ${isPopular ? styles.popular : ''} ${isActive ? styles.active : ''}`
+ }
+
return (
-
+
{removeAfterDot(_price.format())}
)
diff --git a/src/components/PriceItem/styles.module.css b/src/components/PriceItem/styles.module.css
index 6e67676..b432182 100644
--- a/src/components/PriceItem/styles.module.css
+++ b/src/components/PriceItem/styles.module.css
@@ -11,6 +11,12 @@
font-weight: 600;
}
+.active {
+ background-color: #30bf52;
+ border-color: #30bf52;
+ color: #fff;
+}
+
.popular {
border-color: #30bf52;
}
diff --git a/src/components/PriceList/index.tsx b/src/components/PriceList/index.tsx
index cd17d65..4e450e1 100644
--- a/src/components/PriceList/index.tsx
+++ b/src/components/PriceList/index.tsx
@@ -26,16 +26,16 @@ const prices: IPrice[] = [
]
interface PriceListProps {
- click: () => void
+ activeItem: number | null
+ click: () => void
}
-function PriceList({click}: PriceListProps): JSX.Element {
-
+function PriceList({click, activeItem}: PriceListProps): JSX.Element {
return (
{prices.map((price, idx) => (
-
+
))}
)
diff --git a/src/components/PriceListPage/index.tsx b/src/components/PriceListPage/index.tsx
index a964ec6..3b58358 100644
--- a/src/components/PriceListPage/index.tsx
+++ b/src/components/PriceListPage/index.tsx
@@ -12,11 +12,12 @@ import PriceList from '../PriceList'
function PriceListPage(): JSX.Element {
const { t } = useTranslation()
const navigate = useNavigate()
+ const selectedPrice = useSelector(selectors.selectSelectedPrice)
+
const email = useSelector(selectors.selectEmail)
const handleNext = () => {
navigate(routes.client.breath())
}
-
return (
<>
@@ -28,7 +29,7 @@ function PriceListPage(): JSX.Element {
>
diff --git a/src/components/PriceListPage/styles.module.css b/src/components/PriceListPage/styles.module.css
index c92e3e5..d5713bd 100644
--- a/src/components/PriceListPage/styles.module.css
+++ b/src/components/PriceListPage/styles.module.css
@@ -21,7 +21,7 @@
.emails-list-container {
width: 40%;
min-width: 200px;
- height: 130px;
+ /* height: 136px; */
margin-top: 48px;
}
diff --git a/src/components/SpecialWelcomeOffer/index.tsx b/src/components/SpecialWelcomeOffer/index.tsx
index 4b42420..e699a74 100644
--- a/src/components/SpecialWelcomeOffer/index.tsx
+++ b/src/components/SpecialWelcomeOffer/index.tsx
@@ -5,6 +5,9 @@ import routes from '@/routes'
import styles from './styles.module.css'
import ModalTop from '../ModalTop'
import Header from '../Header'
+import { useCallback } from 'react'
+import { useDispatch } from 'react-redux'
+import { actions } from '@/store'
interface ModalTopProps {
open: boolean
@@ -14,7 +17,14 @@ interface ModalTopProps {
function SpecialWelcomeOffer({ open, onClose }: ModalTopProps): JSX.Element {
const { t } = useTranslation()
const navigate = useNavigate()
+ const dispatch = useDispatch()
+ const updateSelectedPrice = useCallback((selectedPrice: number | null) => {
+ dispatch(actions.payment.update({
+ selectedPrice
+ }))
+ }, [dispatch])
const handleNext = () => {
+ updateSelectedPrice(1)
navigate(routes.client.emailEnter())
}
diff --git a/src/store/index.ts b/src/store/index.ts
index 5bbb6a3..caa7b88 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -3,13 +3,15 @@ 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 payment, { actions as paymentActions } from './payment'
import subscriptionPlans, { actions as subscriptionPlasActions, selectPlanById } from './subscriptionPlan'
import status, { actions as userStatusActions, selectStatus } from './status'
import { loadStore, backupStore } from './storageHelper'
import { selectAuraCoordinates } from './aura'
+import { selectSelectedPrice } from './payment'
const preloadedState = loadStore()
-export const reducer = combineReducers({ token, user, form, status, subscriptionPlans, aura })
+export const reducer = combineReducers({ token, user, form, status, subscriptionPlans, aura, payment })
export const actions = {
token: tokenActions,
user: userActions,
@@ -17,6 +19,7 @@ export const actions = {
status: userStatusActions,
subscriptionPlan: subscriptionPlasActions,
aura: auraActions,
+ payment: paymentActions,
reset: createAction('reset'),
}
export const selectors = {
@@ -25,6 +28,7 @@ export const selectors = {
selectStatus,
selectPlanById,
selectAuraCoordinates,
+ selectSelectedPrice,
...formSelectors,
}
export type RootState = ReturnType
diff --git a/src/store/payment.ts b/src/store/payment.ts
new file mode 100644
index 0000000..8cf8135
--- /dev/null
+++ b/src/store/payment.ts
@@ -0,0 +1,28 @@
+import { createSlice, createSelector } from '@reduxjs/toolkit'
+import type { PayloadAction } from '@reduxjs/toolkit'
+
+interface IPayment {
+ selectedPrice: number | null
+}
+
+const initialState: IPayment = {
+ selectedPrice: null
+}
+
+const paymentSlice = createSlice({
+ name: 'payment',
+ initialState,
+ reducers: {
+ update(state, action: PayloadAction>) {
+ return { ...state, ...action.payload }
+ },
+ },
+ extraReducers: (builder) => builder.addCase('reset', () => initialState),
+})
+
+export const { actions } = paymentSlice
+export const selectSelectedPrice = createSelector(
+ (state: { payment: IPayment }) => state.payment.selectedPrice,
+ (payment) => payment
+)
+export default paymentSlice.reducer