feat: infinity months date picker, texts from translate v2, prices from chosen

This commit is contained in:
gofnnp 2023-09-23 02:50:29 +04:00
parent 87eba58d0e
commit 64bdc08452
21 changed files with 140 additions and 45 deletions

View File

@ -34,7 +34,7 @@ function App(): JSX.Element {
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false)
const navigate = useNavigate()
const closeSpecialOffer = () => {
const closeSpecialOfferAttention = () => {
setIsSpecialOfferOpen(false)
navigate(routes.client.emailEnter())
}
@ -46,7 +46,7 @@ function App(): JSX.Element {
<Route path={routes.client.birthday()} element={<BirthdayPage />} />
<Route path={routes.client.didYouKnow()} element={<DidYouKnowPage />} />
<Route path={routes.client.freePeriodInfo()} element={<FreePeriodInfoPage />} />
<Route path={routes.client.attention()} element={<AttentionPage isOpenModal={isSpecialOfferOpen} onCloseSpecialOffer={closeSpecialOffer} />} />
<Route path={routes.client.attention()} element={<AttentionPage isOpenModal={isSpecialOfferOpen} onCloseSpecialOffer={closeSpecialOfferAttention} />} />
<Route path={routes.client.feedback()} element={<FeedbackPage />} />
<Route path={routes.client.birthtime()} element={<BirthtimePage />} />
<Route path={routes.client.createProfile()} element={<SkipStep />} />

View File

@ -3,11 +3,13 @@ import Title from "../Title";
import styles from "./styles.module.css";
import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { useCallback, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { AICompats, AIRequests, useApi, useApiCall } from "@/api";
import { useNavigate } from "react-router-dom";
import routes from "@/routes";
import { EPathsFromHome } from "@/store/siteConfig";
import FullScreenModal from "../FullScreenModal";
import CompatibilityLoading from "../CompatibilityLoading";
function CompatResultPage(): JSX.Element {
const token =
@ -21,6 +23,18 @@ function CompatResultPage(): JSX.Element {
const categoryId = useSelector(selectors.selectCategoryId);
const homeConfig = useSelector(selectors.selectHome);
const [text, setText] = useState("Loading...");
const [isOpenModal, setIsOpenModal] = useState(true);
useEffect(() => {
const timeOut = setTimeout(() => {
setIsOpenModal(false)
}, 5000)
return () => {
clearTimeout(timeOut)
}
}, [])
const handleNext = () => {
dispatch(
@ -75,6 +89,9 @@ function CompatResultPage(): JSX.Element {
return (
<section className={`${styles.page} page`}>
<FullScreenModal isOpen={isOpenModal}>
<CompatibilityLoading />
</FullScreenModal>
{text !== "Loading..." && (
<div className={styles.cross} onClick={handleNext}></div>
)}
@ -103,7 +120,7 @@ function CompatResultPage(): JSX.Element {
)}
{text !== "Loading..." &&
homeConfig.pathFromHome === EPathsFromHome.breath && (
<button className={styles['button-green']} onClick={handleNext}>
<button className={styles["button-green"]} onClick={handleNext}>
{t("use-all-power")}
</button>
)}

View File

@ -79,7 +79,8 @@
color: #a09b9b;
}
.date-picker-item.selected {
color: white;
font-weight: 600;
color: #fff;
}
/* Header and confirm button */

View File

@ -19,7 +19,7 @@ const DatePicker: React.FC<DatePickerProps> = ({
);
const days = Array.from({ length: 31 }, (_, index) => (index + 1).toString());
const months = Array.from({ length: 12 }, (_, index) =>
const months = Array.from({ length: 36 }, (_, index) =>
new Date(0, index).toLocaleDateString(undefined, { month: "long" })
);
const years = Array.from({ length: 81 }, (_, index) =>
@ -27,19 +27,19 @@ const DatePicker: React.FC<DatePickerProps> = ({
);
const handleDaySelect = (day: string) => {
const newDate = new Date(getDateAsString(selectedDate));
const newDate = new Date(getDateAsString(selectedDate).replace(/-/g, "/"));
newDate.setDate(parseInt(day));
setSelectedDate(getDateAsString(newDate));
};
const handleMonthSelect = (month: string) => {
const newDate = new Date(getDateAsString(selectedDate));
const newDate = new Date(getDateAsString(selectedDate).replace(/-/g, "/"));
newDate.setMonth(months.indexOf(month));
setSelectedDate(getDateAsString(newDate));
};
const handleYearSelect = (year: string) => {
const newDate = new Date(getDateAsString(selectedDate));
const newDate = new Date(getDateAsString(selectedDate).replace(/-/g, "/"));
newDate.setFullYear(parseInt(year));
setSelectedDate(getDateAsString(newDate));
};

View File

@ -24,17 +24,14 @@ const DatePickerItem: React.FC<DatePickerItemProps> = ({
data,
selectedValue,
onSelect,
unit
unit,
}) => {
console.log(selectedValue);
console.log(data);
const isMobile = useIsMobile();
const scrollRef = useRef<HTMLDivElement | null>(null);
const [touchY, setTouchY] = useState<number>(0);
const [translateY, setTranslateY] = useState<number>(
data.indexOf(selectedValue) * -ITEM_HEIGHT
(data.indexOf(selectedValue) + (unit === "month" ? 12 : 0)) * -ITEM_HEIGHT
);
const handleTouchStart = (event: React.TouchEvent<HTMLDivElement>) => {
@ -45,10 +42,26 @@ const DatePickerItem: React.FC<DatePickerItemProps> = ({
if (isMobile && touchY !== null) {
const deltaY = event.touches[0].clientY - touchY;
wheelScroll(deltaY);
setTouchY(event.touches[0].clientY);
}
};
useEffect(() => {
setTranslateY((data.indexOf(selectedValue) + (unit === "month" ? 12 : 0)) * -ITEM_HEIGHT)
}, [selectedValue, data, unit])
useEffect(() => {
if (unit === "month") {
if (
data.indexOf(selectedValue) < 12 ||
data.indexOf(selectedValue) > 23
) {
setTranslateY((data.indexOf(selectedValue) + 12) * -ITEM_HEIGHT);
}
}
}, [unit, data, selectedValue]);
const handleTouchEnd = () => {
if (isMobile && scrollRef.current) {
const selectedIndex = Math.round(-translateY / ITEM_HEIGHT);

View File

@ -53,7 +53,7 @@ function CompatibilityPage(): JSX.Element {
};
const handleValidDate = (date: string | IDate) => {
setIsDisabledDate(date === '');
setIsDisabledDate(date === "");
setSelectedDate(date);
checkAllDisabled();
};

View File

@ -127,7 +127,7 @@
.compatibility-categories {
display: flex;
flex-direction: column;
gap: 32px;
gap: 16px;
margin-top: 72px;
}

View File

@ -0,0 +1,18 @@
import Title from "../Title";
import styles from "./styles.module.css";
// interface ICompatibilityLoadingProps {
// onEndLoading: () => void;
// }
function CompatibilityLoading(): JSX.Element {
return (
<section className={`${styles.container}`}>
<Title variant="h3" className={styles.title}>
Analysis of you with Viktor Ershov
</Title>
</section>
);
}
export default CompatibilityLoading;

View File

@ -0,0 +1,12 @@
.container {
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.title {
color: #fd3761;
font-weight: 600;
}

View File

@ -7,24 +7,24 @@ import styles from './styles.module.css'
import { useSelector } from 'react-redux'
import { selectors } from '@/store'
import { getZodiacSignByDate } from '@/services/zodiac-sign'
import SpecialWelcomeOffer from '../SpecialWelcomeOffer'
import { useState } from 'react'
// import SpecialWelcomeOffer from '../SpecialWelcomeOffer'
// import { useState } from 'react'
function DidYouKnowPage(): JSX.Element {
const { t } = useTranslation()
const navigate = useNavigate()
const handleNext = () => navigate(routes.client.freePeriodInfo())
const [isOpenModal, setIsOpenModal] = useState(false)
const handleSpecialOffer = () => {
setIsOpenModal(true)
}
// const [isOpenModal, setIsOpenModal] = useState(false)
// const handleSpecialOffer = () => {
// setIsOpenModal(true)
// }
const birthdate = useSelector(selectors.selectBirthdate)
const zodiacSign = getZodiacSignByDate(birthdate)
return (
<section className={`${styles.page} page`}>
<SpecialWelcomeOffer open={isOpenModal} />
{/* <SpecialWelcomeOffer open={isOpenModal} /> */}
<div className={styles.content}>
<Title variant='h1'>{t('did_you_know')}</Title>
<p className={styles.zodiacInfo}>
@ -35,7 +35,7 @@ function DidYouKnowPage(): JSX.Element {
<MainButton onClick={handleNext}>
{t('learn_about_my_energy')}
</MainButton>
<span className={styles.skip} onClick={handleSpecialOffer}>{t('skip_for_now')}</span>
<span className={styles.skip} onClick={handleNext}>{t('skip_for_now')}</span>
</footer>
</section>
)

View File

@ -61,7 +61,7 @@ function EmailEnterPage(): JSX.Element {
return (
<section className='page'>
<Title variant='h2' className='mt-24'>{t('we_will_email_you')}</Title>
<Title variant='h2' className='mt-24'>{t('aura.web.email_title')}</Title>
<EmailInput
name="email"
value={email}
@ -69,16 +69,16 @@ function EmailEnterPage(): JSX.Element {
onValid={handleValidEmail}
onInvalid={() => setIsDisabled(true)}
/>
<p>{t('we_dont_share')}</p>
<p style={{ marginBottom: '8px' }}>{t('we_dont_share')}</p>
<MainButton onClick={handleClick} disabled={isDisabled}>
{isLoading ? <Loader color={LoaderColor.White} /> : t('_continue')}
</MainButton>
<Policy sizing='medium'>
{t('_continue_agree', {
eulaLink: <a href='https://aura.wit.life/terms' target='_blank' rel='noopener noreferrer'>{t('eula')}</a>,
privacyLink: <a href='https://aura.wit.life/privacy' target='_blank' rel='noopener noreferrer'>{t('privacy_policy')}</a>,
})}
</Policy>
<MainButton onClick={handleClick} disabled={isDisabled}>
{isLoading ? <Loader color={LoaderColor.White} /> : t('_continue')}
</MainButton>
<ErrorText size='medium' isShown={Boolean(error)} message={error ? extractErrorMessage(error) : null} />
</section>
)

View File

@ -162,7 +162,7 @@ function HomePage(): JSX.Element {
{/* <a href={asset?.url.replace('http://', 'https://')} download></a> */}
</div>
</div>
<div className={styles.content}>
<div className={styles.content} style={{ marginTop: isShowNavbar ? "calc(100vh - 570px)" : "calc(100vh - 500px)"}}>
<div className={styles["content__buttons"]}>
<BlurringSubstrate
style={{ color: "#fa71ea" }}

View File

@ -28,7 +28,7 @@ function PaymentTable({ currency, locale, items }: PaymentTableProps): JSX.Eleme
</div>
<div className='payment__item-description'>
<p>{item.description}</p>
<p>One dollar thirty six cents per day</p>
{/* <p>One dollar thirty six cents per day</p> */}
</div>
</div>
)
@ -44,7 +44,7 @@ function PaymentTable({ currency, locale, items }: PaymentTableProps): JSX.Eleme
{items.map(toItem)}
</div>
</div>
<div className='payment__information'>{t('charged_only')}</div>
<div className='payment__information'>{t('charged_only', {price: totalPrice.format()})}</div>
</div>
)
}

View File

@ -3,7 +3,7 @@
flex-direction: column;
max-width: 400px;
width: 100%;
margin-top: 20px;
margin-top: 8px;
margin-bottom: 6px;
text-align: center;
}

View File

@ -23,7 +23,7 @@ const removeAfterDot = (value: string): string => {
interface PriceItemProps {
active: boolean;
click: () => void;
click: (id: number) => void;
}
function PriceItem({
@ -38,12 +38,16 @@ function PriceItem({
const compatClassName = () => {
const isPopular = id === 3;
// const isActive = active;
return `${styles.container} ${isPopular ? styles.popular : ""}`;
const isActive = active;
return `${styles.container} ${isPopular ? styles.popular : ""} ${isActive ? styles.active : ""}`;
};
const itemClick = () => {
click(id);
}
return (
<div onClick={click} className={compatClassName()}>
<div onClick={itemClick} className={compatClassName()}>
{removeAfterDot(_price.format())}
</div>
);

View File

@ -10,11 +10,12 @@
border: solid #d6d2d2 2px;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s, color 0.3s;
}
.active {
background-color: #30bf52;
border-color: #30bf52;
background-color: #d6d2d2;
border-color: #d6d2d2 !important;
color: #fff;
}

View File

@ -1,5 +1,8 @@
import { useState } from 'react'
import PriceItem from '../PriceItem'
import styles from './styles.module.css'
import { useDispatch } from 'react-redux'
import { actions } from '@/store'
export interface IPrice {
id: number
@ -31,11 +34,29 @@ interface PriceListProps {
}
function PriceList({click, activeItem}: PriceListProps): JSX.Element {
const dispatch = useDispatch();
const [activePriceItem, setActivePriceItem] = useState<number | null>(activeItem)
const priceItemClick = (id: number) => {
console.log(id);
setActivePriceItem(id)
const activePriceItem = prices.find((item) => item.id === Number(id))
if (activePriceItem) {
dispatch(
actions.payment.update({
selectedPrice: activePriceItem.value
})
);
}
setTimeout(() => {
click()
}, 1000)
}
return (
<div className={`${styles.container}`}>
{prices.map((price, idx) => (
<PriceItem active={price.id === activeItem} key={idx} value={price.value} id={price.id} click={click} />
<PriceItem active={price.id === activePriceItem} key={idx} value={price.value} id={price.id} click={priceItemClick} />
))}
</div>
)

View File

@ -31,7 +31,7 @@ function PriceListPage(): JSX.Element {
<UserHeader email={email} />
<section className={`${styles.page} page`}>
<Title className={styles.title} variant='h2'>{t('choose_your_own_fee')}</Title>
<p className={styles.slogan}>{t('should_not_get', { strongText: <strong>{t('money')}</strong> })}</p>
<p className={styles.slogan}>{t('should_not_get', { strongText: <strong>{t('aura.web.price_selection')}</strong> })}</p>
<div className={styles['emails-list-container']}>
<EmailsList />
</div>

View File

@ -11,6 +11,8 @@ import CallToAction from "../CallToAction";
import routes from "@/routes";
import styles from "./styles.module.css";
import Header from "../Header";
import SpecialWelcomeOffer from "../SpecialWelcomeOffer";
import { useState } from "react";
const currency = Currency.USD;
const locale = Locale.EN;
@ -24,12 +26,17 @@ const paymentItems = [
];
function SubscriptionPage(): JSX.Element {
const [isOpenModal, setIsOpenModal] = useState(false);
const { t } = useTranslation();
const navigate = useNavigate();
const email = useSelector(selectors.selectEmail);
const itemPrice = useSelector(selectors.selectPlanById(itemPriceId));
const selectedPrice = useSelector(selectors.selectSelectedPrice);
if (selectedPrice || selectedPrice === 0) {
paymentItems[0].price = selectedPrice;
}
const handleClick = () => navigate(routes.client.paymentMethod());
const handleCross = () => navigate(routes.client.home());
const handleCross = () => setIsOpenModal(true);
const policyLink = (
<a href="https://aura.wit.life/" target="_blank" rel="noopener noreferrer">
{t("subscription_policy")}
@ -38,6 +45,7 @@ function SubscriptionPage(): JSX.Element {
console.log({ itemPrice });
return (
<>
<SpecialWelcomeOffer open={isOpenModal} onClose={handleClick} />
<Header classCross={styles.cross} clickCross={handleCross} />
<UserHeader email={email} />
<section className="page">

View File

@ -32,12 +32,12 @@ export default {
unexpected_error: 'Sorry, an unexpected error has occurred.',
oops: "Oops!",
total_today: "Total today",
charged_only: "You will be charged only $1 for your 7-day trial. We'll email you a reminder before your trial period ends. Cancel anytime.",
charged_only: "You will be charged only <price> for your 7-day trial. We'll email you a reminder before your trial period ends. Cancel anytime.",
purposes: "For entertaiment purposes only.",
get_access: "Get access",
subscription_text: "By proceeding, you agree that if you do not cancel your subscription before the end of the 7-day trial period, you will be automatically charged nineteen US dollars zero cents every 2 weeks until you cancel the subscription in the settings. Learn more about cancellation and refund policy in <policyLink>",
subscription_policy: "Subscription policy",
company_name: "Wit LLC, California, US",
company_name: "Wit Apps LLC, California, US",
choose_payment: "Choose Payment Method",
or: "OR",
card: "Credit / Debit Card",

View File

@ -93,7 +93,7 @@ export const hasNavigation = (path: string) =>
export const hasNoNavigation = (path: string) => !hasNavigation(path);
export const withCrossButtonRoutes = [
routes.client.attention(),
// routes.client.attention(),
routes.client.subscription(),
];
export const hasCrossButton = (path: string) =>