Palmistry

This commit is contained in:
Евгений Пономарев 2024-03-22 00:28:03 +00:00 committed by Victor Ershov
parent 4ec60bcb8d
commit 21de1c6322
89 changed files with 8464 additions and 1 deletions

75
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@stripe/react-stripe-js": "^2.3.1",
"@stripe/stripe-js": "^2.1.9",
"apng-js": "^1.1.1",
"framer-motion": "^11.0.8",
"html-react-parser": "^3.0.16",
"i18next": "^22.5.0",
"i18next-react-postprocessor": "^3.1.0",
@ -430,6 +431,21 @@
"integrity": "sha512-JsHlIAjZDwX2Q/vDGN4xzKRC8n1K4xCwzKl7wZOOwUH9ow030CRspVRkP3OWHrY5gLmpbmICc/iK2aptF3t/Ow==",
"dev": true
},
"node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.18",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz",
@ -2145,6 +2161,34 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true
},
"node_modules/framer-motion": {
"version": "11.0.8",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.8.tgz",
"integrity": "sha512-1KSGNuqe1qZkS/SWQlDnqK2VCVzRVEoval379j0FiUBJAZoqgwyvqFkfvJbgW2IPFo4wX16K+M0k5jO23lCIjA==",
"dependencies": {
"tslib": "^2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/framer-motion/node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -3821,6 +3865,21 @@
"integrity": "sha512-JsHlIAjZDwX2Q/vDGN4xzKRC8n1K4xCwzKl7wZOOwUH9ow030CRspVRkP3OWHrY5gLmpbmICc/iK2aptF3t/Ow==",
"dev": true
},
"@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"requires": {
"@emotion/memoize": "0.7.4"
}
},
"@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"@esbuild/android-arm": {
"version": "0.17.18",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz",
@ -4957,6 +5016,22 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true
},
"framer-motion": {
"version": "11.0.8",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.8.tgz",
"integrity": "sha512-1KSGNuqe1qZkS/SWQlDnqK2VCVzRVEoval379j0FiUBJAZoqgwyvqFkfvJbgW2IPFo4wX16K+M0k5jO23lCIjA==",
"requires": {
"@emotion/is-prop-valid": "^0.8.2",
"tslib": "^2.4.0"
},
"dependencies": {
"tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",

View File

@ -15,6 +15,7 @@
"@stripe/react-stripe-js": "^2.3.1",
"@stripe/stripe-js": "^2.1.9",
"apng-js": "^1.1.1",
"framer-motion": "^11.0.8",
"html-react-parser": "^3.0.16",
"i18next": "^22.5.0",
"i18next-react-postprocessor": "^3.1.0",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -103,6 +103,7 @@ import AdditionalPurchases from "../pages/AdditionalPurchases";
import AddReportPage from "../pages/AdditionalPurchases/pages/AddReport";
import UnlimitedReadingsPage from "../pages/AdditionalPurchases/pages/UnlimitedReadings";
import AddConsultationPage from "../pages/AdditionalPurchases/pages/AddConsultation";
import StepsManager from "@/components/palmistry/steps-manager/steps-manager";
const isProduction = import.meta.env.MODE === "production";
@ -470,6 +471,17 @@ function App(): JSX.Element {
/>
</Route>
</Route>
<Route
path="/palmistry"
element={<StepsManager/>}
/>
<Route
path="/palmistry/:step"
element={<StepsManager/>}
/>
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>

View File

@ -10,6 +10,7 @@ import BackButton from "./BackButton";
import iconUrl from "./icon.png";
import menuUrl from "./menu.png";
import styles from "./styles.module.css";
import usePalmistrySteps from '@/hooks/palmistry/use-steps';
type HeaderProps = {
openMenu?: () => void;
@ -37,6 +38,7 @@ function Header({
const showBackButton = isNotEntrypoint(location.pathname);
const showMenuButton = hasNavigation(location.pathname);
const showCrossButton = hasCrossButton(location.pathname);
const palmistrySteps = usePalmistrySteps();
useEffect(() => {
if (!initialPath) {
@ -48,6 +50,10 @@ function Header({
}, [location.pathname, initialPath, isNavigated]);
const goBack = () => {
if (location.pathname.includes("/palmistry")) {
palmistrySteps.goBack();
return;
}
if (
location.pathname.includes("/questionnaire") ||
location.pathname.includes("/about-us") ||

View File

@ -20,6 +20,7 @@ function Navbar({ isOpen, closeMenu }: NavbarProps): JSX.Element {
const combinedClassNames = ['navbar', isOpen && 'navbar--open'].filter(Boolean).join(' ')
const handleLogout = () => {
localStorage.removeItem('palmistry.firstUnpassedStep');
navigate(routes.client.birthday())
logout()
}

View File

@ -0,0 +1,7 @@
.alert-modal__title {
font-size: 24px;
font-weight: 500;
line-height: 21px;
margin-bottom: 24px;
text-align: center;
}

View File

@ -0,0 +1,22 @@
import './alert-modal.css';
import Modal, { ModalType } from '../modal/modal';
import ModalOverlay, { ModalOverlayType } from '../modal-overlay/modal-overlay';
type Props = {
title: string;
onClose: () => void;
children: React.ReactNode;
};
export default function AlertModal(props: Props) {
return (
<ModalOverlay type={ModalOverlayType.Dark} className="alert-modal" onClick={props.onClose}>
<Modal type={ModalType.Error} onClose={props.onClose}>
<h3 className="alert-modal__title">{props.title}</h3>
{props.children}
</Modal>
</ModalOverlay>
);
}

View File

@ -0,0 +1,9 @@
.biometric-data {
color: var(--footer-small-text);
font-size: 14px;
font-weight: 400;
line-height: 18px;
max-width: 400px;
text-align: start;
width: 100%;
}

View File

@ -0,0 +1,18 @@
import './biometric-data.css';
export default function BiometricData() {
return (
<div className="biometric-data">
<svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.98799 3.28522L9.98835 3.29467C10.0145 4.72099 10.047 6.49611 9.47166 8.10911C9.1562 8.99366 8.67885 9.76259 8.05294 10.3947C7.34041 11.1142 6.40729 11.6859 5.27957 12.0937C5.24266 12.107 5.20422 12.1178 5.16534 12.1259C5.1106 12.1372 5.05532 12.1429 5.00013 12.1429C4.94494 12.1429 4.88975 12.1372 4.83492 12.1259C4.79603 12.1178 4.75787 12.1071 4.72113 12.0938C3.59208 11.6868 2.65797 11.1155 1.94481 10.3958C1.31864 9.76389 0.84128 8.99514 0.52609 8.11078C-0.0471305 6.5026 -0.0145183 4.73081 0.0117326 3.30717L0.0122702 3.28522C0.017377 3.16775 0.0208711 3.04435 0.0228422 2.90798C0.0324287 2.23836 0.547234 1.68454 1.19473 1.64721C2.5449 1.5692 3.58939 1.11396 4.48183 0.21449L4.48945 0.206986C4.78062 -0.0689955 5.21972 -0.0689955 5.51081 0.206986L5.51843 0.21449C6.41087 1.11396 7.45535 1.5692 8.80553 1.64711C9.45311 1.68454 9.96783 2.23836 9.97742 2.90789C9.97948 3.04518 9.98288 3.16858 9.98799 3.28522ZM4.14758 6.78863L6.48753 4.45882C6.71918 4.22801 7.09473 4.22801 7.32638 4.45882C7.55787 4.68931 7.55787 5.06323 7.32638 5.29388L4.56693 8.04138C4.4511 8.1567 4.29934 8.21429 4.14758 8.21429C3.99582 8.21429 3.84406 8.1567 3.72823 8.04138L2.67362 6.99133C2.44213 6.76084 2.44213 6.38692 2.67362 6.15627C2.90527 5.92562 3.28082 5.92562 3.51247 6.15627L4.14758 6.78863Z"
fill="#B5C4FF"
></path>
</svg>
{' '}
No biometric data collected. All recognition process performs on your device.
</div>
);
}

View File

@ -0,0 +1,89 @@
.button {
align-items: center;
background: var(--button-background);
border: none;
border-radius: 8px;
color: var(--button-color);
cursor: pointer;
display: flex;
font-size: 18px;
font-weight: 500;
justify-content: center;
line-height: 20px;
max-width: 400px;
min-height: 60px;
min-width: 250px;
padding: 12px 16px;
width: 100%;
}
.button__spinner {
animation: spinner-rotate 2s linear infinite;
height: 50px;
left: 50%;
margin: -25px 0 0 -25px;
position: absolute;
top: 50%;
width: 50px;
z-index: 2;
}
.button__spinner-path {
stroke: #93bfec;
stroke-linecap: round;
animation: spinner-dash 1.5s ease-in-out infinite;
}
.button:active:not(.button_disabled) {
animation-duration: 0.2s;
animation-iteration-count: 1;
animation-name: button-scale;
background: var(--button-active-bg);
}
.button_disabled {
background: var(--light-silver);
cursor: not-allowed;
}
.button_active {
background: var(--strong-blue);
color: var(--button-active);
}
@keyframes button-scale {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
-webkit-transform: scale(0.95);
transform: scale(0.95);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes spinner-rotate {
100% {
transform: rotate(1turn);
}
}
@keyframes spinner-dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}

View File

@ -0,0 +1,44 @@
import './button.css';
type Props = {
children: React.ReactNode;
type: 'button' | 'submit';
disabled?: boolean;
onClick?: () => void;
active?: boolean;
className?: string;
isProcessing?: boolean;
};
export default function Button(props: Props) {
const className = ['button'];
if (props.disabled) {
className.push('button_disabled');
}
if (props.active && !props.disabled) {
className.push('button_active');
}
if (props.className) {
className.push(props.className);
}
return (
<button
className={className.join(' ')}
type={props.type}
disabled={props.disabled}
onClick={props.onClick}
>
{props.isProcessing && (
<svg className="button__spinner" viewBox="0 0 50 50">
<circle className="button__spinner-path" cx="25" cy="25" r="20" fill="none" strokeWidth="5"/>
</svg>
)}
{props.children}
</button>
);
}

View File

@ -0,0 +1,6 @@
.color-circle {
border: 2px solid #fff;
border-radius: 50%;
height: 40px;
width: 40px;
}

View File

@ -0,0 +1,9 @@
import './color-circle.css';
type Props = {
color: string;
};
export default function ColorCircle(props: Props) {
return <div className="color-circle" style={{ background: props.color }}/>
}

View File

@ -0,0 +1,113 @@
.discount-screen {
margin: 0 auto;
position: relative;
max-width: 428px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.discount-screen__header {
display: flex;
width: 100%;
padding: 24px 0 11px;
justify-content: center;
}
.discount-screen__content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 0 32px 32px;
}
.discount-screen__content * {
font-family: OpenSans Regular;
}
.discount-screen__title {
font-size: 20px;
margin-top: 23px;
font-weight: 600;
line-height: 24px;
text-align: center;
margin-bottom: 24px;
}
.discount-screen__blocks {
gap: 7px;
display: flex;
align-items: flex-end;
}
.discount-screen__block {
gap: 12px;
width: 160px;
display: flex;
padding: 16px;
overflow: hidden;
text-align: center;
align-items: center;
border-radius: 10px;
flex-direction: column;
}
.discount-screen__block:first-child {
border: 2px solid #c7c7c7;
}
.discount-screen__block:last-child {
padding-top: 0;
border: 2px solid #066fde;
}
.discount-screen__price-block {
font-weight: 600;
line-height: 24px;
}
.discount-screen__details {
display: flex;
flex-direction: column;
}
.discount-screen__details-name {
color: #8e8e93;
font-size: 14px;
line-height: 18px;
}
.discount-screen__details-value {
font-weight: 600;
line-height: 24px;
}
.discount-screen__button {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 132px;
height: fit-content;
min-height: 38px;
background: #066fde;
border-radius: 10px;
border: none;
font-weight: 600;
font-size: 14px;
line-height: 18px;
color: #fff;
}
.discount-screen__header-block {
top: 0;
color: #fff;
height: 32px;
display: flex;
background: #066fde;
align-items: center;
width: calc(100% + 32px);
justify-content: center;
}

View File

@ -0,0 +1,78 @@
import React from "react";
import { useNavigate } from 'react-router-dom';
import './discount-screen.css';
import routes from '@/routes';
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
export default function DiscountScreen() {
const navigate = useNavigate();
const userHasWeeklySubscription = false;
const goPremiumBundle = () => {
navigate(routes.client.palmistryPremiumBundle());
};
React.useEffect(() => {
if (userHasWeeklySubscription) {
goPremiumBundle();
}
}, [userHasWeeklySubscription]);
return (
<div className="discount-screen">
<div className="discount-screen__header">
<HeaderLogo />
</div>
<div className="discount-screen__content">
<span className="discount-screen__title">
Not planning on looking back?
</span>
<div className="discount-screen__blocks">
<section className="discount-screen__block">
<span className="discount-screen__price-block">19 for <br /> 1-week plan</span>
<div className="discount-screen__details">
<span className="discount-screen__details-name">Total savings</span>
<span className="discount-screen__details-value">0</span>
</div>
<div className="discount-screen__details">
<span className="discount-screen__details-name">7-day trial</span>
<span className="discount-screen__details-value">yes</span>
</div>
<button className="discount-screen__button" style={{ minHeight: '38px' }} onClick={goPremiumBundle}>
Start trial
</button>
</section>
<section className="discount-screen__block">
<div className="discount-screen__header-block">save 33%</div>
<span className="discount-screen__price-block">12.73 for <br /> 1-week plan</span>
<div className="discount-screen__details">
<span className="discount-screen__details-name">Total savings</span>
<span className="discount-screen__details-value">6.27</span>
</div>
<div className="discount-screen__details">
<span className="discount-screen__details-name">3-day trial</span>
<span className="discount-screen__details-value">no</span>
</div>
<button className="discount-screen__button">
Pay now and <br /> skip trial
</button>
</section>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,37 @@
.email-header {
align-items: center;
display: flex;
height: 39px;
justify-content: flex-end;
margin-bottom: 32px;
padding: 0 32px;
width: 100%;
background: var(--light-cornflower-blue);
}
.email-header h1 {
font-size: 14px;
line-height: 140%;
color: var(--white);
font-weight: 500;
}
.email-header div {
align-items: center;
background: var(--pale-gray);
border-radius: 50%;
display: flex;
height: 27px;
justify-content: center;
margin-left: 10px;
width: 27px;
background: var(--gentle-blue);
}
.email-header div h1 {
color: #fff;
font-size: 14px;
font-weight: 600;
line-height: 18px;
text-transform: uppercase;
}

View File

@ -0,0 +1,17 @@
import './email-header.css';
type Props = {
email: string;
};
export default function EmailHeader(props: Props) {
return (
<div className="email-header">
<h1>{props.email}</h1>
<div>
<h1>{props.email[0]}</h1>
</div>
</div>
);
}

View File

@ -0,0 +1,12 @@
.header-logo {
display: flex;
flex-direction: row;
align-items: center;
}
.header-logo__caption {
font-size: 24px;
font-weight: 600;
margin-left: 10px;
text-transform: uppercase;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

View File

@ -0,0 +1,12 @@
import './header-logo.css';
import headerLogoImage from './header-logo.png';
export default function HeaderLogo() {
return (
<div className="header-logo">
<img src={headerLogoImage} alt="Logo" width={40} height={40} />
<span className="header-logo__caption">Aura</span>
</div>
);
}

View File

@ -0,0 +1,22 @@
.header {
align-items: center;
display: flex;
justify-content: center;
background: var(--pale-blue);
border-bottom: 1px solid var(--transparent-to-periwinkle);
height: 50px;
min-height: 50px;
position: relative;
width: 100%;
}
.header__button-wrapper {
left: 28px;
position: absolute;
align-items: center;
cursor: pointer;
display: flex;
height: 30px;
justify-content: center;
width: 30px;
}

View File

@ -0,0 +1,36 @@
import './header.css';
import useSteps from '../../../hooks/palmistry/use-steps';
import HeaderLogo from '../header-logo/header-logo';
export default function Home() {
const steps = useSteps();
return (
<header className="header">
{!steps.isWelcome && (
<div className="header__button-wrapper" onClick={steps.goBack}>
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M19.7676 12.3203H5.76758"
stroke="#000000"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.7676 19.3203L5.76758 12.3203L12.7676 5.32031"
stroke="#000000"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
)}
<HeaderLogo/>
</header>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

View File

@ -0,0 +1,6 @@
.input-item__label {
color: var(--slate-blue-placeholder);
font-size: 12px;
line-height: 16px;
margin: 0 0 6px 6px;
}

View File

@ -0,0 +1,26 @@
import './input-item.css';
import Input, { type Props as InputProps } from '../input/input';
type Props = InputProps & {
label: string;
};
export default function InputItem(props: Props) {
return (
<div className="input-item">
<h3 className="input-item__label">{props.label}</h3>
<Input
placeholder={props.placeholder}
maxLength={props.maxLength}
type={props.type}
value={props.value}
onChange={props.onChange}
onFocus={props.onFocus}
onBlur={props.onBlur}
inputMode={props.inputMode}
/>
</div>
);
}

View File

@ -0,0 +1,11 @@
.input-wrapper {
grid-gap: 12px;
background-color: var(--main-gradient);
display: grid;
gap: 12px;
grid-template-columns: repeat(3,1fr);
max-width: 400px;
position: relative;
width: 100%;
z-index: 3;
}

View File

@ -0,0 +1,13 @@
import './input-wrapper.css';
type Props = {
children: React.ReactNode;
};
export default function InputWrapper(props: Props) {
return (
<div className="input-wrapper">
{props.children}
</div>
);
}

View File

@ -0,0 +1,80 @@
.input {
margin-bottom: 0;
width: 100%;
display: block;
font-size: 16px;
height: 48px;
position: relative;
}
.input input {
appearance: none;
background: var(--white-to-transparent);
border: 1px solid var(--light-silver-to-lilac-blue);
border-radius: 8px;
color: var(--midnight-black);
font-size: 16px;
height: 48px;
line-height: 18px;
max-width: 400px;
min-width: 250px;
outline: none;
padding: 12px 12px 5px;
transition: border-color .3s ease;
width: 100%;
background: var(--pale-blue-input);
border: 2px solid var(--pale-lavender);
padding-top: 5px;
color: var(--midnight-black-input);
min-width: 96px;
}
.input input:focus {
border-color: var(--strong-blue);
transition-delay: .1s;
}
.input input:focus + .input__placeholder {
display: none;
}
.input_floating-placeholder input:focus + .input__placeholder {
display: block;
font-size: 12px;
top: 12px;
width: auto;
}
.input.input_filled > .input__placeholder {
display: block;
}
.input_filled .input__placeholder {
display: none;
}
.input__placeholder {
color: var(--slate-blue-placeholder);
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
left: 12px;
overflow: hidden;
text-overflow: ellipsis;
transition: top .3s ease,color .3s ease,font-size .3s ease;
white-space: nowrap;
}
.input__icon-wrapper {
align-items: center;
background: 0 0;
display: flex;
height: 30px;
justify-content: center;
right: 2px;
width: 30px;
position: absolute;
top: 50%;
transform: translateY(-50%);
}

View File

@ -0,0 +1,73 @@
import React from 'react';
import './input.css';
export type Props = {
placeholder: string;
maxLength?: number;
type: 'text' | 'password';
value: string;
className?: string;
inputMode?: 'numeric';
floatingPlaceholder?: boolean;
onChange: (value: string) => void;
onFocus?: (event: React.FocusEvent) => void;
onBlur?: (value: React.FocusEvent) => void;
};
export default function Input(props: Props) {
const [isFocused, setIsFocused] = React.useState(false);
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
props.onChange(event.target.value);
};
const onBlur = (event: React.FocusEvent) => {
setIsFocused(false);
if (props.onBlur) {
props.onBlur(event);
}
}
const onFocus = (event: React.FocusEvent) => {
setIsFocused(true);
if (props.onFocus) {
props.onFocus(event);
}
};
const className = ['input'];
if (props.value) {
className.push('input_filled');
}
if (props.className) {
className.push(props.className);
}
if (props.floatingPlaceholder) {
className.push('input_floating-placeholder');
}
return (
<label className={className.join(' ')}>
<input
type={props.type}
placeholder=" "
maxLength={props.maxLength}
value={props.value}
inputMode={props.inputMode}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
/>
{!props.value && !isFocused && <p className="input__placeholder">{props.placeholder}</p>}
<div className="input__icon-wrapper"/>
</label>
);
}

View File

@ -0,0 +1,44 @@
.loader {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: linear-gradient(358.53deg, #242d7c -20.35%, #00aeef 86.02%);
}
.loader__planet-system {
width: 200px;
height: 200px;
}
.loader__satellite {
transform: translate(99.999167px, 100px);
animation: rotate-loader 2s linear infinite;
}
.loader_transparent {
background: rgba(#fff, 0.5);
}
.loader_transparent .loader__planet-system {
width: 100px;
height: 100px;
}
.loader_fixed {
position: fixed;
}
@keyframes rotate-loader {
0% {
transform: translate(99.999167px, 100px) rotate(0);
}
100% {
transform: translate(99.999167px, 100px) rotate(359deg);
}
}

View File

@ -0,0 +1,169 @@
import './loader.css';
type Props = {
transparent?: boolean;
fixed?: boolean;
};
export default function Loader(props: Props) {
const className = ['loader'];
if (props.fixed) {
className.push('loader_fixed');
}
if (props.transparent) {
className.push('loader_transparent');
}
return (
<div className={className.join(' ')}>
<svg
id="ez7CdZ0ljOb1"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
viewBox="0 0 130 130"
shapeRendering="geometricPrecision"
textRendering="geometricPrecision"
className="loader__planet-system"
>
<g transform="matrix(.75 0 0 0.75-8.94152-4.529317)">
<ellipse
rx="42.992154"
ry="42.992154"
transform="translate(100 100)"
fill="#f2f5fd"
strokeWidth="0"
></ellipse>
<g mask="url(#ez7CdZ0ljOb17)">
<g transform="translate(-.10828 0)">
<path
d="M69.33037,63.94051c11.48667-.555806,10.646781-1.111613,24.220815-.741075s14.129839.741075,16.167797.741075s6.299142,4.075914,1.852689,5.372796-5.122842,1.852689-11.571664,1.111613-5.84361-.926345-12.698558-.555807-12.783549.370538-17.971079.185269-5.187527-6.11387,0-6.113871Z"
transform="translate(.000001 0.000002)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M106.447164,77.0946c14.387951-.185269,16.240641-.185269,21.057631,1.296882s8.892904,5.00226,3.334838,5.187528-24.390804,3.520107-30.839626,1.852687-2.047034-6.550787-1.023517-7.040215s5.641296-1.296882,7.470674-1.296882Z"
transform="translate(.000001 0.000002)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M83.685058,78.391484c3.616392.494232,10.541456,6.575036,3.616392,8.18466s-15.509729-.234097-20.696297-.689271-4.292332-6.732887,1.25193-6.911734s12.211582-1.077887,15.827975-.583655Z"
transform="translate(.000001 0.000001)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M83.685058,78.391484c3.616392.494232,10.541456,6.575036,3.616392,8.18466s-15.509729-.234097-20.696297-.689271-4.292332-6.732887,1.25193-6.911734s12.211582-1.077887,15.827975-.583655Z"
transform="matrix(-1 0 0-1 213.434431 151.473045)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M87.475298,93.610961C81.225563,94.926744,90.575989,100,93.867653,100s15.810607-.589239,13.542308-4.17774-16.642999-2.45053-19.934663-2.211299Z"
transform="translate(-30.692744 0)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M93.551186,91.730207C87.301451,93.04599,86.967858,100,90.259522,100s10.985268-1.332026,8.716969-4.920527-2.133641-3.588497-5.425305-3.349266Z"
transform="translate(0 0.000002)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M115.050874,91.490973c-8.603709.153545-8.60371,2.845717-8.60371,3.588502s-3.850212,4.920525,8.60371,4.920525s32.034786-1.57126,31.675936-4.920526s2.339257-7.857561-3.734656-7.857561-9.289778,4.26906-15.487358,4.26906-3.850213-.153548-12.453922,0Z"
transform="translate(0 0.000004)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M56.579173,106.747003c20.138043,1.33901,20.129223.956437,31.775029,0s24.502726,3.060595,17.562507,7.460202-.644181,1.721584-18.61526,1.721584-25.702176,3.060596-30.722277,1.339011-6.595733-10.903369.000001-10.520797Z"
transform="translate(-7.095096 0.8538)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M123.768487,107.471231c-8.929962,4.228781-2.668871,9.366125,3.323661,9.366125s5.606301-13.594906-3.323661-9.366125Z"
transform="matrix(1.261706 0 0 1.10015-27.493214-8.659777)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M122.4687,107.512152c-7.417826-.765147-6.948968,8.416639-.956436,8.416639s8.374262-7.651491.956436-8.416639Z"
transform="translate(-6.975611-2.944536)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
<path
d="M62.170894,124.599973c0,0,7.578478-1.097554,14.546322-1.097554s10.782458-1.128156,19.990976-.451262s31.177486,1.579419,36.685363,0s23.938755,11.869759-5.888759,12.005015q-29.827516.135256-64.329888,0-6.961132-7.831735-1.004014-10.456199Z"
transform="translate(.000001 0.000002)"
fill="#bcc9ed"
strokeWidth="0.5"
></path>
</g>
<mask id="ez7CdZ0ljOb17" mask-type="luminance" x="-150%" y="-150%" height="400%" width="400%">
<ellipse
rx="42.992154"
ry="42.992154"
transform="translate(100 100)"
fill="#f2f5fd"
strokeWidth="0"
></ellipse>
</mask>
</g>
<path
d="M142.99215,100c0,23.74391-19.24824,42.99215-42.99215,42.99215-14.42453,0-27.18988-7.10378-34.98843-18.00373C72.0538,130.0269,80.68061,132.99215,90,132.99215c23.74391,0,42.99215-19.24824,42.99215-42.99215c0-9.31938-2.96525-17.9462-8.00373-24.98843C135.88837,72.81012,142.99215,85.57547,142.99215,100Z"
fill="#aebce9"
fillOpacity="0.5"
strokeWidth="0"
></path>
<path
d="M57.00785,100c0-23.74391,19.24824-42.99215,42.99215-42.99215c7.46776,0,14.49081,1.904,20.61019,5.25303-3.73326-.8507-7.61926-1.29996-11.61019-1.29996-26.37224,0-48.16261,19.61735-51.57452,45.05546-.2753-1.96596-.41764-3.97455-.41764-6.01638h.00001Z"
fill="#fff"
fillOpacity="0.5"
strokeWidth="0"
></path>
<g id="ez7CdZ0ljOb21_tr" className="loader__satellite">
<g transform="translate(-99.999159,-100)">
<ellipse
rx="42.992154"
ry="42.992154"
transform="matrix(1.547075 0 0 1.547075 100 100)"
fill="none"
stroke="#f2f5fd"
></ellipse>
<ellipse
rx="42.986598"
ry="42.986598"
transform="matrix(.15 0 0 0.15 99.999167 33.48708)"
fill="#aebce9"
strokeWidth="0"
></ellipse>
</g>
</g>
<polygon
points="0,-20 5.656854,-5.656854 20,0 5.656854,5.656854 0,20 -5.656854,5.656854 -20,0 -5.656854,-5.656854 0,-20"
transform="matrix(.35 0 0 0.35 49.579173 17.03909)"
fill="#dee5f9"
strokeWidth="0"
></polygon>
<polygon
points="0,-20 5.656854,-5.656854 20,0 5.656854,5.656854 0,20 -5.656854,5.656854 -20,0 -5.656854,-5.656854 0,-20"
transform="matrix(.27 0 0 0.27 29.579173 37.03909)"
fill="#aebce9"
strokeWidth="0"
></polygon>
<polygon
points="0,-20 5.656854,-5.656854 20,0 5.656854,5.656854 0,20 -5.656854,5.656854 -20,0 -5.656854,-5.656854 0,-20"
transform="matrix(.45 0 0 0.45 169.579173 167.03909)"
fill="#f2f5fd"
strokeWidth="0"
></polygon>
</g>
</svg>
</div>
);
}

View File

@ -0,0 +1,25 @@
.modal-overlay {
background: var(--loader-background);
height: calc(100% + 50px);
min-height: 100vh;
overflow: hidden;
position: fixed;
top: -50px;
left: 0;
width: 100%;
}
.modal-overlay_type_light {
background: var(--loader-background);
}
.modal-overlay_type_dark {
background: rgba(85,84,85,.8);
height: 100vh;
left: 0;
overflow: hidden;
position: fixed;
top: 0;
width: 100%;
z-index: 2000;
}

View File

@ -0,0 +1,29 @@
import './modal-overlay.css';
export enum ModalOverlayType {
Light = 'light',
Dark = 'dark',
}
type Props = {
children?: React.ReactNode;
className?: string;
type?: ModalOverlayType;
onClick?: (e: React.MouseEvent) => void;
};
export default function ModalOverlay(props: Props) {
const className = ['modal-overlay'];
if (props.className) {
className.push(props.className);
}
if (props.type) {
className.push(`modal-overlay_type_${props.type}`);
}
return (
<div className={className.join(' ')} onClick={props.onClick}>{props.children}</div>
);
}

View File

@ -0,0 +1,34 @@
.modal {
left: 50%;
max-width: 488px;
position: absolute;
top: 50%;
transform: translate(-50%,-50%);
width: 100%;
z-index: 3;
}
.modal__close-button {
align-items: center;
background: var(--pale-blue);
border-radius: 20px;
display: flex;
height: 32px;
justify-content: center;
margin-left: auto;
width: 32px;
}
.modal_type_error {
align-items: center;
background: var(--main-gradient);
border: 1px solid #fff;
border-radius: 8px;
box-shadow: 0 0 14px rgba(12,31,65,.24);
color: var(--midnight-black);
display: flex;
flex-direction: column;
max-width: 311px;
padding: 12px 12px 24px;
width: calc(100% - 64px);
}

View File

@ -0,0 +1,51 @@
import './modal.css';
export enum ModalType {
Error = 'error',
}
type Props = {
children: React.ReactNode;
type?: ModalType;
noCloseButton?: boolean;
onClose: () => void;
};
export default function Modal(props: Props) {
const className = ['modal'];
if (props.type === ModalType.Error) {
className.push('modal_type_error');
}
return (
<div className={className.join(' ')}>
{!props.noCloseButton && (
<div className="modal__close-button" onClick={props.onClose}>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.7071 12.7071C12.3166 13.0976 11.6834 13.0976 11.2929 12.7071L6.29289 7.70711C5.90237 7.31658 5.90237 6.68342 6.29289 6.29289L11.2929 1.29289C11.6834 0.902369 12.3166 0.902369 12.7071 1.29289C13.0976 1.68342 13.0976 2.31658 12.7071 2.70711L8.41421 7L12.7071 11.2929C13.0976 11.6834 13.0976 12.3166 12.7071 12.7071Z"
fill="#858DA5"
stroke="#858DA5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.29289 12.7071C1.68342 13.0976 2.31658 13.0976 2.70711 12.7071L7.70711 7.70711C8.09763 7.31658 8.09763 6.68342 7.70711 6.29289L2.70711 1.29289C2.31658 0.902369 1.68342 0.902369 1.29289 1.29289C0.902369 1.68342 0.902369 2.31658 1.29289 2.70711L5.58579 7L1.29289 11.2929C0.902369 11.6834 0.902369 12.3166 1.29289 12.7071Z"
fill="#858DA5"
stroke="#858DA5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
)}
{props.children}
</div>
);
}

View File

@ -0,0 +1,29 @@
.palm-camera-modal__camera {
border-radius: 10px;
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
.palm-camera-modal__hand-icon {
height: calc(100% - 120px);
left: 50%;
position: absolute;
top: 20px;
transform: translate(-50%);
width: auto;
}
.palm-camera-modal__button-shutter {
background: var(--white);
border-radius: 50%;
bottom: 30px;
height: 30px;
left: 50%;
outline: 20px solid hsla(0,0%,100%,.28);
position: absolute;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
width: 30px;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
.palm-recognition-error-modal__title {
font-size: 18px;
font-weight: 500;
line-height: 21px;
margin-bottom: 24px;
margin-top: 12px;
text-align: center;
}
.palm-recognition-error-modal__images {
display: flex;
margin-bottom: 24px;
}
.palm-recognition-error-modal__correct-image-wrapper {
margin-left: 16px;
position: relative;
}
.palm-recognition-error-modal__check-mark {
bottom: 30px;
height: 40px;
position: absolute;
right: -34px;
}
.palm-recognition-error-modal__description {
line-height: 19px;
text-align: center;
}
.palm-recognition-error-modal__close-button {
margin-bottom: 0;
margin-top: 24px;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,614 @@
.palmistry-container {
align-items: center;
display: flex;
flex: 1 1;
flex-direction: column;
padding: 32px;
position: relative;
}
.palmistry-container svg {
display: inline;
vertical-align: baseline;
}
.palmistry-container__header {
color: var(--midnight-black);
font-size: 20px;
font-weight: 500;
line-height: 26px;
text-align: center;
}
.palmistry-container__description {
color: var(--midnight-black);
font-size: 18px;
font-weight: 400;
line-height: 28px;
margin: 24px 0;
text-align: center;
}
.palmistry-container__bold-description {
color: var(--midnight-black);
font-weight: 700;
line-height: 30px;
text-align: center;
}
.palmistry-container__form-birthday {
margin-bottom: 24px;
position: relative;
}
.palmistry-container__error-text {
color: var(--coral);
font-size: 12px;
left: 12px;
line-height: 16px;
margin-left: 12px;
opacity: 0;
position: absolute;
transform: translateY(-32px);
transition: all 0.5s;
}
.palmistry-container__error-text_visible {
opacity: 1;
position: static;
transform: translateY(6px);
}
.palmistry-container__content {
align-items: center;
display: flex;
flex-direction: column;
color: var(--midnight-black);
gap: 24px;
}
.palmistry-container__title {
color: var(--midnight-black);
font-size: 24px;
font-weight: 600;
line-height: 36px;
}
.palmistry-container__bottom-content {
align-items: center;
display: flex;
flex-direction: column;
gap: 12px;
}
.palmistry-container__notification-wrapper {
align-items: center;
display: flex;
flex-direction: column;
gap: 6px;
}
.palmistry-container__policy {
display: flex;
width: 100%;
}
.palmistry-container__policy p {
width: 100%;
color: var(--midnight-black);
font-size: 12px;
font-weight: 400;
line-height: 18px;
text-align: center;
}
.palmistry-container__policy a {
text-decoration: underline;
}
.palmistry-container__purposes {
color: var(--greyish-blue);
font-size: 12px;
line-height: 18px;
text-align: center;
}
.palmistry-container__button-wrapper {
align-items: center;
display: flex;
flex-direction: column;
width: 100%;
}
.palmistry-container__button-wrapper button:not(:last-child) {
margin-bottom: 12px;
}
.palmistry-container__button-wrapper_horizontal {
display: flex;
gap: 12px;
width: 100%;
}
.palmistry-container__button-wrapper_horizontal button {
flex: 1 1;
max-width: none;
min-width: auto;
}
.palmistry-container__title-wrapper {
color: var(--midnight-black);
}
.palmistry-container__title-wrapper h3 {
line-height: 30px;
text-align: center;
}
.palmistry-container_single-question {
gap: 24px;
padding: 32px;
}
.palmistry-container__personal-statement-subtitle {
font-size: 18px;
font-weight: 400;
line-height: 28px;
min-height: 56px;
opacity: 0;
}
.palmistry-container__personal-statement-fade-in-animation {
animation: personal-statement-fade-in 0.7s ease;
opacity: 1;
}
.palmistry-container__personal-statement-button-container {
display: flex;
gap: 12px;
width: 100%;
}
.palmistry-container__personal-statement-button.button {
min-width: 30px;
}
.palmistry-container__personal-statement-text-block {
display: flex;
font-weight: 400;
justify-content: space-between;
width: 100%;
}
.palmistry-container__personal-statement-text-block > p {
text-align: left;
}
.palmistry-container__personal-statement-text-block > p:last-child {
text-align: right;
}
.palmistry-container__image-wrapper {
background: var(--pale-blue);
border-radius: 8px;
display: flex;
gap: 20px;
justify-content: space-evenly;
margin: 24px 0;
max-width: 400px;
min-width: 310px;
padding: 12px;
position: relative;
width: 100%;
}
.palmistry-container__image-wrapper-container {
text-align: center;
}
.palmistry-container__correct-title, .palmistry-container__wrong-title {
font-size: 18px;
font-weight: 700;
line-height: 24px;
margin-bottom: 6px;
}
.palmistry-container__correct-title {
color: var(--pale-green);
}
.palmistry-container__wrong-title {
color: var(--bright-red);
}
.palmistry-container__wrapper-correct-palm-image {
position: relative;
}
.palmistry-container__check-mark {
bottom: 43px;
position: absolute;
right: -20px;
}
.palmistry-container__uncorrect-images {
grid-gap: 6px 16px;
align-items: center;
display: grid;
gap: 6px 16px;
grid-template-columns: repeat(2, 1fr);
}
.palmistry-container__uncorrect-images > :last-child {
margin-left: -5px;
}
.palmistry-container__take-palm-button {
margin-bottom: 12px;
}
.palmistry-container_type_resonated-element {
gap: 24px;
padding: 32px;
}
.palmistry-container_type_resonated-element > div {
margin: 0;
}
.palmistry-container_type_resonated-element > div + div {
display: flex;
flex-direction: column;
gap: 6px;
}
.palmistry-container_type_resonated-element button {
gap: 24px;
justify-content: flex-start;
margin: 0 !important;
min-width: 311px;
padding: 0 24px;
}
.palmistry-container_type_color-you-like {
padding: 32px;
}
.palmistry-container_type_color-you-like > div {
margin: 0;
}
.palmistry-container_type_color-you-like > div + div {
display: flex;
flex-direction: column;
gap: 6px;
}
.palmistry-container_type_color-you-like button {
gap: 24px;
justify-content: flex-start;
margin: 0 !important;
min-width: 311px;
padding: 0 24px;
}
.palmistry-container_type_decisions {
padding: 32px;
}
.palmistry-container_type_decisions > div {
margin: 0;
}
.palmistry-container_type_guidance-plan {
gap: 24px;
}
.palmistry-container_type_personal-statement {
color: var(--midnight-black);
font-size: 20px;
font-weight: 500;
gap: 24px;
line-height: 26px;
text-align: center;
}
.palmistry-container_type_scan-info {
gap: 24px;
text-align: center;
}
.palmistry-container_type_scan-info .palmistry-container__title {
color: var(--midnight-black);
font-size: 20px;
font-weight: 500;
line-height: 28px;
}
.palmistry-container_type_scan-info .palmistry-container__description {
font-size: 18px;
font-weight: 400;
line-height: 28px;
margin: 0;
}
.palmistry-container_type_upload {
flex-flow: wrap;
flex-direction: column;
padding-top: 0;
position: relative;
}
.palmistry-container_type_upload .palmistry-container__title {
color: var(--midnight-black);
font-size: 20px;
font-weight: 500;
line-height: 24px;
margin-top: 32px;
text-align: center;
}
.palmistry-container_type_scan-photo {
color: var(--midnight-black);
}
.palmistry-container_type_scan-photo .palmistry-container__title {
font-size: 20px;
font-weight: 600;
line-height: 24px;
margin-bottom: 34px;
text-align: center;
animation: title-opacity 1.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 13s;
animation-fill-mode: forwards;
}
.palmistry-container_type_scan-photo .palmistry-container__waiting-title {
animation: waiting-title 0.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 14.5s;
animation-fill-mode: forwards;
font-size: 18px;
font-weight: 500;
line-height: 24px;
margin-top: 70px;
opacity: 0;
text-align: center;
}
.palmistry-container_type_scan-photo .palmistry-container__waiting-description {
animation: waiting-description 8s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 15s;
animation-fill-mode: forwards;
font-size: 18px;
font-weight: 400;
line-height: 24px;
margin-top: 45px;
opacity: 0;
text-align: center;
}
.palmistry-container_type_email {
color: var(--midnight-black);
padding-top: 32px;
}
.palmistry-container_type_email .palmistry-container__title-wrapper {
margin-bottom: 24px;
}
.palmistry-container_type_email .palmistry-container__title-wrapper h2 {
font-size: 20px;
font-style: normal;
font-weight: 500;
letter-spacing: -0.0024em;
line-height: 30px;
text-align: center;
}
.palmistry-container_type_email .palmistry-container__input {
margin-bottom: 24px;
max-width: 400px;
width: 100%;
}
.palmistry-container_type_email .palmistry-container__input input {
appearance: none;
background: var(--white-to-transparent);
border: 1px solid var(--light-silver-to-lilac-blue);
border-radius: 8px;
color: var(--midnight-black);
font-size: 16px;
height: 48px;
line-height: 18px;
max-width: 400px;
min-width: 250px;
outline: none;
padding: 12px 12px 5px;
transition: border-color 0.3s ease;
width: 100%;
}
.palmistry-container_type_email .palmistry-container__input input:not(:placeholder-shown) + .input__placeholder {
font-size: 12px;
top: 12px;
width: auto;
}
.palmistry-container_type_email .palmistry-container__description {
margin-top: 0;
margin-bottom: 24px;
}
.palmistry-container_type_email .palmistry-container__description h3 {
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: 28px;
text-align: center;
}
.palmistry-container_type_email .palmistry-container__policy {
display: flex;
max-width: 400px;
width: 100%;
}
.palmistry-container_type_email .palmistry-container__policy p {
color: var(--midnight-black);
font-size: 14px;
font-weight: 400;
line-height: 18px;
text-align: center;
}
.palmistry-container_type_email .palmistry-container__policy a {
color: var(--midnight-black);
font-size: 14px;
font-weight: 400;
line-height: 18px;
text-align: center;
text-decoration: underline;
}
.palmistry-container_type_email .palmistry-container__button {
margin: 24px 0 32px;
}
.palmistry-container_type_subscription-plan {
align-items: center;
display: flex;
flex-direction: column;
padding: 0 32px 32px;
width: 100%;
color: var(--midnight-black);
}
.palmistry-container_type_subscription-plan .palmistry-container__title {
font-size: 20px;
font-weight: 500;
line-height: 120%;
text-align: center;
}
.palmistry-container_type_subscription-plan .palmistry-container__image {
margin: 12px 0;
}
.palmistry-container_type_subscription-plan .palmistry-container__plans {
display: flex;
justify-content: center;
margin-bottom: 27px;
width: 100%;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan {
align-items: center;
border: 2px solid var(--pale-gray);
border-radius: 8px;
cursor: pointer;
display: flex;
height: 56px;
justify-content: center;
max-width: 76px;
padding: 0 4px;
width: fit-content;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan h3 {
font-size: 16px;
line-height: 20px;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan:not(:last-child) {
margin-right: 12px;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan:last-child {
position: relative;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan:last-child::after {
content: '';
background: var(--pale-gray);
bottom: -24px;
height: 15px;
position: absolute;
width: 2px;
}
.palmistry-container_type_subscription-plan .palmistry-container__plan_active {
background: var(--transparent-to-gold);
border: 2px solid var(--strong-blue);
color: var(--black-color-text);
}
.palmistry-container_type_subscription-plan .palmistry-container__plan_active::after {
background: var(--strong-blue) !important;
}
.palmistry-container_type_subscription-plan .palmistry-container__subscription-text {
font-size: 14px;
font-weight: 600;
line-height: 120%;
margin-bottom: 16px;
text-align: center;
}
.palmistry-container_type_subscription-plan .palmistry-container__subscription-text_active {
color: var(--blue-color-text);
}
.palmistry-container_type_subscription-plan .email-header {
width: calc(100% + 64px);
}
.palmistry-container_type_paywall {
align-items: center;
display: flex;
flex-direction: column;
width: 100%;
color: var(--midnight-black);
padding: 0;
position: relative;
}
.palmistry-container_type_payment {
padding-bottom: 0;
}
.palmistry-container_type_discount {
width: 100%;
}
@keyframes personal-statement-fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes title-opacity {
100% {
opacity: 0;
}
}
@keyframes waiting-title {
100% {
margin-top: 34px;
opacity: 1;
}
}
@keyframes waiting-description {
10% {
margin-top: 24px;
opacity: 1;
}
100% {
margin-top: 24px;
opacity: 1;
}
}

View File

@ -0,0 +1,40 @@
import './palmistry-container.css';
import { Step } from '@/hooks/palmistry/use-steps';
export enum ContainerType {
Elements = 'elements',
ColorYouLike = 'color-you-like',
Decisions = 'decisions',
GuidancePlan = 'guidance-plan',
PersonalStatement = 'personal-statement',
ScanInfo = 'scan-info',
Upload = 'upload',
ScanPhoto = 'scan-photo',
Email = 'email',
SubscriptionPlan = 'subscription-plan',
}
type Props = {
children: React.ReactNode;
singleQuestion: boolean;
type: Step | null;
};
export default function PalmistryContainer(props: Props) {
const className = ['palmistry-container'];
if (props.type) {
className.push(`palmistry-container_type_${props.type}`);
}
if (props.singleQuestion) {
className.push('palmistry-container_single-question');
}
return (
<section className={className.join(' ')}>
{props.children}
</section>
);
}

View File

@ -0,0 +1,228 @@
.payment-screen {
margin: 0 auto;
position: relative;
max-width: 428px;
height: 100%;
display: flex;
flex-direction: column;
}
.payment-screen__header {
display: flex;
width: 100%;
padding: 24px 0 11px;
justify-content: center;
}
.payment-screen__content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
}
.payment-screen__content * {
font-family: OpenSans Regular;
}
.payment-screen__about-us {
display: flex;
text-align: center;
align-items: center;
flex-direction: column;
margin-bottom: 16px;
}
.payment-screen__about-us > span {
padding: 0 60px;
margin-bottom: 6px;
}
.payment-screen__about-us span {
font-size: 14px;
line-height: 18px;
font-family: Alata Regular !important;
}
.payment-screen__about-us-accent {
color: #066fde;
}
.payment-screen__timer {
width: 100%;
display: flex;
padding: 8px 12px;
border-radius: 4px;
background: #eff2fd;
margin-bottom: 16px;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
}
.payment-screen__timer-title {
font-size: 14px;
line-height: 20px;
}
.payment-screen__timer-time {
gap: 1px;
display: flex;
font-size: 16px;
line-height: 22px;
align-items: center;
}
.payment-screen__timer-time span {
width: 18px;
height: 28px;
display: flex;
background: #fff;
font-weight: 700;
border-radius: 4px;
align-items: center;
justify-content: center;
border: 1px solid #dee5f9;
}
.payment-screen__title {
width: 100%;
margin-bottom: 16px;
font-size: 24px;
line-height: 32px;
text-align: left;
color: #121620;
font-weight: 400;
font-family: Alata Regular !important;
}
.payment-screen__total-today {
width: 100%;
display: flex;
padding: 12px 0;
margin-bottom: 6px;
align-items: center;
border-top: 1px solid #dee5f9;
border-bottom: 1px solid #dee5f9;
justify-content: space-between;
}
.payment-screen__total-today span {
font-size: 16px;
line-height: 18px;
font-weight: 600;
}
.payment-screen__total-today .payment-screen__trial-price {
color: #066fde;
font-weight: 700;
}
.payment-screen__promocode {
gap: 8px;
width: 100%;
display: flex;
align-items: center;
padding: 12px 0 16px;
}
.payment-screen__promocode span {
color: #04a777;
font-size: 12px;
font-weight: 600;
line-height: 18px;
}
.payment-screen__prices {
width: 100%;
display: flex;
margin-bottom: 6px;
flex-direction: column;
}
.payment-screen__prices span {
color: #4b536a;
font-size: 12px;
line-height: 20px;
}
.payment-screen__prices s {
color: #858da5;
}
.payment-screen__guarantees {
width: 100%;
display: flex;
justify-content: space-between;
gap: 30px;
margin-bottom: 30px;
}
.payment-screen__guarantee {
width: 100%;
display: flex;
justify-content: space-between;
gap: 8px;
max-width: 155px;
align-items: center;
}
.payment-screen__guarantee svg {
min-width: 24px;
min-height: 24px;
max-width: 24px;
max-height: 24px;
}
.payment-screen__guarantee span {
color: #4b536a;
font-weight: 600;
font-size: 12px;
line-height: 18px;
}
.payment-screen__widget {
background: #fff;
bottom: 0;
box-shadow: 0 -2px 16px rgba(18, 22, 32, .1);
max-width: 428px;
width: 100%;
padding: 40px;
position: relative;
}
.payment-screen__widget_success {
height: 400px;
}
.payment-screen__success {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: #fff;
z-index: 99;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 30px;
padding: 40px;
}
.payment-screen__success-icon {
width: 100px;
height: 100px;
max-width: 50%;
flex-shrink: 0;
}
.payment-screen__success-text {
font-size: 24px;
line-height: 32px;
text-align: center;
color: #121620;
}

View File

@ -0,0 +1,269 @@
import React from "react";
import { useSelector } from "react-redux";
import { useNavigate } from 'react-router-dom';
import './payment-screen.css';
import routes from '@/routes';
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
import useTimer from '@/hooks/palmistry/use-timer';
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
import PaymentModal from "@/components/pages/TrialPayment/components/PaymentModal";
import { selectors } from "@/store";
const getFormattedPrice = (price: number) => {
return (price / 100).toFixed(2);
}
export default function PaymentScreen() {
const navigate = useNavigate();
const time = useTimer();
const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan);
// const subscriptionStatus = useSelector(selectors.selectStatus);
const subscriptionStatus = "subscribed";
const steps = useSteps();
React.useEffect(() => {
if (subscriptionStatus === "subscribed") {
setTimeout(() => {
navigate(routes.client.palmistryDiscount());
}, 1500);
}
}, [subscriptionStatus]);
React.useEffect(() => {
if (!activeSubPlanFromStore) {
steps.setFirstUnpassedStep(Step.SubscriptionPlan);
}
}, [activeSubPlanFromStore]);
const trialPrice = activeSubPlanFromStore?.trial?.price_cents || 0;
const fullPrice = activeSubPlanFromStore?.price_cents || 0;
const [minutes, seconds] = time.split(':');
return (
<div className="payment-screen">
<div className="payment-screen__header">
<HeaderLogo />
</div>
<div className="payment-screen__content">
<div className="payment-screen__about-us">
<span>
The #1 Astrology app trusted by over{" "}
<span className="payment-screen__about-us-accent">25 million</span>{" "}
people.
</span>
<svg
width="77"
height="12"
viewBox="0 0 77 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_409_2130)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.4773 4.45009C12.4173 4.2587 12.2544 4.13486 12.0624 4.13486L8.13729 4.12454L6.89963 0.310887C6.83788 0.120438 6.67628 -0.00762207 6.48113 0.000352486C6.28911 0.00269785 6.12704 0.127475 6.06931 0.319328L4.91044 4.12454L0.937881 4.13486C0.745855 4.13486 0.582925 4.2587 0.522944 4.44961C0.462517 4.64098 0.52384 4.84226 0.678714 4.96139L3.78738 7.36358L2.56808 11.401C2.5099 11.5928 2.57256 11.7926 2.72833 11.9109C2.80666 11.97 2.89618 12 2.98571 12C3.07434 12 3.16251 11.9709 3.23906 11.9132L6.51646 9.49272L9.76119 11.9113C9.91565 12.0295 10.1179 12.0291 10.2733 11.9109C10.429 11.7932 10.4917 11.5933 10.434 11.4014L9.21289 7.36358L12.3211 4.96184C12.476 4.84226 12.5373 4.64098 12.4773 4.45009Z"
fill="#FFC43A"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M28.4773 4.45009C28.4173 4.2587 28.2544 4.13486 28.0624 4.13486L24.1373 4.12454L22.8996 0.310887C22.8379 0.120438 22.6763 -0.00762207 22.4811 0.000352486C22.2891 0.00269785 22.127 0.127475 22.0693 0.319328L20.9104 4.12454L16.9379 4.13486C16.7458 4.13486 16.5829 4.2587 16.5229 4.44961C16.4625 4.64098 16.5239 4.84226 16.6787 4.96139L19.7874 7.36358L18.5681 11.401C18.5099 11.5928 18.5726 11.7926 18.7283 11.9109C18.8066 11.97 18.8962 12 18.9857 12C19.0743 12 19.1625 11.9709 19.2391 11.9132L22.5165 9.49272L25.7612 11.9113C25.9156 12.0295 26.1179 12.0291 26.2733 11.9109C26.429 11.7931 26.4917 11.5933 26.434 11.4014L25.2129 7.36358L28.3211 4.96184C28.476 4.84226 28.5373 4.64098 28.4773 4.45009Z"
fill="#FFC43A"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M44.4773 4.45009C44.4173 4.2587 44.2544 4.13486 44.0624 4.13486L40.1373 4.12454L38.8996 0.310887C38.8379 0.120438 38.6763 -0.00762207 38.4811 0.000352486C38.2891 0.00269785 38.127 0.127475 38.0693 0.319328L36.9104 4.12454L32.9379 4.13486C32.7459 4.13486 32.5829 4.2587 32.5229 4.44961C32.4625 4.64098 32.5238 4.84226 32.6787 4.96139L35.7874 7.36358L34.5681 11.401C34.5099 11.5928 34.5726 11.7926 34.7283 11.9109C34.8066 11.97 34.8962 12 34.9857 12C35.0743 12 35.1625 11.9709 35.2391 11.9132L38.5165 9.49272L41.7612 11.9113C41.9156 12.0295 42.1179 12.0291 42.2733 11.9109C42.429 11.7931 42.4917 11.5933 42.434 11.4014L41.2129 7.36358L44.3211 4.96184C44.476 4.84226 44.5373 4.64098 44.4773 4.45009Z"
fill="#FFC43A"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M60.4774 4.45009C60.4169 4.2587 60.2543 4.13486 60.0621 4.13486L56.1372 4.12454L54.8996 0.310887C54.8376 0.120438 54.6761 -0.00762207 54.4812 0.000352486C54.2889 0.00269785 54.1268 0.127475 54.069 0.319328L52.9106 4.12454L48.9379 4.13486C48.7459 4.13486 48.5829 4.2587 48.5229 4.44961C48.4625 4.64098 48.5238 4.84226 48.6787 4.96139L51.7873 7.36358L50.5681 11.401C50.5098 11.5928 50.5725 11.7926 50.7283 11.9109C50.8066 11.97 50.8961 12 50.9857 12C51.0743 12 51.1625 11.9709 51.239 11.9132L54.5166 9.49272L57.7609 11.9113C57.9157 12.0295 58.1179 12.0291 58.2732 11.9109C58.429 11.7931 58.4915 11.5933 58.4337 11.4014L57.2127 7.36358L60.321 4.96184C60.4758 4.84226 60.5373 4.64098 60.4774 4.45009Z"
fill="#FFC43A"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M76.4774 4.45009C76.4174 4.2587 76.2544 4.13486 76.0626 4.13486L72.1372 4.12454L70.8996 0.310887C70.8381 0.120438 70.6765 -0.00762207 70.4811 0.000352486C70.2894 0.00269785 70.1273 0.127475 70.0695 0.319328L68.9106 4.12454L64.9382 4.13486C64.746 4.13486 64.5829 4.2587 64.5229 4.44961C64.4625 4.64098 64.524 4.84226 64.6787 4.96139L67.7876 7.36358L66.5682 11.401C66.5099 11.5928 66.5729 11.7926 66.7282 11.9109C66.8069 11.97 66.8965 12 66.9856 12C67.0742 12 67.1628 11.9709 67.2394 11.9132L70.5166 9.49272L73.7614 11.9113C73.9157 12.0295 74.1179 12.0291 74.2731 11.9109C74.429 11.7931 74.492 11.5933 74.4342 11.4014L73.2127 7.36358L76.3211 4.96184C76.4758 4.84226 76.5373 4.64098 76.4774 4.45009Z"
fill="#FFC43A"
/>
</g>
<defs>
<clipPath id="clip0_409_2130">
<rect
width="76"
height="12"
fill="white"
transform="translate(0.5)"
/>
</clipPath>
</defs>
</svg>
</div>
<div className="payment-screen__timer">
<span className="payment-screen__timer-title">
Personalized offer reserved
</span>
<div className="payment-screen__timer-time">
<span>{minutes[0]}</span>
<span>{minutes[1]}</span>:<span>{seconds[0]}</span>
<span>{seconds[1]}</span>
</div>
</div>
<h1 className="payment-screen__title">Start your 7-day trial</h1>
<div className="payment-screen__total-today">
<span>Total today</span>
<span className="payment-screen__trial-price">
${getFormattedPrice(trialPrice)}
</span>
</div>
<div className="payment-screen__promocode">
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.125 8.125C8.47018 8.125 8.75 7.84518 8.75 7.5C8.75 7.15482 8.47018 6.875 8.125 6.875C7.77982 6.875 7.5 7.15482 7.5 7.5C7.5 7.84518 7.77982 8.125 8.125 8.125Z"
fill="#04A777"
/>
<path
d="M11.875 13.125C12.2202 13.125 12.5 12.8452 12.5 12.5C12.5 12.1548 12.2202 11.875 11.875 11.875C11.5298 11.875 11.25 12.1548 11.25 12.5C11.25 12.8452 11.5298 13.125 11.875 13.125Z"
fill="#04A777"
/>
<path
d="M17.5 6.05375V3.75C17.5 3.405 17.22 3.125 16.875 3.125H3.125C2.78 3.125 2.5 3.405 2.5 3.75V6.05375C0.9875 6.7575 0 8.29 0 10C0 11.7087 0.9875 13.2425 2.5 13.9462V16.25C2.5 16.595 2.78 16.875 3.125 16.875H16.875C17.22 16.875 17.5 16.595 17.5 16.25V13.9462C19.0125 13.2425 20 11.7087 20 10C20 8.29 19.0125 6.7575 17.5 6.05375ZM8.125 5.625C9.15875 5.625 10 6.46625 10 7.5C10 8.53375 9.15875 9.375 8.125 9.375C7.09125 9.375 6.25 8.53375 6.25 7.5C6.25 6.46625 7.09125 5.625 8.125 5.625ZM6.875 14.375C6.73375 14.375 6.5925 14.3275 6.475 14.23C6.21 14.0087 6.17375 13.615 6.395 13.35L12.645 5.85C12.8675 5.58375 13.2612 5.55125 13.525 5.77C13.79 5.99125 13.825 6.385 13.6038 6.65125L7.35375 14.1512C7.23125 14.2975 7.05375 14.375 6.875 14.375ZM11.875 14.375C10.8413 14.375 10 13.5337 10 12.5C10 11.4663 10.8413 10.625 11.875 10.625C12.9087 10.625 13.75 11.4663 13.75 12.5C13.75 13.5337 12.9087 14.375 11.875 14.375Z"
fill="#04A777"
/>
</svg>
<span>Code AURA24 applied!</span>
</div>
<div className="payment-screen__prices">
<span>
You will be charged only{" "}
<b>${getFormattedPrice(trialPrice)} for your 7-day trial.</b>
</span>
<span>
Then <s>${getFormattedPrice(fullPrice)}</s> $
{getFormattedPrice(trialPrice)} per week. Save $
{getFormattedPrice(fullPrice - trialPrice)} every week.
</span>
<span>
Well <b>email you a reminder</b> before your trial ends.
</span>
</div>
<div className="payment-screen__guarantees">
<div className="payment-screen__guarantee">
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_409_2029)">
<path
d="M20.003 4.75028C20.003 3.23303 18.7698 2 17.2525 2H2.75046C1.23321 2 0 3.23303 0 4.75028V8.00088H20.003V4.75028Z"
fill="#066FDE"
/>
<path
d="M5.00027 5.00079C4.44721 5.00079 4 4.55267 4 4.00052V1.00008C4 0.448125 4.44721 0 5.00027 0C5.55333 0 6.00035 0.448125 6.00035 1.00008V4.00052C6.00035 4.55267 5.55333 5.00079 5.00027 5.00079Z"
fill="#066FDE"
/>
<path
d="M15.002 5.00079C14.449 5.00079 14.002 4.55267 14.002 4.00052V1.00008C14.002 0.448125 14.449 0 15.002 0C15.5551 0 16.0021 0.448125 16.0021 1.00008V4.00052C16.0021 4.55267 15.5551 5.00079 15.002 5.00079Z"
fill="#066FDE"
/>
<path
d="M8.00123 19.0029H3.00044C1.3462 19.0029 0 17.6567 0 16.0025V6.00106C0 5.44892 0.447026 5.00098 1.00008 5.00098C1.55314 5.00098 2.00035 5.44892 2.00035 6.00106V16.0025C2.00035 16.5537 2.44829 17.0027 3.00044 17.0027H8.00123C8.55429 17.0027 9.00131 17.4507 9.00131 18.0028C9.00131 18.555 8.55429 19.0029 8.00123 19.0029Z"
fill="#066FDE"
/>
<path
d="M19.004 9.0015C18.4509 9.0015 18.0039 8.55337 18.0039 8.00141V6.00106C18.0039 5.44892 18.4509 5.00098 19.004 5.00098C19.5571 5.00098 20.0043 5.44892 20.0043 6.00106V8.00141C20.0043 8.55337 19.5571 9.0015 19.004 9.0015Z"
fill="#066FDE"
/>
<path
d="M22.1001 12.9057C19.5657 10.3713 15.441 10.3713 12.9066 12.9057C10.3723 15.44 10.3723 19.5647 12.9066 22.0991C15.441 24.6334 19.5657 24.6334 22.1001 22.0991C24.6344 19.5647 24.6344 15.44 22.1001 12.9057ZM18.7405 20.1548L17.5033 18.9166L16.2662 20.1537C15.8761 20.5437 15.2419 20.5437 14.8519 20.1537C14.4618 19.7636 14.4618 19.1296 14.8519 18.7395L16.0891 17.5023L14.8519 16.2652C14.4618 15.8751 14.4618 15.241 14.8519 14.8509C15.2419 14.4608 15.8761 14.4608 16.2662 14.8509L17.5033 16.0881L18.7405 14.8509C19.1306 14.4608 19.7646 14.4608 20.1546 14.8509C20.5447 15.241 20.5447 15.8751 20.1546 16.2652L18.9176 17.5023L20.1546 18.7395C20.5447 19.1296 20.5447 19.7636 20.1546 20.1537C19.7646 20.5448 19.1315 20.5448 18.7405 20.1548Z"
fill="#066FDE"
/>
</g>
<defs>
<clipPath id="clip0_409_2029">
<rect width="24" height="24" fill="white"></rect>
</clipPath>
</defs>
</svg>
<span>No commitment. Cancel anytime.</span>
</div>
<div className="payment-screen__guarantee">
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M21.4319 3.42545C16.665 3.42545 12.5755 0.218965 12.5326 0.184671C12.3813 0.0650635 12.194 0 12.0011 0C11.8081 0 11.6209 0.0650635 11.4695 0.184671C11.4266 0.218965 7.35424 3.42545 2.57024 3.42545C2.34286 3.42545 2.12479 3.51577 1.964 3.67656C1.80322 3.83734 1.71289 4.05541 1.71289 4.28279V11.9989C1.71289 17.7517 4.0363 20.5724 11.6496 23.9246C11.7601 23.9743 11.8799 24 12.0011 24C12.1222 24 12.242 23.9743 12.3526 23.9246C19.9658 20.5724 22.2892 17.7517 22.2892 11.9989V4.28279C22.2892 4.05541 22.1989 3.83734 22.0381 3.67656C21.8773 3.51577 21.6593 3.42545 21.4319 3.42545ZM12.0011 18.8577C10.6445 18.8577 9.31845 18.4554 8.19053 17.7018C7.06261 16.9481 6.1835 15.8769 5.66438 14.6237C5.14525 13.3704 5.00942 11.9913 5.27407 10.6608C5.53872 9.33037 6.19195 8.10825 7.15117 7.14903C8.11039 6.18981 9.33251 5.53658 10.663 5.27193C11.9935 5.00728 13.3725 5.14311 14.6258 5.66223C15.8791 6.18136 16.9503 7.06047 17.7039 8.18839C18.4576 9.31631 18.8598 10.6424 18.8598 11.9989C18.8598 13.818 18.1372 15.5625 16.851 16.8488C15.5647 18.1351 13.8201 18.8577 12.0011 18.8577Z"
fill="#066FDE"
/>
<path
d="M13.9646 9.67597L11.1439 12.5052L10.0379 11.3907C9.95799 11.3107 9.86309 11.2473 9.75865 11.2041C9.65421 11.1608 9.54226 11.1385 9.42921 11.1385C9.31617 11.1385 9.20422 11.1608 9.09978 11.2041C8.99534 11.2473 8.90044 11.3107 8.8205 11.3907C8.74056 11.4706 8.67715 11.5655 8.63389 11.6699C8.59063 11.7744 8.56836 11.8863 8.56836 11.9994C8.56836 12.1124 8.59063 12.2244 8.63389 12.3288C8.67715 12.4333 8.74056 12.5282 8.8205 12.6081L10.5352 14.3228C10.6149 14.4031 10.7097 14.4669 10.8142 14.5105C10.9187 14.554 11.0307 14.5764 11.1439 14.5764C11.2571 14.5764 11.3692 14.554 11.4736 14.5105C11.5781 14.4669 11.6729 14.4031 11.7526 14.3228L15.182 10.8934C15.262 10.8135 15.3254 10.7186 15.3686 10.6141C15.4119 10.5097 15.4342 10.3977 15.4342 10.2847C15.4342 10.1716 15.4119 10.0597 15.3686 9.95525C15.3254 9.8508 15.262 9.7559 15.182 9.67597C15.1021 9.59603 15.0072 9.53262 14.9027 9.48936C14.7983 9.44609 14.6863 9.42383 14.5733 9.42383C14.4603 9.42383 14.3483 9.44609 14.2439 9.48936C14.1394 9.53262 14.0445 9.59603 13.9646 9.67597Z"
fill="#066FDE"
/>
</svg>
<span>30-Day Money-Back Guarantee</span>
</div>
</div>
</div>
<style>{`.palmistry-payment-modal { max-height: calc(100dvh - 40px) }`}</style>
{activeSubPlanFromStore && (
<div className={`payment-screen__widget${subscriptionStatus === "subscribed" ? " payment-screen__widget_success" : ""}`}>
{subscriptionStatus !== "subscribed" && <PaymentModal />}
{subscriptionStatus === "subscribed" && (
<div className="payment-screen__success">
<svg
className="payment-screen__success-icon"
xmlns="http://www.w3.org/2000/svg"
width="512"
height="512"
viewBox="0 0 52 52"
>
<path
fill="#4ec794"
d="M26 0C11.664 0 0 11.663 0 26s11.664 26 26 26 26-11.663 26-26S40.336 0 26 0zm14.495 17.329-16 18a1.997 1.997 0 0 1-2.745.233l-10-8a2 2 0 0 1 2.499-3.124l8.517 6.813L37.505 14.67a2.001 2.001 0 0 1 2.99 2.659z"
/>
</svg>
<div className="payment-screen__success-text">Payment success</div>
</div>
)}
</div>
)}
</div>
);
}

View File

@ -0,0 +1,637 @@
.paywall {
align-items: center;
display: flex;
flex-direction: column;
padding: 0;
width: 100%;
}
.paywall__trusted {
align-items: center;
border-bottom: 1px solid var(--pale-lavender);
display: flex;
gap: 12px;
justify-content: flex-start;
margin-top: -30px;
padding: 12px 20px;
}
.paywall__trusted-image {
width: 50px;
}
.paywall__trusted-text {
color: var(--soft-blue);
font-family: SF Pro Text Regular, sans-serif;
font-size: 14px;
font-weight: 500;
line-height: 18px;
}
.paywall__trusted-text-accent {
color: var(--strong-blue-text);
}
.paywall__trusted-rate {
background-color: #fff;
border: 1px solid var(--pale-lavender);
border-radius: 30px;
color: #121620;
display: flex;
font-size: 12px;
font-weight: 500;
gap: 2px;
line-height: 16px;
padding: 9px 10px;
}
.paywall__title {
margin-right: auto;
padding: 0 20px;
}
.paywall__title-text {
color: var(--midnight-black);
font-size: 30px;
font-weight: 600;
line-height: 38px;
padding: 20px 0;
font-weight: 600;
}
.paywall__title-text-accent {
color: var(--strong-blue-text);
}
.paywall__spiritist {
border-bottom: 1px solid var(--pale-lavender);
display: flex;
padding: 0 20px;
}
.paywall__spiritist-dialog {
border-top: 1px solid var(--pale-lavender);
padding: 12px 0;
}
.paywall__spiritist-title {
font-size: 20px;
font-weight: 700;
line-height: 28px;
margin-bottom: 12px;
}
.paywall__spiritist-description {
color: var(--soft-blue-periwinkle);
font-size: 12px;
font-weight: 500;
line-height: 16px;
max-width: 80%;
}
.paywall__spiritist-description-accent {
color: var(--strong-blue-text);
font-size: 16px;
font-weight: 700;
line-height: 24px;
}
.paywall__spiritist-spiritualist {
margin-top: auto;
position: relative;
bottom: -2px;
}
.paywall__spiritist-spiritualist-image {
width: 132px;
}
.paywall__spiritist-spiritualist-chat {
left: 12px;
position: absolute;
top: 10px;
}
.paywall__astrologers {
align-items: center;
background: var(--pale-blue-transparent);
border-bottom: 1px solid var(--pale-lavender);
color: var(--midnight-black);
display: flex;
font-size: 16px;
font-weight: 700;
line-height: 24px;
padding: 12px 20px;
width: 100%;
}
.paywall__astrologers-image {
margin: auto;
}
.paywall__action {
align-items: center;
display: flex;
flex-direction: column;
margin-top: 20px;
padding: 0 20px;
width: 100%;
}
.paywall__action-chats {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 12px;
margin-top: 12px;
}
.paywall__action-title {
color: var(--midnight-black);
font-family: SF Pro Text Regular, sans-serif;
font-size: 14px;
font-weight: 500;
line-height: 18px;
margin-left: 14px;
}
.paywall__action-title-accent {
color: var(--strong-blue-text);
}
.paywall__action-people {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 12px;
margin-top: 12px;
}
.paywall__guarantee {
background-color: var(--pale-blue);
color: var(--midnight-black);
display: flex;
padding: 12px 20px;
position: relative;
width: 100%;
font-family: SF Pro Text Regular, sans-serif;
}
.paywall__guarantee-image {
display: inline;
}
.paywall__guarantee-content {
margin-left: 12px;
}
.paywall__guarantee-title {
color: var(--strong-blue-text);
font-size: 16px;
font-weight: 700;
line-height: 24px;
}
.paywall__guarantee-text {
font-size: 14px;
line-height: 20px;
}
.paywall__work-description {
align-items: center;
display: flex;
flex-direction: column;
margin-top: 30px;
padding: 0 20px;
}
.paywall__work-description-main-title {
color: var(--midnight-black);
font-size: 20px;
font-weight: 700;
line-height: 28px;
margin-bottom: 20px;
text-align: center;
}
.paywall__work-description-item {
align-items: flex-start;
box-sizing: border-box;
-webkit-column-gap: 12px;
column-gap: 12px;
display: flex;
line-height: 1;
margin-bottom: 24px;
position: relative;
}
.paywall__work-description-item:not(:last-child)::before {
background-color: var(--strong-blue-text);
border-radius: 10px;
content: '';
height: calc(100% - 22px);
left: 16px;
position: absolute;
top: 41px;
width: 3px;
}
.paywall__work-description-item:nth-child(3)::before {
background-color: var(--pale-lavender-20);
}
.paywall__work-description-item:nth-child(3) .paywall__work-description-item-image::after {
background-color: var(--strong-blue-text);
border-radius: 50%;
height: calc(100% - 16px);
width: calc(100% - 16px);
}
.paywall__work-description-item:last-child .paywall__work-description-item-image {
background-color: transparent;
}
.paywall__work-description-item:last-child .paywall__work-description-item-image::after {
border: 4px solid var(--pale-lavender-20);
border-radius: 50%;
box-sizing: border-box;
flex: none;
flex-grow: 0;
height: 35px;
order: 0;
width: 35px;
}
.paywall__work-description-item-image {
background-color: var(--pale-lavender-20);
border-radius: 50%;
display: block;
flex-shrink: 0;
height: 35px;
padding: 5px;
position: relative;
width: 35px;
}
.paywall__work-description-item-image::after {
content: '';
height: calc(100% - 10px);
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 10px);
}
.paywall__work-description-item-paragraph {
color: var(--soft-blue-periwinkle);
font-size: 14px;
line-height: 1.4;
}
.paywall__work-description-item-title {
color: var(--strong-blue-text);
font-size: 18px;
font-weight: 700;
line-height: 26px;
text-align: left;
}
.paywall__work-description-button-wrapper {
display: flex;
justify-content: center;
width: 100%;
}
.paywall__included {
margin-top: 20px;
padding: 0 20px;
}
.paywall__included-title {
color: var(--midnight-black);
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
text-align: center;
}
.paywall__included-list {
background-color: var(--pale-blue);
border: 1px solid var(--pale-lavender);
border-radius: 10px;
display: flex;
flex-direction: column;
padding: 16px;
row-gap: 16px;
}
.paywall__included-item {
align-items: center;
column-gap: 8px;
display: flex;
}
.paywall__palm-description {
align-items: center;
display: flex;
flex-direction: column;
margin-top: 30px;
padding: 0 20px;
}
.paywall__palm-description-title {
color: var(--dark-blue);
font-size: 20px;
font-weight: 700;
line-height: 28px;
margin-bottom: 20px;
text-align: center;
}
.paywall__palm-description-title-accent {
color: var(--strong-blue-text);
}
.paywall__palm-description-list {
color: var(--midnight-black);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
line-height: 1;
margin-bottom: 25px;
row-gap: 12px;
}
.paywall__palm-description-item {
align-items: center;
border: 1px solid var(--pale-lavender);
border-radius: 8px;
display: flex;
padding: 16px 16px 16px 0;
width: 100%;
}
.paywall__palm-description-item:nth-child(odd) {
flex-direction: row-reverse;
}
.paywall__palm-description-item:nth-child(even) {
padding: 16px 0 16px 16px;
}
.paywall__palm-description-text {
color: var(--soft-blue-periwinkle);
font-size: 14px;
font-weight: 500;
line-height: 1.3;
padding-left: 17px;
position: relative;
}
.paywall__palm-description-text:not(:last-child) {
margin-bottom: 8px;
}
.paywall__palm-description-text::before {
background-color: var(--pale-lavender-20);
border-radius: 50%;
content: "";
height: 12px;
left: 0;
position: absolute;
top: 4px;
width: 12px;
}
.paywall__palm-description-text::after {
background-color: var(--strong-blue-text);
border-radius: 50%;
content: "";
height: 6px;
left: 3px;
position: absolute;
top: 7px;
width: 6px;
}
.paywall__palm-description-button-wrapper {
display: flex;
justify-content: center;
width: 100%;
}
.paywall__reviews {
align-items: center;
display: flex;
flex-direction: column;
margin: 30px 0;
padding: 0 20px;
}
.paywall__reviews-main-title {
color: var(--midnight-black);
font-size: 20px;
font-weight: 700;
margin-bottom: 36px;
text-align: center;
}
.paywall__reviews-main-title-accent {
color: var(--strong-blue-text);
}
.paywall__reviews-list {
color: var(--midnight-black);
display: flex;
flex-wrap: wrap;
margin-bottom: 25px;
row-gap: 30px;
}
.paywall__reviews-item {
background-color: var(--pale-blue);
border-radius: 8px;
color: var(--midnight-black);
column-gap: 5px;
display: flex;
margin-left: 10px;
padding: 16px;
position: relative;
width: calc(100% - 10px);
}
.paywall__reviews-img-wrapper {
aspect-ratio: 0.8333333333;
border: 2px solid var(--transparent-to-white);
border-radius: 9px;
flex-shrink: 0;
left: -26px;
overflow: hidden;
position: relative;
top: -26px;
width: 95px;
}
.paywall__reviews-img {
height: 100%;
max-width: 50vw;
object-fit: cover;
width: 100%;
}
.paywall__reviews-content {
color: var(--soft-blue);
font-size: 12px;
line-height: 1.3;
margin-bottom: 6px;
}
.paywall__reviews-text {
color: var(--soft-blue-gray);
line-height: 1.3;
margin-bottom: 6px;
}
.paywall__reviews-title {
color: var(--midnight-black);
display: inline-block;
font-size: 16px;
line-height: 1.3;
margin-bottom: 6px;
}
.paywall__reviews-review-name {
font-size: 12px;
}
.paywall__reviews-quotes {
background-size: contain;
height: 32px;
position: absolute;
right: 16px;
top: -16px;
width: 32px;
}
.paywall__logos {
color: var(--midnight-black);
display: flex;
flex-direction: column;
letter-spacing: -0.0024em;
margin: 24px 0 62px;
padding: 0 20px;
text-align: center;
width: 100%;
margin: 0 0 24px;
}
.paywall__logos-title {
font-size: 20px;
font-weight: 700;
line-height: 28px;
margin-bottom: 15px;
}
.paywall__logos-title-accent {
color: var(--strong-blue-text);
}
.paywall__logos-row {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 24px;
}
.paywall__logos-row:last-child {
margin-bottom: 0;
}
.paywall__footer {
align-items: center;
border-top: 1px solid var(--pale-gray);
display: flex;
flex-direction: column;
padding-top: 12px;
width: calc(100% + 14px);
margin: 0 0 24px;
}
.paywall__footer h4 {
font-size: 16px;
line-height: 140%;
margin-bottom: 6px;
}
.paywall__footer-links {
display: flex;
margin-bottom: 8px;
}
.paywall__footer-links div {
align-items: center;
cursor: pointer;
display: flex;
}
.paywall__footer-links > :first-child {
margin-right: 24px;
}
.paywall__footer-links h3 {
color: var(--strong-blue-text);
font-size: 14px;
letter-spacing: 0.0008em;
line-height: 18px;
margin-left: 6px;
}
.paywall__footer-copyright {
font-size: 12px;
letter-spacing: 0.0008em;
line-height: 16px;
text-align: center;
}
.paywall__get-prediction {
align-items: center;
background: var(--pale-blue);
bottom: 0;
box-shadow: 0 -3px 11px rgba(0, 0, 0, .15);
color: var(--soft-blue-gray);
display: flex;
font-size: 14px;
padding: 12px 24px;
position: sticky;
transition: all 0.5s;
width: 100%;
z-index: 10;
}
.paywall__get-prediction-timer {
font-family: "SF Mono Bold, sans-serif";
border-radius: 4px;
background: initial;
display: inline;
margin: 5px;
min-width: 62px;
padding: 0;
}
.paywall__get-prediction-timer > span {
color: var(--strong-blue-text);
font-size: 14px;
font-weight: 700;
line-height: 22px;
}
.paywall__get-prediction-button {
font-weight: 700;
line-height: 26px;
min-height: auto;
min-width: auto;
padding: 6px 8px;
white-space: nowrap;
width: auto;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,139 @@
.premium-bundle-screen {
margin: 0 auto;
position: relative;
max-width: 428px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.premium-bundle-screen__header {
display: flex;
width: 100%;
padding: 24px 0 11px;
justify-content: center;
}
.premium-bundle-screen__content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 0 32px 32px;
padding-bottom: 20px;
}
.premium-bundle-screen__button-skip {
height: 30px;
border: none;
display: flex;
padding: 0 8px;
color: #066fde;
margin-top: 12px;
font-weight: 600;
margin-left: auto;
align-items: center;
background: #eff2fd;
border-radius: 20px;
}
.premium-bundle-screen__title {
margin: 8px 0;
font-size: 20px;
font-weight: 600;
line-height: 26px;
text-align: center;
letter-spacing: .2px;
}
.premium-bundle-screen__subtitle {
font-size: 16px;
line-height: 18px;
text-align: center;
}
.premium-bundle-screen__block-description {
width: 100%;
position: relative;
background: white;
z-index: 3;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 0 8px #0003;
border-radius: 8px;
padding: 16px;
text-align: center;
margin: 24px 0;
gap: 12px;
}
.premium-bundle-screen__block-description p {
font-size: 14px;
line-height: 18px;
}
.premium-bundle-screen__list-title {
font-size: 14px;
line-height: 18px;
font-weight: 700;
}
.premium-bundle-screen__item {
display: flex;
align-items: center;
align-self: flex-start;
}
.premium-bundle-screen__icon {
display: flex;
width: 40px;
height: 40px;
background: #ffeede;
border-radius: 20px;
margin-right: 16px;
align-items: center;
justify-content: center;
}
.premium-bundle-screen__subsection {
width: 100%;
padding: 12px;
border-top: 2px solid #e0e3eb;
margin-bottom: -12px;
}
.premium-bundle-screen__one-time-price {
color: #066fde;
font-weight: 600;
line-height: 24px;
}
.premium-bundle-screen__button {
font-weight: 500;
background: #eff2fd;
justify-content: center;
align-items: center;
display: flex;
padding: 12px 16px;
max-width: 400px;
min-width: 250px;
width: 100%;
min-height: 60px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 18px;
line-height: 20px;
color: #121620;
position: relative;
background: #066fde;
color: #fff!important;
position: relative;
}
.premium-bundle-screen__button svg {
fill: #fff;
margin-right: 8px;
}

View File

@ -0,0 +1,156 @@
import React from "react";
import { useNavigate } from 'react-router-dom';
import './premium-bundle-screen.css';
import routes from '@/routes';
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
export default function PremiumBundleScreen() {
const navigate = useNavigate();
const userHasPremiumBundle = false;
React.useEffect(() => {
if (userHasPremiumBundle) {
navigate(routes.client.home());
}
}, [userHasPremiumBundle]);
const goHome = () => {
navigate(routes.client.home());
};
return (
<div className="premium-bundle-screen">
<div className="premium-bundle-screen__header">
<HeaderLogo />
</div>
<div className="premium-bundle-screen__content">
<button className="premium-bundle-screen__button-skip" onClick={goHome}>Skip &gt;</button>
<span className="premium-bundle-screen__title">Get extra insights with our Premium Bundle</span>
<span className="premium-bundle-screen__subtitle">
Exclusive offer: recommended for get more insights about what future
holds for you.
</span>
<div className="premium-bundle-screen__block-description">
<span className="premium-bundle-screen__list-title">What your Premium Bundle will include:</span>
<div className="premium-bundle-screen__item">
<div className="premium-bundle-screen__icon">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_840_6840)">
<path
d="M19.4064 7.01573L15.4441 6.43996L13.672 2.84952C12.9876 1.46263 11.0085 1.46306 10.3243 2.84948L8.55231 6.43992L4.59001 7.01573C3.0594 7.2381 2.44844 9.12037 3.55553 10.1996L6.42269 12.9944L5.74586 16.9406C5.48444 18.465 7.08564 19.6277 8.45425 18.9084L11.9982 17.0451L15.5423 18.9084C16.909 19.6268 18.512 18.4648 18.2507 16.9406L17.5738 12.9944L20.441 10.1996C21.5483 9.11995 20.9363 7.23806 19.4064 7.01573ZM19.324 9.0539L16.1557 12.1422C15.9672 12.326 15.8812 12.5908 15.9257 12.8503L16.6736 17.2111C16.7111 17.4301 16.4833 17.5955 16.2867 17.4922L12.3704 15.4334C12.1374 15.3109 11.8589 15.3109 11.6259 15.4334L7.70964 17.4922C7.51295 17.5956 7.28519 17.4301 7.32273 17.2111L8.07067 12.8503C8.11516 12.5908 8.02914 12.326 7.84061 12.1422L4.67228 9.0539C4.51314 8.89879 4.60019 8.63104 4.82008 8.59902L9.19858 7.96279C9.45911 7.92491 9.68439 7.76132 9.80092 7.52521L11.7591 3.55757C11.8574 3.35845 12.139 3.35831 12.2373 3.55762L14.1955 7.52521C14.312 7.76132 14.5373 7.92496 14.7978 7.96279L19.1763 8.59902C19.3961 8.63104 19.4831 8.89884 19.324 9.0539Z"
fill="#FF9649"
/>
<path
d="M6.31805 2.21025L5.36128 0.893391C5.1015 0.536016 4.60125 0.456703 4.24388 0.716484C3.88646 0.976172 3.80719 1.47647 4.06692 1.83389L5.02369 3.1507C5.28357 3.50827 5.78381 3.58725 6.1411 3.32761C6.49852 3.06797 6.57778 2.56767 6.31805 2.21025Z"
fill="#FF9649"
/>
<path
d="M3.13954 14.0113C3.00309 13.5911 2.55177 13.361 2.13149 13.4977L0.551992 14.0109C0.131805 14.1475 -0.0981173 14.5987 0.0383827 15.019C0.175117 15.4399 0.62718 15.669 1.04643 15.5326L2.62593 15.0194C3.04616 14.8828 3.27609 14.4315 3.13954 14.0113Z"
fill="#FF9649"
/>
<path
d="M19.7573 0.716518C19.3999 0.456831 18.8996 0.536002 18.6399 0.893424L17.6831 2.21024C17.4234 2.56766 17.5027 3.068 17.8601 3.32764C18.2176 3.58742 18.7179 3.50802 18.9775 3.15074L19.9342 1.83392C20.1939 1.4765 20.1147 0.976159 19.7573 0.716518Z"
fill="#FF9649"
/>
<path
d="M23.4452 14.0109L21.8658 13.4977C21.4456 13.3609 20.9943 13.5911 20.8577 14.0113C20.7212 14.4315 20.9511 14.8829 21.3713 15.0194L22.9508 15.5326C23.3701 15.669 23.8221 15.4398 23.9588 15.019C24.0954 14.5988 23.8654 14.1475 23.4452 14.0109Z"
fill="#FF9649"
/>
<path
d="M12.0021 20.2128C11.5603 20.2128 11.2021 20.5709 11.2021 21.0127V22.6364C11.2021 23.0782 11.5603 23.4364 12.0021 23.4364C12.4439 23.4364 12.8021 23.0782 12.8021 22.6364V21.0127C12.8021 20.5709 12.4439 20.2128 12.0021 20.2128Z"
fill="#FF9649"
/>
</g>
<defs>
<clipPath id="clip0_840_6840">
<rect width="24" height="24" fill="white"></rect>
</clipPath>
</defs>
</svg>
</div>
<p>Guide to Modern Astrology</p>
</div>
<div className="premium-bundle-screen__item">
<div className="premium-bundle-screen__icon">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_840_6862)">
<path
d="M21.0843 1.45852C20.8093 0.613031 20.0141 0 19.0781 0C18.1615 0 17.3799 0.587906 17.0897 1.40625H13.9884C13.6982 0.587906 12.9166 0 12 0C11.0834 0 10.3018 0.587906 10.0116 1.40625H6.91031C6.62006 0.587906 5.83852 0 4.92188 0C3.98587 0 3.19073 0.613031 2.91572 1.45852C1.26216 1.74413 0 3.18792 0 4.92188V21.8906C0 23.0537 0.946266 24 2.10938 24H21.8906C23.0537 24 24 23.0537 24 21.8906V4.92188C24 3.18792 22.7378 1.74413 21.0843 1.45852ZM18.375 2.10938C18.375 1.72167 18.6904 1.40625 19.0781 1.40625C19.4658 1.40625 19.7812 1.72167 19.7812 2.10938V3.51562C19.7812 3.90333 19.4658 4.21875 19.0781 4.21875C18.6904 4.21875 18.375 3.90333 18.375 3.51562V2.10938ZM11.2969 2.10938C11.2969 1.72167 11.6123 1.40625 12 1.40625C12.3877 1.40625 12.7031 1.72167 12.7031 2.10938V3.51562C12.7031 3.90333 12.3877 4.21875 12 4.21875C11.6123 4.21875 11.2969 3.90333 11.2969 3.51562V2.10938ZM4.21875 2.10938C4.21875 1.72167 4.53417 1.40625 4.92188 1.40625C5.30958 1.40625 5.625 1.72167 5.625 2.10938V3.51562C5.625 3.90333 5.30958 4.21875 4.92188 4.21875C4.53417 4.21875 4.21875 3.90333 4.21875 3.51562V2.10938ZM22.5938 21.8906C22.5938 22.2783 22.2783 22.5938 21.8906 22.5938H2.10938C1.72167 22.5938 1.40625 22.2783 1.40625 21.8906V8.48438H22.5938V21.8906ZM22.5938 7.07812H1.40625V4.92188C1.40625 4.00523 1.99411 3.22369 2.8125 2.93344V3.51562C2.8125 4.67873 3.75877 5.625 4.92188 5.625C6.08498 5.625 7.03125 4.67873 7.03125 3.51562V2.8125H9.89062V3.51562C9.89062 4.67873 10.8369 5.625 12 5.625C13.1631 5.625 14.1094 4.67873 14.1094 3.51562V2.8125H16.9688V3.51562C16.9688 4.67873 17.915 5.625 19.0781 5.625C20.2412 5.625 21.1875 4.67873 21.1875 3.51562V2.93344C22.0059 3.22369 22.5938 4.00523 22.5938 4.92188V7.07812Z"
fill="#FF9649"
/>
<path
d="M9.34435 14.2438L11.091 12.4972C11.5319 12.0562 11.2198 11.2969 10.5938 11.2969H6.375C5.98669 11.2969 5.67188 11.6117 5.67188 12C5.67188 12.3883 5.98669 12.7031 6.375 12.7031H8.89628L7.2841 14.3153C6.8431 14.7563 7.15524 15.5156 7.78126 15.5156H8.48438C9.25979 15.5156 9.89064 16.1465 9.89064 16.9219C9.89064 17.6973 9.25979 18.3281 8.48438 18.3281C7.70898 18.3281 7.07813 17.6973 7.07813 16.9219C7.07813 16.5336 6.76332 16.2188 6.375 16.2188C5.98669 16.2188 5.67188 16.5336 5.67188 16.9219C5.67188 18.4727 6.93357 19.7344 8.48438 19.7344C10.0352 19.7344 11.2969 18.4727 11.2969 16.9219C11.2969 15.6708 10.4759 14.608 9.34435 14.2438Z"
fill="#FF9649"
/>
<path
d="M19.0312 18.3283H16.9219V12.0001C16.9219 11.3766 16.1641 11.0602 15.7216 11.503L12.9091 14.3155C12.6345 14.5901 12.6345 15.0352 12.9091 15.3098C13.1836 15.5844 13.6289 15.5844 13.9035 15.3098L15.5156 13.6976V18.3283H13.4062C13.0179 18.3283 12.7031 18.6431 12.7031 19.0314C12.7031 19.4197 13.0179 19.7345 13.4062 19.7345H19.0312C19.4196 19.7345 19.7344 19.4197 19.7344 19.0314C19.7344 18.6431 19.4196 18.3283 19.0312 18.3283Z"
fill="#FF9649"
/>
</g>
<defs>
<clipPath id="clip0_840_6862">
<rect width="24" height="24" fill="white"></rect>
</clipPath>
</defs>
</svg>
</div>
<p>Annual Forecast for 2024</p>
</div>
<div className="premium-bundle-screen__subsection">
<span className="premium-bundle-screen__one-time-price">One-time price of 19!</span>
<p>Original price is 45. Save 58%!</p>
</div>
<div className="premium-bundle-screen__subsection">
<p>
These plans are <b>yours to keep</b> even if you decide Hint isnt
right for you.
</p>
</div>
</div>
<button className="premium-bundle-screen__button premium-bundle-screen__button-active premium-bundle-screen__buy-button">
<svg
width="13"
height="16"
viewBox="0 0 13 16"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M11.5556 6.24219H1.44444C0.6467 6.24219 0 6.97481 0 7.87855V13.6058C0 14.5096 0.6467 15.2422 1.44444 15.2422H11.5556C12.3533 15.2422 13 14.5096 13 13.6058V7.87855C13 6.97481 12.3533 6.24219 11.5556 6.24219Z"/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.5 0.242188C4.29086 0.242188 2.5 2.03305 2.5 4.24219V8.24219H10.5V4.24219C10.5 2.03305 8.70914 0.242188 6.5 0.242188ZM6.5 1.24219C4.84315 1.24219 3.5 2.58533 3.5 4.24219V7.24219H9.5V4.24219C9.5 2.58533 8.15685 1.24219 6.5 1.24219Z"
/>
</svg>{" "}
Buy now
</button>
</div>
</div>
);
}

View File

@ -0,0 +1,58 @@
.progress-bar {
align-items: center;
display: flex;
flex-direction: column;
gap: 12px;
justify-content: center;
margin-top: 12px;
padding: 0 24px 5px;
width: 100%;
}
.progress-bar__current-step {
color: var(--strong-blue-80);
font-size: 14px;
font-weight: 600;
line-height: 18px;
}
.progress-bar__container {
background: var(--pale-lavender);
height: 4px;
margin-bottom: 2px;
position: relative;
width: 100%;
}
.progress-bar__container::before, .progress-bar__container::after {
border-radius: 50%;
content: "";
height: 16px;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 16px;
}
.progress-bar__container::before {
background: var(--progress-line);
}
.progress-bar__container::after {
background: var(--pale-lavender);
right: 0;
}
.progress-bar__filler {
background: linear-gradient(90.25deg, var(--progress-line) 0, #4455f2 473.72%);
border-radius: 8px;
height: 6px;
position: absolute;
top: 50%;
transform: translateY(-50%);
transition: all 0.5s ease;
}
.progress-bar_finish .progress-bar__container::after {
background: var(--progress-line);
}

View File

@ -0,0 +1,30 @@
import './progress-bar.css';
import useSteps from '../../../hooks/palmistry/use-steps';
type Props = {
step: number;
};
export default function ProgressBar(props: Props) {
const steps = useSteps();
const lastStep = steps.progressBarRange[1];
const progressPercentage = (props.step / lastStep) * 100;
const className = ['progress-bar'];
if (props.step === lastStep) {
className.push('progress-bar_finish');
}
return (
<div className={className.join(' ')}>
<div className="progress-bar__current-step">{props.step}/{lastStep}</div>
<div className="progress-bar__container">
<div className="progress-bar__filler" style={{ width: `${progressPercentage}%` }}/>
</div>
</div>
);
}

View File

@ -0,0 +1,223 @@
.scanned-photo {
display: flex;
height: 477px;
justify-content: center;
position: relative;
width: 291px;
}
.scanned-photo__container {
height: 477px;
position: relative;
width: 291px;
z-index: 2;
}
.scanned-photo__stick {
animation: scanned-photo-stick-move 5.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 14.5s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
background-color: var(--strong-blue-text);
height: 2px;
left: -2px;
opacity: 0;
position: absolute;
width: 96px;
z-index: 5;
}
.scanned-photo__image {
height: 100%;
object-fit: cover;
width: 100%;
}
.scanned-photo__svg-objects {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.scanned-photo__finger-point {
animation: finger-show 1s linear;
animation-fill-mode: forwards;
transform: scale(0);
transform-origin: center center;
}
.scanned-photo__finger-point_thumb {
animation-delay: 0s;
}
.scanned-photo__finger-point_index {
animation-delay: 1s;
}
.scanned-photo__finger-point_middle {
animation-delay: 2s;
}
.scanned-photo__finger-point_ring {
animation-delay: 3s;
}
.scanned-photo__finger-point_little {
animation-delay: 4s;
}
.scanned-photo__line {
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 3px;
fill-rule: evenodd;
clip-rule: evenodd;
stroke-miterlimit: 1.5;
stroke-dasharray: 500;
stroke: #fff;
fill: none;
animation: line-show 1.5s linear;
animation-fill-mode: forwards;
}
.scanned-photo__line_heart {
stroke: #f8d90f;
animation-delay: 4.5s;
}
.scanned-photo__line_life {
stroke: #e51c39;
}
.scanned-photo__line_head {
stroke: #00d114;
animation-delay: 1.5s;
}
.scanned-photo__line_fate {
stroke: #05ced8;
animation-delay: 3s;
}
.scanned-photo__decoration {
align-items: center;
display: flex;
justify-content: center;
opacity: 0;
animation: scanned-photo-opacity 1.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 12s;
animation-fill-mode: forwards;
height: 220px;
margin-top: -10px;
position: absolute;
width: 220px;
}
.scanned-photo__decoration__corners {
animation: scanned-photo-corners-opacity 1.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-delay: 13.5s;
animation-fill-mode: forwards;
background: linear-gradient(to right, var(--strong-blue-text) 2px, transparent 2px) 0 0, linear-gradient(to right, var(--strong-blue-text) 2px, transparent 2px) 0 100%, linear-gradient(to left, var(--strong-blue-text) 2px, transparent 2px) 100% 0, linear-gradient(to left, var(--strong-blue-text) 2px, transparent 2px) 100% 100%, linear-gradient(to bottom, var(--strong-blue-text) 2px, transparent 2px) 0 0, linear-gradient(to bottom, var(--strong-blue-text) 2px, transparent 2px) 100% 0, linear-gradient(to top, var(--strong-blue-text) 2px, transparent 2px) 0 100%, linear-gradient(to top, var(--strong-blue-text) 2px, transparent 2px) 100% 100%;
background-repeat: no-repeat;
background-size: 15px 15px;
height: 100%;
position: relative;
width: 100%;
align-items: center;
display: flex;
justify-content: center;
opacity: 0;
}
.scanned-photo__decoration__corners > svg {
position: absolute;
}
.scanned-photo__decoration__light-blue-circle {
align-items: center;
background: var(--pale-blue);
border-radius: 50%;
display: flex;
height: 200px;
justify-content: center;
position: absolute;
width: 200px;
}
.scanned-photo_small {
animation: scanned-photo-resize 1.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-fill-mode: forwards;
}
.scanned-photo_small .scanned-photo__container {
animation: scanned-photo-container-resize 1.5s cubic-bezier(0.37, 0, 0.63, 1);
animation-fill-mode: forwards;
}
@keyframes scanned-photo-resize {
100% {
height: 207px;
}
}
@keyframes scanned-photo-container-resize {
100% {
border: 3px solid #fff;
height: 159px;
margin-top: 20px;
width: 97px;
}
}
@keyframes scanned-photo-opacity {
100% {
opacity: 1;
}
}
@keyframes scanned-photo-corners-opacity {
10% {
opacity: 0;
}
20% {
opacity: 0.7;
}
40% {
opacity: 0.3;
}
50% {
opacity: 0.6;
}
100% {
opacity: 1;
}
}
@keyframes scanned-photo-stick-move {
0% {
opacity: 1;
top: 0;
}
50% {
opacity: 1;
top: 100%;
}
100% {
opacity: 1;
top: 0;
}
}
@keyframes finger-show {
100% {
transform: scale(1);
}
}
@keyframes line-show {
100% {
stroke-dashoffset: 0;
}
}

View File

@ -0,0 +1,180 @@
import './scanned-photo.css';
type Props = {
photo: string;
small: boolean;
displayLines: boolean;
};
export default function StepScanPhoto(props: Props) {
const className = ['scanned-photo'];
if (props.small) {
className.push('scanned-photo_small');
}
return (
<div className={className.join(' ')}>
<div className="scanned-photo__container">
<div className="scanned-photo__stick" />
<img className="scanned-photo__image" alt="PalmIcon" src={props.photo} width={291} height={477}/>
<svg viewBox="0 0 291 477" className="scanned-photo__svg-objects">
<svg x="235" y="211" height="24px" width="24px">
<circle
cx="50%"
cy="50%"
r="11"
fill="white"
opacity="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_thumb"
/>
<circle
cx="50%"
cy="50%"
r="5"
fill="#066FDE"
stroke="white"
strokeWidth="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_thumb"
/>
</svg>
<svg x="172" y="38" height="24px" width="24px">
<circle
cx="50%"
cy="50%"
r="11"
fill="white"
opacity="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_index"
/>
<circle
cx="50%"
cy="50%"
r="5"
fill="#066FDE"
stroke="white"
strokeWidth="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_index"
/>
</svg>
<svg x="125" y="10" height="24px" width="24px">
<circle
cx="50%"
cy="50%"
r="11"
fill="white"
opacity="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_middle"
/>
<circle
cx="50%"
cy="50%"
r="5"
fill="#066FDE"
stroke="white"
strokeWidth="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_middle"
/>
</svg>
<svg x="81" y="41" height="24px" width="24px">
<circle
cx="50%"
cy="50%"
r="11"
fill="white"
opacity="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_ring"
/>
<circle
cx="50%"
cy="50%"
r="5"
fill="#066FDE"
stroke="white"
strokeWidth="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_ring"
/>
</svg>
<svg x="32" y="113" height="24px" width="24px">
<circle
cx="50%"
cy="50%"
r="11"
fill="white"
opacity="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_little"
/>
<circle
cx="50%"
cy="50%"
r="5"
fill="#066FDE"
stroke="white"
strokeWidth="0.3"
className="scanned-photo__finger-point scanned-photo__finger-point_little"
/>
</svg>
{props.displayLines && (
<>
<path
className="scanned-photo__line scanned-photo__line_heart"
d="M 95 334 L 99 330 L 104 327 L 109 323 L 113 319 L 118 315 L 123 311 L 128 308 L 132 304 L 137 301 L 142 298 L 146 296 L 151 293 L 156 291 L 160 289 L 165 287 L 170 286 L 174 284 L 179 283 L 184 283 L 189 282 L 193 282 L 198 283 L 203 284 L 207 285"
style={{ strokeDasharray: 128.14, strokeDashoffset: 128.14 }}
/>
<path
className="scanned-photo__line scanned-photo__line_life"
d="M 205 283 L 193 291 L 181 299 L 170 306 L 160 314 L 153 322 L 147 329 L 143 337 L 139 345 L 136 352 L 133 360 L 130 368 L 128 376 L 126 383 L 125 391 L 125 399 L 126 406 L 128 414 L 132 422 L 137 429 L 143 437 L 149 445 L 156 452"
style={{ strokeDasharray: 211.483, strokeDashoffset: 211.483 }}
/>
<path
className="scanned-photo__line scanned-photo__line_head"
d="M 24 316 L 29 316 L 34 315 L 38 315 L 43 314 L 48 313 L 52 312 L 57 312 L 62 311 L 67 310 L 71 309 L 76 307 L 81 305 L 85 303 L 90 301 L 95 298 L 99 296 L 104 294 L 109 292 L 113 289 L 118 287 L 123 284 L 128 280 L 132 276 L 137 271 L 142 265"
style={{ strokeDasharray: 132.6, strokeDashoffset: 132.6 }}
/>
<path
className="scanned-photo__line scanned-photo__line_fate"
d="M 134 260 L 129 299 L 125 306 L 122 314 L 120 322 L 118 329 L 116 337 L 115 345 L 114 352"
style={{ strokeDasharray: 94.8313, strokeDashoffset: 94.8313 }}
/>
</>
)}
</svg>
</div>
<div className="scanned-photo__decoration">
<div className="scanned-photo__decoration__corners">
<div className="scanned-photo__decoration__light-blue-circle" />
<svg
version="1.1"
id="L3"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 220 220"
enableBackground="new 0 0 0 0"
>
<circle fill="none" stroke="#EFF2FD" strokeWidth="2" cx="110" cy="110" r="105"/>
<circle fill="#066fde" stroke="none" strokeWidth="3" cx="110" cy="215" r="4">
<animateTransform
attributeName="transform"
dur="15s"
type="rotate"
from="0 110 110"
to="360 110 110"
repeatCount="indefinite"
></animateTransform>
</circle>
</svg>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,206 @@
import React from 'react';
import { useDispatch } from 'react-redux';
import { actions } from '@/store';
import InputWrapper from '../input-wrapper/input-wrapper';
import InputItem from '../input-item/input-item';
import Button from '../button/button';
import useSteps from '../../../hooks/palmistry/use-steps';
enum Field {
year = 'year',
month = 'month',
day = 'day',
}
const dateDivider = '-';
export default function StepBirthdate() {
const steps = useSteps();
const dispatch = useDispatch();
const [year, setYear] = React.useState('');
const [month, setMonth] = React.useState('');
const [day, setDay] = React.useState('');
const [fieldsWithErrors, setFieldsWithErrors] = React.useState(new Set as Set<Field>);
const [errorIsVisible, setErrorIsVisible] = React.useState(false);
React.useEffect(() => {
const [storedYear, storedMonth, storedDay] = steps.storedValue.split(dateDivider);
if (storedYear) setYear(storedYear);
if (storedMonth) setMonth(storedMonth);
if (storedDay) setDay(storedDay);
}, [steps.storedValue]);
const onChangeYear = (value: string) => {
const yearNumber = Number(value);
if (Number.isNaN(yearNumber) || yearNumber > new Date().getFullYear()) {
return;
}
setFieldsWithErrors((prevValue) => {
const newValue = new Set(prevValue);
if (value !== '' && yearNumber < 1924) {
newValue.add(Field.year);
} else {
newValue.delete(Field.year);
}
return newValue;
});
setYear(value);
};
const onChangeMonth = (value: string) => {
const monthNumber = Number(Number(value).toString().replace(/\D/g, '').slice(0, 2));
if (Number.isNaN(monthNumber) || monthNumber > 12) {
return;
}
setFieldsWithErrors((prevValue) => {
const newValue = new Set(prevValue);
if (value !== '' && (monthNumber < 1 || monthNumber > 12)) {
newValue.add(Field.year);
} else {
newValue.delete(Field.year);
}
return newValue;
});
if (monthNumber < 10) {
setMonth(`0${monthNumber}`);
} else {
setMonth(`${monthNumber}`);
}
};
const onChangeDay = (value: string) => {
const dayNumber = Number(value);
const monthNumber = Number(month);
setFieldsWithErrors((prevValue) => {
const newValue = new Set(prevValue);
if (value !== '' && dayNumber === 0) {
newValue.add(Field.day);
} else {
newValue.delete(Field.day);
}
return newValue;
});
if (
Number.isNaN(dayNumber) ||
!monthNumber ||
monthNumber === 2 && dayNumber > 29 ||
[4, 6, 9, 11].includes(monthNumber) && dayNumber > 30 ||
dayNumber > 31
) {
return;
}
if (dayNumber < 10) {
setDay(`0${dayNumber}`);
} else {
setDay(`${dayNumber}`);
}
};
const onFocus = (field: Field) => {
if (fieldsWithErrors.has(field) && fieldsWithErrors.size === 1) {
setErrorIsVisible(false);
}
};
const onBlur = (field: Field) => {
if (fieldsWithErrors.has(field)) {
setErrorIsVisible(true);
}
};
const formIsValid = Boolean(year && month && day && !fieldsWithErrors.size);
const onNext = () => {
if (!formIsValid) return;
const birthdate = [year, month, day].join(dateDivider);
dispatch(actions.form.addDate(birthdate));
steps.saveCurrent(birthdate);
steps.goNext();
};
return (
<>
<h3 className="palmistry-container__header">Whats your date of birth?</h3>
<p className="palmistry-container__description">
Your birth date reveals your core personality traits, needs and desires.
</p>
<div className="palmistry-container__form-birthday">
<InputWrapper>
<InputItem
label="Year"
placeholder="YYYY"
inputMode="numeric"
maxLength={4}
type="text"
value={year}
onChange={onChangeYear}
onFocus={() => onFocus(Field.year)}
onBlur={() => onBlur(Field.year)}
/>
<InputItem
label="Month"
placeholder="MM"
inputMode="numeric"
type="text"
value={month}
onChange={onChangeMonth}
onFocus={() => onFocus(Field.month)}
onBlur={() => onBlur(Field.month)}
/>
<InputItem
label="Day"
placeholder="DD"
inputMode="numeric"
type="text"
value={day}
onChange={onChangeDay}
onFocus={() => onFocus(Field.day)}
onBlur={() => onBlur(Field.day)}
/>
</InputWrapper>
<h3
className={[
'palmistry-container__error-text',
errorIsVisible ? 'palmistry-container__error-text_visible' : '',
].join(' ')}
>Date not found. Please check your details and try again.</h3>
</div>
<Button
type="button"
disabled={!formIsValid}
onClick={onNext}
active
>
Next
</Button>
</>
);
}

View File

@ -0,0 +1,82 @@
import Button from '../button/button';
import ColorCircle from '../color-circle/color-circle';
import useSteps, { ColorYouLikeChoice } from '../../../hooks/palmistry/use-steps';
export default function StepColorYouLike() {
const steps = useSteps();
const onNext = (choice: ColorYouLikeChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h3>Which color do you like the most?</h3>
</div>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Red}
onClick={() => onNext(ColorYouLikeChoice.Red)}
>
<ColorCircle color="rgb(255, 87, 88)"/>
<span>Red</span>
</Button>
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Yellow}
onClick={() => onNext(ColorYouLikeChoice.Yellow)}
>
<ColorCircle color="rgb(255, 247, 61)"/>
<span>Yellow</span>
</Button>
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Blue}
onClick={() => onNext(ColorYouLikeChoice.Blue)}
>
<ColorCircle color="rgb(6, 111, 222)"/>
<span>Blue</span>
</Button>
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Orange}
onClick={() => onNext(ColorYouLikeChoice.Orange)}
>
<ColorCircle color="rgb(255, 168, 0)"/>
<span>Orange</span>
</Button>
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Green}
onClick={() => onNext(ColorYouLikeChoice.Green)}
>
<ColorCircle color="rgb(117, 219, 156)"/>
<span>Green</span>
</Button>
<Button
type="button"
active={steps.storedValue === ColorYouLikeChoice.Violet}
onClick={() => onNext(ColorYouLikeChoice.Violet)}
>
<ColorCircle color="rgb(151, 71, 255)"/>
<span>Violet</span>
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,45 @@
import Button from '../button/button';
import useSteps, { DecisionsChoice } from '../../../hooks/palmistry/use-steps';
export default function StepDecisions() {
const steps = useSteps();
const onNext = (choice: DecisionsChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h3>Do you make decisions with your head or your heart?</h3>
</div>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === DecisionsChoice.Heart}
onClick={() => onNext(DecisionsChoice.Heart)}
>
Heart
</Button>
<Button
type="button"
active={steps.storedValue === DecisionsChoice.Head}
onClick={() => onNext(DecisionsChoice.Head)}
>
Head
</Button>
<Button
type="button"
active={steps.storedValue === DecisionsChoice.Both}
onClick={() => onNext(DecisionsChoice.Both)}
>
Both
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,165 @@
import React from 'react';
import { useTranslation } from "react-i18next";
import { useDispatch } from "react-redux";
import { Step } from '@/hooks/palmistry/use-steps';
import { useAuth } from "@/auth";
import { useApi, ApiError, extractErrorMessage } from "@/api";
import useSteps from '@/hooks/palmistry/use-steps';
import Button from '@/components/palmistry/button/button';
import Input from '@/components/palmistry/input/input';
import { getClientTimezone } from "@/locales";
import { actions } from "@/store";
import Title from "@/components/Title";
import ErrorText from "@/components/ErrorText";
import Loader, { LoaderColor } from "@/components/Loader";
const emailRegex = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
export default function StepEmail() {
const api = useApi();
const { signUp } = useAuth();
const { t, i18n } = useTranslation();
const dispatch = useDispatch();
const steps = useSteps();
const [email, setEmail] = React.useState(steps.storedValue);
const [emailIsValid, setEmailIsValid] = React.useState(false);
const [isLoading, setIsLoading] = React.useState(false);
const [isAuth, setIsAuth] = React.useState(false);
const [apiError, setApiError] = React.useState<ApiError | null>(null);
const [error, setError] = React.useState<boolean>(false);
const timezone = getClientTimezone();
const locale = i18n.language;
const onChangeEmail = (value: string) => {
setEmail(value);
};
React.useEffect(() => {
if (steps.storedValue) setEmail(steps.storedValue);
}, [steps.storedValue]);
React.useEffect(() => {
const emailIsValid = email.match(emailRegex) !== null;
setEmailIsValid(emailIsValid);
if (emailIsValid) {
dispatch(actions.form.addEmail(email));
}
}, [email]);
const authorization = async () => {
try {
setIsLoading(true);
const auth = await api.auth({ email, timezone, locale });
const { auth: { token, user } } = auth;
signUp(token, user);
const payload = {
user: {
profile_attributes: {
birthday: steps.getStoredValue(Step.Birthdate),
gender: steps.getStoredValue(Step.Gender),
relationship_status: steps.getStoredValue(Step.RelationshipStatus),
},
},
token,
};
const updatedUser = await api.updateUser(payload).catch((error) => console.log("Error: ", error));
if (updatedUser?.user) dispatch(actions.user.update(updatedUser.user));
dispatch(actions.status.update("registred"));
setIsLoading(false);
setIsAuth(true);
} catch (error) {
console.error(error);
if (error instanceof ApiError) {
setApiError(error as ApiError);
} else {
setError(true);
}
setIsLoading(false);
}
};
const onNext = async () => {
await authorization();
steps.saveCurrent(email);
steps.goNext();
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h2>Enter your email to get your advanced Palmistry reading with AURA</h2>
</div>
<Input
className="palmistry-container__input"
placeholder="You Email"
type="text"
value={email}
onChange={onChangeEmail}
floatingPlaceholder
/>
<div className="palmistry-container__description">
<h3>We dont share any personal information.</h3>
</div>
<div className="palmistry-container__policy">
<p>
By clicking "Continue" below you agree to AURA{' '}
<a href="https://aura.wit.life/terms" target="_blank" rel="noreferrer nofollow">
EULA
</a>{' '}
and{' '}
<a href="https://aura.wit.life/privacy" target="_blank" rel="noreferrer nofollow">
Privacy Policy
</a>
.
</p>
</div>
<Button
className="palmistry-container__button"
type="button"
active={emailIsValid}
disabled={!emailIsValid}
onClick={onNext}
>
{isLoading && <Loader color={LoaderColor.White} />}
{!isLoading && !(!apiError && !error && !isLoading && isAuth) && t("_continue")}
{!apiError && !error && !isLoading && isAuth && (
<img
style={{ height: "30px", width: "auto" }}
src="/SuccessIcon.png"
alt="Success Icon"
/>
)}
</Button>
{isLoading && <Loader color={LoaderColor.White} />}
{(error || apiError) && (
<Title variant="h3" style={{ color: "red", margin: 0 }}>
Something went wrong
</Title>
)}
{apiError && (
<ErrorText
size="medium"
isShown={Boolean(apiError)}
message={apiError ? extractErrorMessage(apiError) : null}
/>
)}
</>
);
}

View File

@ -0,0 +1,39 @@
import Button from '../button/button';
import useSteps, { GenderChoice } from '../../../hooks/palmistry/use-steps';
export default function StepGender() {
const steps = useSteps();
const onNext = (choice: GenderChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<h3 className="palmistry-container__header">Whats your gender?</h3>
<p className="palmistry-container__description">
In Palmistry, everyone is a blend of masculine and feminine, so it helps to know yours.
</p>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === GenderChoice.Male}
onClick={() => onNext(GenderChoice.Male)}
>
Male
</Button>
<Button
type="button"
active={steps.storedValue === GenderChoice.Female}
onClick={() => onNext(GenderChoice.Female)}
>
Female
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,238 @@
import React from 'react';
import Button from '../button/button';
import { Step } from '@/hooks/palmistry/use-steps';
import useSteps, { DecisionsChoice } from '@/hooks/palmistry/use-steps';
import useZodiacSign, { ZodiacSign } from '@/hooks/palmistry/use-zodiac-sign';
export default function StepGuidancePlan() {
const steps = useSteps();
const { getSignByDate, getDecisionMakingStatistics } = useZodiacSign();
const storedBirthdate = steps.getStoredValue(Step.Birthdate);
const storedDecisionChoice = steps.getStoredValue(Step.Decisions);
const [zodiacSign, setZodiacSign] = React.useState<ZodiacSign | null>(null);
const [decisionMakingStatistics, setDecisionMakingStatistics] = React.useState<number>(0);
React.useEffect(() => {
if (storedBirthdate) {
const [storedMonth, storedDay] = storedBirthdate.split('-').slice(1).map(Number);
const sign = getSignByDate(storedMonth, storedDay);
setZodiacSign(sign);
setDecisionMakingStatistics(getDecisionMakingStatistics(sign)[storedDecisionChoice as DecisionsChoice]);
}
}, [storedBirthdate]);
const onBack = () => {
steps.goBack();
};
const onNext = () => {
steps.goNext();
};
return (
<>
{steps.getStoredValue(Step.Decisions) === DecisionsChoice.Heart && (
<>
<svg width="251" height="250" viewBox="0 0 251 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="gradient_svg"
x1="48"
y1="-4.15258e-06"
x2="48"
y2="86"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FDDAA6" />
<stop offset="1" stopColor="#DEB475" />
</linearGradient>
</defs>
<rect width="250" height="250" transform="translate(0.5)" fill="" />
<path
d="M70.3196 21H69.6094C69.1832 21 68.8281 21.3073 68.8281 21.7169C68.473 26.5306 63.2173 31.4467 58.2102 31.8905C57.8196 31.9246 57.5 32.266 57.5 32.6415V33.3585C57.5 33.7681 57.8196 34.0754 58.2457 34.1095C63.2173 34.4509 68.2954 39.4011 68.8281 44.2148C68.8636 44.6586 69.2543 45 69.7514 45H70.2486C70.7457 45 71.1364 44.6586 71.1719 44.1807C71.598 38.7866 76.108 34.3485 81.7188 34.0754C82.1804 34.0413 82.5 33.6999 82.5 33.256V32.6415C82.5 32.1977 82.1449 31.8563 81.7188 31.8222C76.0725 31.5491 71.527 27.0768 71.1719 21.6145C71.1009 21.3073 70.7457 21 70.3196 21Z"
fill="rgba(222, 229, 249, 0.7)"
/>
<path
d="M133.499 52.6187C129.705 52.6187 126.642 49.556 126.642 45.7619C126.642 45.3352 126.307 45 125.881 45C125.454 45 125.119 45.3352 125.119 45.7619C125.119 49.556 122.056 52.6187 118.262 52.6187C117.835 52.6187 117.5 52.9539 117.5 53.3805C117.5 53.8072 117.835 54.1424 118.262 54.1424C122.056 54.1424 125.119 57.2051 125.119 60.9992C125.119 61.4258 125.454 61.761 125.881 61.761C126.307 61.761 126.642 61.4258 126.642 60.9992C126.642 57.2051 129.705 54.1424 133.499 54.1424C133.926 54.1424 134.261 53.8072 134.261 53.3805C134.261 52.9539 133.926 52.6187 133.499 52.6187Z"
fill="rgba(222, 229, 249, 0.3)"
/>
<path
d="M209.748 43.8802C202.338 43.8802 196.356 37.8983 196.356 30.488C196.356 29.6547 195.701 29 194.868 29C194.035 29 193.38 29.6547 193.38 30.488C193.38 37.8983 187.398 43.8802 179.988 43.8802C179.155 43.8802 178.5 44.5349 178.5 45.3682C178.5 46.2015 179.155 46.8562 179.988 46.8562C187.398 46.8562 193.38 52.838 193.38 60.2484C193.38 61.0817 194.035 61.7364 194.868 61.7364C195.701 61.7364 196.356 61.0817 196.356 60.2484C196.356 52.838 202.338 46.8562 209.748 46.8562C210.582 46.8562 211.236 46.2015 211.236 45.3682C211.236 44.5349 210.582 43.8802 209.748 43.8802Z"
fill="rgba(222, 229, 249, 0.45)"
/>
<rect x="18.0527" y="151" width="230" height="6" rx="3" transform="rotate(15 18.0527 151)" fill="#DEE5F9" />
<g transform="translate(5, 35)">
<path
d="M167.888 72C177.055 72.0008 185.509 76.9012 190 84.8187C194.491 76.9012 202.945 72.0008 212.112 72C226.133 72 237.5 84.8837 237.5 98.7736C237.5 133.66 190 158 190 158C190 158 142.5 133.66 142.5 98.7736C142.5 84.8837 153.867 72 167.888 72Z"
fill="#BCC9ED"
/>
</g>
<circle cx="126.5" cy="201" r="16" fill="#DEE5F9"/>
<path
d="M55.4669 64C50.7008 64 46.837 67.8679 46.837 72.6391C46.837 72.8876 46.8499 73.1329 46.8704 73.3759C46.0168 73.1897 45.1313 73.0887 44.2219 73.0887C37.3845 73.0887 31.8418 78.6375 31.8418 85.4822C31.8418 87.0153 32.1217 88.4824 32.63 89.8377C26.3122 90.3992 21.3579 95.7087 21.3579 102.179C21.3579 106.286 23.3545 109.924 26.4277 112.18C23.3527 113.197 20.9798 115.912 20.5637 119.344C20.0106 123.905 23.1168 128.066 27.5736 128.881C26.1889 130.94 25.3805 133.42 25.3805 136.089C25.3805 143.227 31.1609 149.014 38.2914 149.014C40.6108 149.014 42.7854 148.398 44.6666 147.326C45.5642 151.824 49.5294 155.214 54.2861 155.214C59.7042 155.214 64.0966 150.817 64.0966 145.393V72.6391C64.0966 67.8679 60.233 64 55.4669 64V64Z"
fill="#dee5f9"
/>
<path
d="M53.6714 124.307C53.3905 123.65 52.6295 123.345 51.9723 123.626C49.9927 124.471 48.3593 125.976 47.3529 127.872C45.4083 127.413 43.3752 127.584 41.5032 128.384C40.8456 128.665 40.5404 129.426 40.8212 130.083C41.1021 130.74 41.8633 131.046 42.5203 130.765C44.1984 130.048 46.0545 130.026 47.7469 130.705C49.439 131.383 50.7646 132.679 51.4802 134.355C51.6585 134.773 51.7953 135.207 51.887 135.647C52.03 136.334 52.6926 136.779 53.3784 136.658C53.3917 136.655 53.4051 136.653 53.4185 136.65C54.1184 136.504 54.5677 135.819 54.4216 135.119C54.2953 134.512 54.1066 133.913 53.8612 133.338C53.0322 131.396 51.6073 129.826 49.7896 128.818C50.5264 127.57 51.6484 126.58 52.9895 126.006C53.647 125.726 53.9523 124.965 53.6714 124.307Z"
fill="#DEE5F9"
/>
<path
d="M47.0581 99.4033C47.0463 99.4275 47.0346 99.4517 47.0211 99.4753C46.3604 100.789 45.9734 102.257 45.9228 103.803C45.8548 105.876 46.4006 107.895 47.5008 109.643C47.8818 110.248 47.7 111.047 47.095 111.428C46.8808 111.563 46.6423 111.627 46.4065 111.627C45.9765 111.627 45.5558 111.413 45.3099 111.022C43.9329 108.835 43.2501 106.31 43.3352 103.718C43.3892 102.068 43.7513 100.489 44.3695 99.0412C42.3818 96.5661 41.3479 93.4023 41.5191 90.225C41.5576 89.511 42.1719 88.9644 42.8815 89.0018C43.5956 89.0403 44.1432 89.6503 44.1047 90.3641C43.9868 92.5527 44.5847 94.7333 45.7678 96.5619C47.4346 94.252 49.8632 92.5029 52.7624 91.6868C53.4505 91.4931 54.1656 91.894 54.3595 92.5822C54.5531 93.2704 54.1523 93.9853 53.4639 94.179C50.6181 94.9801 48.3399 96.9049 47.0581 99.4033V99.4033Z"
fill="#DEE5F9"
/>
<path
d="M74.1308 64C78.8968 64 82.7607 67.8679 82.7607 72.6391C82.7607 72.8876 82.7478 73.1329 82.7272 73.3759C83.5808 73.1897 84.4664 73.0887 85.3758 73.0887C92.2131 73.0887 97.7559 78.6375 97.7559 85.4822C97.7559 87.0153 97.476 88.4824 96.9676 89.8377C103.285 90.3992 108.24 95.7087 108.24 102.179C108.24 106.286 106.243 109.924 103.17 112.18C106.245 113.197 108.618 115.912 109.034 119.344C109.587 123.905 106.481 128.066 102.024 128.881C103.409 130.94 104.217 133.42 104.217 136.089C104.217 143.227 98.4368 149.014 91.3063 149.014C88.9869 149.014 86.8122 148.398 84.9311 147.326C84.0334 151.824 80.0683 155.214 75.3116 155.214C69.8934 155.214 65.501 150.817 65.501 145.393V72.6391C65.501 67.8679 69.3647 64 74.1308 64V64Z"
fill="#dee5f9"
/>
<path
d="M75.9262 124.307C76.2071 123.65 76.9681 123.345 77.6253 123.626C79.6049 124.471 81.2383 125.976 82.2448 127.872C84.1893 127.413 86.2225 127.584 88.0945 128.384C88.752 128.665 89.0573 129.426 88.7764 130.083C88.4956 130.74 87.7343 131.046 87.0773 130.765C85.3993 130.048 83.5432 130.026 81.8508 130.705C80.1586 131.383 78.833 132.679 78.1174 134.355C77.9391 134.773 77.8023 135.207 77.7106 135.647C77.5676 136.334 76.9051 136.779 76.2192 136.658C76.206 136.655 76.1926 136.653 76.1792 136.65C75.4793 136.504 75.03 135.819 75.176 135.119C75.3023 134.512 75.491 133.913 75.7364 133.338C76.5654 131.396 77.9904 129.826 79.808 128.818C79.0712 127.57 77.9493 126.58 76.6082 126.006C75.9506 125.726 75.6454 124.965 75.9262 124.307Z"
fill="#DEE5F9"
/>
<path
d="M82.5396 99.4033C82.5513 99.4275 82.5631 99.4517 82.5765 99.4753C83.2373 100.789 83.6243 102.257 83.6749 103.803C83.7429 105.876 83.1971 107.895 82.0968 109.643C81.7159 110.248 81.8976 111.047 82.5026 111.428C82.7168 111.563 82.9554 111.627 83.1912 111.627C83.6212 111.627 84.0418 111.413 84.2878 111.022C85.6647 108.835 86.3476 106.31 86.2625 103.718C86.2085 102.068 85.8463 100.489 85.2282 99.0412C87.2158 96.5661 88.2498 93.4023 88.0786 90.225C88.0401 89.511 87.4257 88.9644 86.7161 89.0018C86.002 89.0403 85.4545 89.6503 85.493 90.3641C85.6109 92.5527 85.013 94.7333 83.8299 96.5619C82.1631 94.252 79.7344 92.5029 76.8352 91.6868C76.1472 91.4931 75.432 91.894 75.2382 92.5822C75.0445 93.2704 75.4453 93.9853 76.1337 94.179C78.9796 94.9801 81.2577 96.9049 82.5396 99.4033V99.4033Z"
fill="#DEE5F9"
/>
</svg>
<div className="palmistry-container__bold-description">
Based on our data, {decisionMakingStatistics}% of <span style={{ color: 'var(--strong-blue-text)' }}>{zodiacSign} Sun</span> people also
make decisions with their Heart. But don't worry, we'll consider that while creating your guidance plan.
</div>
</>
)}
{steps.getStoredValue(Step.Decisions) === DecisionsChoice.Head && (
<>
<svg width="251" height="250" viewBox="0 0 251 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="gradient_svg"
x1="48"
y1="-4.15258e-06"
x2="48"
y2="86"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FDDAA6"/>
<stop offset="1" stopColor="#DEB475"/>
</linearGradient>
</defs>
<rect width="250" height="250" transform="translate(0.5)" fill="" />
<path
d="M70.3196 21H69.6094C69.1832 21 68.8281 21.3073 68.8281 21.7169C68.473 26.5306 63.2173 31.4467 58.2102 31.8905C57.8196 31.9246 57.5 32.266 57.5 32.6415V33.3585C57.5 33.7681 57.8196 34.0754 58.2457 34.1095C63.2173 34.4509 68.2954 39.4011 68.8281 44.2148C68.8636 44.6586 69.2543 45 69.7514 45H70.2486C70.7457 45 71.1364 44.6586 71.1719 44.1807C71.598 38.7866 76.108 34.3485 81.7188 34.0754C82.1804 34.0413 82.5 33.6999 82.5 33.256V32.6415C82.5 32.1977 82.1449 31.8563 81.7188 31.8222C76.0725 31.5491 71.527 27.0768 71.1719 21.6145C71.1009 21.3073 70.7457 21 70.3196 21Z"
fill="rgba(222, 229, 249, 0.7)"
/>
<path
d="M133.499 52.6187C129.705 52.6187 126.642 49.556 126.642 45.7619C126.642 45.3352 126.307 45 125.881 45C125.454 45 125.119 45.3352 125.119 45.7619C125.119 49.556 122.056 52.6187 118.262 52.6187C117.835 52.6187 117.5 52.9539 117.5 53.3805C117.5 53.8072 117.835 54.1424 118.262 54.1424C122.056 54.1424 125.119 57.2051 125.119 60.9992C125.119 61.4258 125.454 61.761 125.881 61.761C126.307 61.761 126.642 61.4258 126.642 60.9992C126.642 57.2051 129.705 54.1424 133.499 54.1424C133.926 54.1424 134.261 53.8072 134.261 53.3805C134.261 52.9539 133.926 52.6187 133.499 52.6187Z"
fill="rgba(222, 229, 249, 0.3)"
/>
<path
d="M209.748 43.8802C202.338 43.8802 196.356 37.8983 196.356 30.488C196.356 29.6547 195.701 29 194.868 29C194.035 29 193.38 29.6547 193.38 30.488C193.38 37.8983 187.398 43.8802 179.988 43.8802C179.155 43.8802 178.5 44.5349 178.5 45.3682C178.5 46.2015 179.155 46.8562 179.988 46.8562C187.398 46.8562 193.38 52.838 193.38 60.2484C193.38 61.0817 194.035 61.7364 194.868 61.7364C195.701 61.7364 196.356 61.0817 196.356 60.2484C196.356 52.838 202.338 46.8562 209.748 46.8562C210.582 46.8562 211.236 46.2015 211.236 45.3682C211.236 44.5349 210.582 43.8802 209.748 43.8802Z"
fill="rgba(222, 229, 249, 0.45)"
/>
<rect
width="230"
height="6"
rx="3"
transform="matrix(-0.965926 0.258819 0.258819 0.965926 238.662 151)"
fill="#DEE5F9"
/>
<path
d="M167.888 72C177.055 72.0008 185.509 76.9012 190 84.8187C194.491 76.9012 202.945 72.0008 212.112 72C226.133 72 237.5 84.8837 237.5 98.7736C237.5 133.66 190 158 190 158C190 158 142.5 133.66 142.5 98.7736C142.5 84.8837 153.867 72 167.888 72Z"
fill="#dee5f9"
/>
<circle cx="126.5" cy="201" r="16" fill="#DEE5F9"/>
<path
d="M51.4669 99C46.7008 99 42.837 102.868 42.837 107.639C42.837 107.888 42.8499 108.133 42.8704 108.376C42.0168 108.19 41.1313 108.089 40.2219 108.089C33.3845 108.089 27.8418 113.638 27.8418 120.482C27.8418 122.015 28.1217 123.482 28.63 124.838C22.3122 125.399 17.3579 130.709 17.3579 137.179C17.3579 141.286 19.3545 144.924 22.4277 147.18C19.3527 148.197 16.9798 150.912 16.5637 154.344C16.0106 158.905 19.1168 163.066 23.5736 163.881C22.1889 165.94 21.3805 168.42 21.3805 171.089C21.3805 178.227 27.1609 184.014 34.2914 184.014C36.6108 184.014 38.7854 183.398 40.6666 182.326C41.5642 186.824 45.5294 190.214 50.2861 190.214C55.7042 190.214 60.0966 185.817 60.0966 180.393V107.639C60.0966 102.868 56.233 99 51.4669 99V99Z"
fill="#BCC9ED"
/>
<path
d="M49.6714 159.307C49.3905 158.65 48.6295 158.345 47.9723 158.626C45.9927 159.471 44.3593 160.976 43.3529 162.872C41.4083 162.413 39.3752 162.584 37.5032 163.384C36.8456 163.665 36.5404 164.426 36.8212 165.083C37.1021 165.74 37.8633 166.046 38.5203 165.765C40.1984 165.048 42.0545 165.026 43.7469 165.705C45.439 166.383 46.7646 167.679 47.4802 169.355C47.6585 169.773 47.7953 170.207 47.887 170.647C48.03 171.334 48.6926 171.779 49.3784 171.658C49.3917 171.655 49.4051 171.653 49.4185 171.65C50.1184 171.504 50.5677 170.819 50.4216 170.119C50.2953 169.512 50.1066 168.913 49.8612 168.338C49.0322 166.396 47.6073 164.826 45.7896 163.818C46.5264 162.57 47.6484 161.58 48.9895 161.006C49.647 160.726 49.9523 159.965 49.6714 159.307Z"
fill="#dee5f9"
/>
<path
d="M43.0581 134.403C43.0463 134.428 43.0346 134.452 43.0211 134.475C42.3604 135.789 41.9734 137.257 41.9228 138.803C41.8548 140.876 42.4006 142.895 43.5008 144.643C43.8818 145.248 43.7 146.047 43.095 146.428C42.8808 146.563 42.6423 146.627 42.4065 146.627C41.9765 146.627 41.5558 146.413 41.3099 146.022C39.9329 143.835 39.2501 141.31 39.3352 138.718C39.3892 137.068 39.7513 135.489 40.3695 134.041C38.3818 131.566 37.3479 128.402 37.5191 125.225C37.5576 124.511 38.1719 123.964 38.8815 124.002C39.5956 124.04 40.1432 124.65 40.1047 125.364C39.9868 127.553 40.5847 129.733 41.7678 131.562C43.4346 129.252 45.8632 127.503 48.7624 126.687C49.4505 126.493 50.1656 126.894 50.3595 127.582C50.5531 128.27 50.1523 128.985 49.4639 129.179C46.6181 129.98 44.3399 131.905 43.0581 134.403V134.403Z"
fill="#dee5f9"
/>
<path
d="M70.1308 99C74.8968 99 78.7607 102.868 78.7607 107.639C78.7607 107.888 78.7478 108.133 78.7272 108.376C79.5808 108.19 80.4664 108.089 81.3758 108.089C88.2131 108.089 93.7559 113.638 93.7559 120.482C93.7559 122.015 93.476 123.482 92.9676 124.838C99.2854 125.399 104.24 130.709 104.24 137.179C104.24 141.286 102.243 144.924 99.17 147.18C102.245 148.197 104.618 150.912 105.034 154.344C105.587 158.905 102.481 163.066 98.024 163.881C99.4088 165.94 100.217 168.42 100.217 171.089C100.217 178.227 94.4368 184.014 87.3063 184.014C84.9869 184.014 82.8122 183.398 80.9311 182.326C80.0334 186.824 76.0683 190.214 71.3116 190.214C65.8934 190.214 61.501 185.817 61.501 180.393V107.639C61.501 102.868 65.3647 99 70.1308 99V99Z"
fill="#BCC9ED"
/>
<path
d="M71.9262 159.307C72.2071 158.65 72.9681 158.345 73.6253 158.626C75.6049 159.471 77.2383 160.976 78.2448 162.872C80.1893 162.413 82.2225 162.584 84.0945 163.384C84.752 163.665 85.0573 164.426 84.7764 165.083C84.4956 165.74 83.7343 166.046 83.0773 165.765C81.3993 165.048 79.5432 165.026 77.8508 165.705C76.1586 166.383 74.833 167.679 74.1174 169.355C73.9391 169.773 73.8023 170.207 73.7106 170.647C73.5676 171.334 72.9051 171.779 72.2192 171.658C72.206 171.655 72.1926 171.653 72.1792 171.65C71.4793 171.504 71.03 170.819 71.176 170.119C71.3023 169.512 71.491 168.913 71.7364 168.338C72.5654 166.396 73.9904 164.826 75.808 163.818C75.0712 162.57 73.9493 161.58 72.6082 161.006C71.9506 160.726 71.6454 159.965 71.9262 159.307Z"
fill="#dee5f9"
/>
<path
d="M78.5396 134.403C78.5513 134.428 78.5631 134.452 78.5765 134.475C79.2373 135.789 79.6243 137.257 79.6749 138.803C79.7429 140.876 79.1971 142.895 78.0968 144.643C77.7159 145.248 77.8976 146.047 78.5026 146.428C78.7168 146.563 78.9554 146.627 79.1912 146.627C79.6212 146.627 80.0418 146.413 80.2878 146.022C81.6647 143.835 82.3476 141.31 82.2625 138.718C82.2085 137.068 81.8463 135.489 81.2282 134.041C83.2158 131.566 84.2498 128.402 84.0786 125.225C84.0401 124.511 83.4257 123.964 82.7161 124.002C82.002 124.04 81.4545 124.65 81.493 125.364C81.6109 127.553 81.013 129.733 79.8299 131.562C78.1631 129.252 75.7344 127.503 72.8352 126.687C72.1472 126.493 71.432 126.894 71.2382 127.582C71.0445 128.27 71.4453 128.985 72.1337 129.179C74.9796 129.98 77.2577 131.905 78.5396 134.403V134.403Z"
fill="#dee5f9"
/>
</svg>
<div className="palmistry-container__bold-description">
Based on our data, {decisionMakingStatistics}% of <span style={{ color: 'var(--strong-blue-text)' }}>{zodiacSign} Sun</span> people also
make decisions with their Head. But don't worry, we'll consider that while creating your guidance plan.
</div>
</>
)}
{steps.getStoredValue(Step.Decisions) === DecisionsChoice.Both && (
<>
<svg width="251" height="250" viewBox="0 0 251 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="gradient_svg"
x1="48"
y1="-4.15258e-06"
x2="48"
y2="86"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FDDAA6"/>
<stop offset="1" stopColor="#DEB475"/>
</linearGradient>
</defs>
<rect width="250" height="250" transform="translate(0.5)" fill=""/>
<path d="M70.3196 21H69.6094C69.1832 21 68.8281 21.3073 68.8281 21.7169C68.473 26.5306 63.2173 31.4467 58.2102 31.8905C57.8196 31.9246 57.5 32.266 57.5 32.6415V33.3585C57.5 33.7681 57.8196 34.0754 58.2457 34.1095C63.2173 34.4509 68.2954 39.4011 68.8281 44.2148C68.8636 44.6586 69.2543 45 69.7514 45H70.2486C70.7457 45 71.1364 44.6586 71.1719 44.1807C71.598 38.7866 76.108 34.3485 81.7188 34.0754C82.1804 34.0413 82.5 33.6999 82.5 33.256V32.6415C82.5 32.1977 82.1449 31.8563 81.7188 31.8222C76.0725 31.5491 71.527 27.0768 71.1719 21.6145C71.1009 21.3073 70.7457 21 70.3196 21Z" fill="rgba(222, 229, 249, 0.7)"/>
<path d="M133.499 52.6187C129.705 52.6187 126.642 49.556 126.642 45.7619C126.642 45.3352 126.307 45 125.881 45C125.454 45 125.119 45.3352 125.119 45.7619C125.119 49.556 122.056 52.6187 118.262 52.6187C117.835 52.6187 117.5 52.9539 117.5 53.3805C117.5 53.8072 117.835 54.1424 118.262 54.1424C122.056 54.1424 125.119 57.2051 125.119 60.9992C125.119 61.4258 125.454 61.761 125.881 61.761C126.307 61.761 126.642 61.4258 126.642 60.9992C126.642 57.2051 129.705 54.1424 133.499 54.1424C133.926 54.1424 134.261 53.8072 134.261 53.3805C134.261 52.9539 133.926 52.6187 133.499 52.6187Z" fill="rgba(222, 229, 249, 0.3)"/>
<path d="M209.748 43.8802C202.338 43.8802 196.356 37.8983 196.356 30.488C196.356 29.6547 195.701 29 194.868 29C194.035 29 193.38 29.6547 193.38 30.488C193.38 37.8983 187.398 43.8802 179.988 43.8802C179.155 43.8802 178.5 44.5349 178.5 45.3682C178.5 46.2015 179.155 46.8562 179.988 46.8562C187.398 46.8562 193.38 52.838 193.38 60.2484C193.38 61.0817 194.035 61.7364 194.868 61.7364C195.701 61.7364 196.356 61.0817 196.356 60.2484C196.356 52.838 202.338 46.8562 209.748 46.8562C210.582 46.8562 211.236 46.2015 211.236 45.3682C211.236 44.5349 210.582 43.8802 209.748 43.8802Z" fill="rgba(222, 229, 249, 0.45)"/>
<rect
width="230"
height="6"
rx="3"
transform="matrix(-1 -8.74228e-08 -8.74228e-08 1 243.357 180.662)"
fill="#DEE5F9"
/>
<circle cx="126.5" cy="201" r="16" fill="#DEE5F9"/>
<path d="M167.888 90C177.055 90.0008 185.509 94.9012 190 102.819C194.491 94.9012 202.945 90.0008 212.112 90C226.133 90 237.5 102.884 237.5 116.774C237.5 151.66 190 176 190 176C190 176 142.5 151.66 142.5 116.774C142.5 102.884 153.867 90 167.888 90Z" fill="#BCC9ED"/>
<path d="M50.4669 85C45.7008 85 41.837 88.8679 41.837 93.6391C41.837 93.8876 41.8499 94.1329 41.8704 94.3759C41.0168 94.1897 40.1313 94.0887 39.2219 94.0887C32.3845 94.0887 26.8418 99.6375 26.8418 106.482C26.8418 108.015 27.1217 109.482 27.63 110.838C21.3122 111.399 16.3579 116.709 16.3579 123.179C16.3579 127.286 18.3545 130.924 21.4277 133.18C18.3527 134.197 15.9798 136.912 15.5637 140.344C15.0106 144.905 18.1168 149.066 22.5736 149.881C21.1889 151.94 20.3805 154.42 20.3805 157.089C20.3805 164.227 26.1609 170.014 33.2914 170.014C35.6108 170.014 37.7854 169.398 39.6666 168.326C40.5642 172.824 44.5294 176.214 49.2861 176.214C54.7042 176.214 59.0966 171.817 59.0966 166.393V93.6391C59.0966 88.8679 55.233 85 50.4669 85Z" fill="#BCC9ED"/>
<path d="M48.6714 145.307C48.3905 144.65 47.6295 144.345 46.9723 144.626C44.9927 145.471 43.3593 146.976 42.3529 148.872C40.4083 148.413 38.3752 148.584 36.5032 149.384C35.8456 149.665 35.5404 150.426 35.8212 151.083C36.1021 151.74 36.8633 152.046 37.5203 151.765C39.1984 151.048 41.0545 151.026 42.7469 151.705C44.439 152.383 45.7646 153.679 46.4802 155.355C46.6585 155.773 46.7953 156.207 46.887 156.647C47.03 157.334 47.6926 157.779 48.3784 157.658C48.3917 157.655 48.4051 157.653 48.4185 157.65C49.1184 157.504 49.5677 156.819 49.4216 156.119C49.2953 155.512 49.1066 154.913 48.8612 154.338C48.0322 152.396 46.6073 150.826 44.7896 149.818C45.5264 148.57 46.6484 147.58 47.9895 147.006C48.647 146.726 48.9523 145.965 48.6714 145.307Z" fill="#DEE5F9"/>
<path d="M42.0581 120.403C42.0463 120.428 42.0346 120.452 42.0211 120.475C41.3604 121.789 40.9734 123.257 40.9228 124.803C40.8548 126.876 41.4006 128.895 42.5008 130.643C42.8818 131.248 42.7 132.047 42.095 132.428C41.8808 132.563 41.6423 132.627 41.4065 132.627C40.9765 132.627 40.5558 132.413 40.3099 132.022C38.9329 129.835 38.2501 127.31 38.3352 124.718C38.3892 123.068 38.7513 121.489 39.3695 120.041C37.3818 117.566 36.3479 114.402 36.5191 111.225C36.5576 110.511 37.1719 109.964 37.8815 110.002C38.5956 110.04 39.1432 110.65 39.1047 111.364C38.9868 113.553 39.5847 115.733 40.7678 117.562C42.4346 115.252 44.8632 113.503 47.7624 112.687C48.4505 112.493 49.1656 112.894 49.3595 113.582C49.5531 114.27 49.1523 114.985 48.4639 115.179C45.6181 115.98 43.3399 117.905 42.0581 120.403Z" fill="#DEE5F9"/>
<path d="M69.1308 85C73.8968 85 77.7607 88.8679 77.7607 93.6391C77.7607 93.8876 77.7478 94.1329 77.7272 94.3759C78.5808 94.1897 79.4664 94.0887 80.3758 94.0887C87.2131 94.0887 92.7559 99.6375 92.7559 106.482C92.7559 108.015 92.476 109.482 91.9676 110.838C98.2854 111.399 103.24 116.709 103.24 123.179C103.24 127.286 101.243 130.924 98.17 133.18C101.245 134.197 103.618 136.912 104.034 140.344C104.587 144.905 101.481 149.066 97.024 149.881C98.4088 151.94 99.2172 154.42 99.2172 157.089C99.2172 164.227 93.4368 170.014 86.3063 170.014C83.9869 170.014 81.8122 169.398 79.9311 168.326C79.0334 172.824 75.0683 176.214 70.3116 176.214C64.8934 176.214 60.501 171.817 60.501 166.393V93.6391C60.501 88.8679 64.3647 85 69.1308 85Z" fill="#BCC9ED"/>
<path d="M70.9262 145.307C71.2071 144.65 71.9681 144.345 72.6253 144.626C74.6049 145.471 76.2383 146.976 77.2448 148.872C79.1893 148.413 81.2225 148.584 83.0945 149.384C83.752 149.665 84.0573 150.426 83.7764 151.083C83.4956 151.74 82.7343 152.046 82.0773 151.765C80.3993 151.048 78.5432 151.026 76.8508 151.705C75.1586 152.383 73.833 153.679 73.1174 155.355C72.9391 155.773 72.8023 156.207 72.7106 156.647C72.5676 157.334 71.9051 157.779 71.2192 157.658C71.206 157.655 71.1926 157.653 71.1792 157.65C70.4793 157.504 70.03 156.819 70.176 156.119C70.3023 155.512 70.491 154.913 70.7364 154.338C71.5654 152.396 72.9904 150.826 74.808 149.818C74.0712 148.57 72.9493 147.58 71.6082 147.006C70.9506 146.726 70.6454 145.965 70.9262 145.307Z" fill="#DEE5F9"/>
<path d="M77.5396 120.403C77.5513 120.428 77.5631 120.452 77.5765 120.475C78.2373 121.789 78.6243 123.257 78.6749 124.803C78.7429 126.876 78.1971 128.895 77.0968 130.643C76.7159 131.248 76.8976 132.047 77.5026 132.428C77.7168 132.563 77.9554 132.627 78.1912 132.627C78.6212 132.627 79.0418 132.413 79.2878 132.022C80.6647 129.835 81.3476 127.31 81.2625 124.718C81.2085 123.068 80.8463 121.489 80.2282 120.041C82.2158 117.566 83.2498 114.402 83.0786 111.225C83.0401 110.511 82.4257 109.964 81.7161 110.002C81.002 110.04 80.4545 110.65 80.493 111.364C80.6109 113.553 80.013 115.733 78.8299 117.562C77.1631 115.252 74.7344 113.503 71.8352 112.687C71.1472 112.493 70.432 112.894 70.2382 113.582C70.0445 114.27 70.4453 114.985 71.1337 115.179C73.9796 115.98 76.2577 117.905 77.5396 120.403Z" fill="#DEE5F9"/>
</svg>
<div className="palmistry-container__bold-description">
Wonderful!
<br />
Based on our data, only the top {decisionMakingStatistics}% of{' '}
<span style={{ color: 'var(--strong-blue-text)' }}>{zodiacSign} Sun</span> people make decisions with their
heart and head. Using both in equal measure is the key to feeling harmonious in your relationships.
</div>
</>
)}
<div className="palmistry-container__button-wrapper_horizontal">
<Button type="button" onClick={onBack}>
Back
</Button>
<Button type="button" active onClick={onNext}>
Next
</Button>
</div>
</>
);
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
import React from 'react';
import { useNavigate } from "react-router-dom";
import { Step } from '@/hooks/palmistry/use-steps';
import useSteps from '@/hooks/palmistry/use-steps';
import Paywall from '@/components/palmistry/paywall/paywall';
export default function StepPaywall() {
const navigate = useNavigate();
const steps = useSteps();
const storedEmail = steps.getStoredValue(Step.Email);
const [email, setEmail] = React.useState(steps.getStoredValue(Step.Email));
React.useEffect(() => {
if (storedEmail) setEmail(storedEmail);
}, [storedEmail]);
const onNext = () => {
navigate('/palmistry/payment');
};
return (
<>
<Paywall email={email} onClickActionButton={onNext}/>
</>
);
}

View File

@ -0,0 +1,87 @@
import React from 'react';
import Button from '../button/button';
import useSteps from '../../../hooks/palmistry/use-steps';
enum AnswerOption {
One = '1',
Two = '2',
Three = '3',
Four = '4',
Five = '5',
}
const questions = [
'I find solace and comfort in spending time alone.',
'I value and enjoy my own company.',
'I prefer socializing in groups rather than spending time alone.',
'Loneliness is something I actively try to avoid.',
'I enjoy activities that I can do independently.',
];
export default function StepPersonalStatement() {
const steps = useSteps();
const [value, setValue] = React.useState<AnswerOption[]>([]);
const [currentQuestionNumber, setCurrentQuestionNumber] = React.useState(0);
const [questionIsVisible, setQuestionIsVisible] = React.useState(true);
const onClickButton = (answer: AnswerOption) => {
setValue((prevState) => [...prevState, answer]);
if (currentQuestionNumber < questions.length - 1) {
setCurrentQuestionNumber((prevState) => prevState + 1);
}
setQuestionIsVisible(false);
};
React.useEffect(() => {
if (!questionIsVisible) setQuestionIsVisible(true);
}, [questionIsVisible]);
React.useEffect(() => {
if (value.length === questions.length) {
steps.saveCurrent(value.join(','));
steps.goNext();
}
}, [value]);
const subtitleClassName = ['palmistry-container__personal-statement-subtitle'];
if (questionIsVisible) subtitleClassName.push('palmistry-container__personal-statement-fade-in-animation');
return (
<>
<p>Do you relate to the following:</p>
<p className={subtitleClassName.join(' ')}>
<q>{questions[currentQuestionNumber]}</q>
</p>
<div className="palmistry-container__personal-statement-button-container">
{Object.values(AnswerOption).map((answer) => (
<Button
key={answer}
type="button"
className="palmistry-container__personal-statement-button"
onClick={() => onClickButton(answer)}
>{answer}</Button>
))}
</div>
<div className="palmistry-container__personal-statement-text-block">
<p>
Strongly
<br/>
Disagree
</p>
<p>
Strongly
<br/>
Agree
</p>
</div>
</>
);
}

View File

@ -0,0 +1,37 @@
import Button from '../button/button';
import useSteps, { RelationshipStatusChoice } from '../../../hooks/palmistry/use-steps';
export default function StepRelationshipStatus() {
const steps = useSteps();
const onNext = (choice: RelationshipStatusChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h3>So we can get to know you better, please tell us your relationship status.</h3>
</div>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === RelationshipStatusChoice.Single}
onClick={() => onNext(RelationshipStatusChoice.Single)}
>
Single
</Button>
<Button
type="button"
active={steps.storedValue === RelationshipStatusChoice.InRelationship}
onClick={() => onNext(RelationshipStatusChoice.InRelationship)}
>
In a relationship
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,144 @@
import Button from '../button/button';
import useSteps, { ResonatedElementChoice } from '../../../hooks/palmistry/use-steps';
export default function StepResonatedElement() {
const steps = useSteps();
const onNext = (choice: ResonatedElementChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h3>Which element resonates with you the most?</h3>
</div>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === ResonatedElementChoice.Earth}
onClick={() => onNext(ResonatedElementChoice.Earth)}
>
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="19.5901" cy="19.9591" r="19.5198" fill="#ffffff"></circle>
<path d="M20.6222 0.623962H19.3867V39.3763H20.6222V0.623962Z" fill="#066fde"></path>
<path
d="M20.6231 30.7402H19.3877C19.3877 27.1561 17.0146 24.9421 15.0085 23.7188C12.5987 22.2387 9.39378 21.3457 6.44577 21.3457C4.195 21.3457 1.57727 21.9329 1.57727 23.5843H0.341797C0.341797 21.4314 2.67818 20.098 6.44577 20.098C9.6262 20.098 13.0635 21.0521 15.6568 22.6546C18.9106 24.6607 20.6231 27.4497 20.6231 30.7402Z"
fill="#066fde"
/>
<path
d="M20.6244 23.0459H19.389C19.389 20.685 18.5205 19.0459 16.6734 17.8716C14.9731 16.7951 12.6978 16.2569 10.496 15.7431C6.70395 14.8502 2.77734 13.9327 2.77734 10.0306H4.01282C4.01282 11.3517 4.59997 12.2691 5.89661 12.9908C7.15655 13.6881 8.91802 14.104 10.7773 14.5321C13.077 15.0703 15.4624 15.633 17.3339 16.8196C19.548 18.2263 20.6244 20.2569 20.6244 23.0459Z"
fill="#066fde"
/>
<path
d="M20.6233 39.3763H19.3879C19.3879 35.6943 17.394 33.3946 15.7304 32.1102C13.7732 30.6056 11.1187 29.676 8.79459 29.676C6.17685 29.676 5.24719 30.7769 5.24719 31.7922H4.01172C4.01172 30.7035 4.52548 29.8105 5.50407 29.2111C6.33588 28.6974 7.47349 28.4283 8.79459 28.4283C11.4123 28.4283 14.2869 29.4313 16.4888 31.1194C18.3726 32.5873 20.6233 35.1928 20.6233 39.3763Z"
fill="#066fde"
/>
<path
d="M20.6236 15.9753H19.3882C19.3882 13.5166 18.0915 12.5013 16.4524 11.2169C14.4096 9.61448 11.8652 7.62059 11.8652 2.14047H13.1007C13.1007 7.02121 15.1924 8.66035 17.2108 10.2383C18.8866 11.5594 20.6236 12.9172 20.6236 15.9753Z"
fill="#066fde"
/>
<path
d="M20.6222 30.7402H19.3867C19.3867 27.4497 21.0993 24.6607 24.3531 22.6546C26.9463 21.0521 30.3959 20.098 33.5641 20.098C37.3317 20.098 39.6681 21.4314 39.6681 23.5843H38.4326C38.4326 22.5445 37.1604 21.3457 33.5641 21.3457C30.6038 21.3457 27.4112 22.2265 25.0014 23.7188C23.0075 24.9421 20.6222 27.1561 20.6222 30.7402Z"
fill="#066fde"
/>
<path
d="M20.6222 23.0459H19.3867C19.3867 20.2691 20.4632 18.2263 22.6772 16.8196C24.5488 15.633 26.9341 15.0703 29.2338 14.5321C31.0931 14.0917 32.8424 13.6881 34.1145 12.9908C35.4234 12.2691 35.9983 11.3517 35.9983 10.0306H37.2338C37.2338 13.9327 33.3072 14.8502 29.5152 15.7431C27.3133 16.2569 25.0381 16.7951 23.3378 17.8716C21.4907 19.0459 20.6222 20.685 20.6222 23.0459Z"
fill="#066fde"
/>
<path
d="M20.6222 39.3763H19.3867C19.3867 35.1805 21.6375 32.575 23.5335 31.1194C25.7353 29.4313 28.61 28.4283 31.2277 28.4283C32.5488 28.4283 33.6864 28.6974 34.5182 29.2111C35.4968 29.8105 36.0106 30.7035 36.0106 31.7922H34.7751C34.7751 30.7646 33.8454 29.676 31.2277 29.676C28.9035 29.676 26.2491 30.6056 24.2919 32.1102C22.6161 33.3946 20.6222 35.6943 20.6222 39.3763Z"
fill="#066fde"
/>
<path
d="M20.6222 15.9753H19.3867C19.3867 12.9172 21.1237 11.5594 22.7996 10.2383C24.8179 8.64812 26.9097 7.02121 26.9097 2.14047H28.1451C28.1451 7.62059 25.6008 9.61448 23.558 11.2169C21.9188 12.5013 20.6222 13.5166 20.6222 15.9753Z"
fill="#066fde"
/>
<path
d="M20 40C14.6544 40 9.63914 37.9205 5.85932 34.1407C2.07951 30.3609 0 25.3456 0 20C0 14.6544 2.07951 9.63915 5.85932 5.85933C9.63914 2.07951 14.6544 0 20 0C25.3456 0 30.3609 2.07951 34.1407 5.85933C37.9205 9.63915 40 14.6544 40 20C40 25.3456 37.9205 30.3609 34.1407 34.1407C30.3731 37.9205 25.3456 40 20 40ZM20 1.24771C14.9847 1.24771 10.2752 3.2049 6.74006 6.74007C3.19266 10.2875 1.2477 14.9969 1.2477 20C1.2477 25.0153 3.20489 29.7248 6.74006 33.2599C10.2875 36.8073 14.9969 38.7523 20 38.7523C25.0153 38.7523 29.7248 36.7951 33.2599 33.2599C36.8073 29.7125 38.7523 25.0031 38.7523 20C38.7523 14.9847 36.7951 10.2752 33.2599 6.74007C29.7248 3.19267 25.0153 1.24771 20 1.24771Z"
fill="#066fde"
/>
</svg>
<span>Earth</span>
</Button>
<Button
type="button"
active={steps.storedValue === ResonatedElementChoice.Water}
onClick={() => onNext(ResonatedElementChoice.Water)}
>
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="19.5901" cy="20.0286" r="19.5198" fill="#ffffff"></circle>
<path
d="M20.0008 7.37594C18.5696 7.37594 16.7347 6.50743 14.802 5.59C13.0772 4.77043 11.2913 3.9264 10.1414 3.9264C9.79892 3.9264 9.51758 3.64505 9.51758 3.30254C9.51758 2.96003 9.79892 2.67869 10.1414 2.67869C11.5726 2.67869 13.4075 3.54719 15.3402 4.46462C17.065 5.28419 18.8509 6.12823 20.0008 6.12823C20.906 6.12823 22.5451 5.16187 23.9885 4.31783C25.7255 3.30254 27.3647 2.33618 28.6001 2.33618C28.9427 2.33618 29.224 2.61753 29.224 2.96003C29.224 3.30254 28.9427 3.58389 28.6001 3.58389C27.6949 3.58389 26.0558 4.55025 24.6124 5.39429C22.8876 6.40958 21.2485 7.37594 20.0008 7.37594Z"
fill="#066fde"
/>
<path
d="M20 40C14.6544 40 9.63914 37.9205 5.85932 34.1407C2.07951 30.3609 0 25.3456 0 20C0 14.6544 2.07951 9.63914 5.85932 5.85933C9.63914 2.07951 14.6544 0 20 0C25.3456 0 30.3609 2.07951 34.1407 5.85933C37.9205 9.63914 40 14.6544 40 20C40 25.3456 37.9205 30.3609 34.1407 34.1407C30.3609 37.9205 25.3456 40 20 40ZM20 1.23547C14.9847 1.23547 10.2752 3.19266 6.74006 6.72783C3.19266 10.2752 1.2477 14.9847 1.2477 19.9878C1.2477 25.0031 3.20489 29.7125 6.74006 33.2477C10.2875 36.7951 14.9969 38.7401 20 38.7401C25.0153 38.7401 29.7248 36.7829 33.2599 33.2477C36.8073 29.7003 38.7523 24.9908 38.7523 19.9878C38.7523 14.9725 36.7951 10.263 33.2599 6.72783C29.7248 3.19266 25.0153 1.23547 20 1.23547Z"
fill="#066fde"
/>
<path
d="M39.3879 20.6848C37.8588 20.6848 35.8282 19.7185 33.6753 18.7032C31.7793 17.8102 29.8221 16.8806 28.6233 16.8806C27.7181 16.8806 26.079 17.8469 24.6356 18.691C22.8986 19.7062 21.2594 20.6726 20.0239 20.6726C18.5805 20.6726 16.6356 19.7185 14.5683 18.7154C12.7212 17.8102 10.8129 16.8806 9.6631 16.8806C8.66004 16.8806 6.83741 17.8958 5.21049 18.7888C3.44903 19.7674 1.77318 20.6848 0.635569 20.6848C0.293061 20.6848 0.0117188 20.4035 0.0117188 20.061C0.0117188 19.7185 0.293061 19.4371 0.635569 19.4371C1.45514 19.4371 3.13098 18.5075 4.6111 17.7001C6.53159 16.6481 8.342 15.6451 9.6631 15.6451C11.1065 15.6451 13.0515 16.5992 15.1188 17.6023C16.9658 18.5075 18.8741 19.4371 20.0239 19.4371C20.9291 19.4371 22.5683 18.4708 24.0117 17.6267C25.7487 16.6114 27.3879 15.6451 28.6233 15.6451C30.1035 15.6451 32.0973 16.587 34.2135 17.59C36.1463 18.5075 38.1524 19.4494 39.4001 19.4494C39.7426 19.4494 40.0239 19.7307 40.0239 20.0732C39.9995 20.4157 39.7304 20.6848 39.3879 20.6848Z"
fill="#066fde"
/>
<path
d="M38.1281 13.4801C36.5745 13.4801 34.7642 12.4648 33.0027 11.4862C31.4247 10.6055 29.7856 9.68807 28.6112 9.68807C27.706 9.68807 26.0669 10.6544 24.6235 11.4985C22.8865 12.5138 21.2473 13.4801 20.0119 13.4801C18.5684 13.4801 16.6235 12.526 14.5562 11.5229C12.7091 10.6177 10.8008 9.68807 9.651 9.68807C8.68464 9.68807 7.24121 10.6789 5.95681 11.5596C4.51338 12.5505 3.15558 13.4924 1.98127 13.4924C1.63876 13.4924 1.35742 13.211 1.35742 12.8685C1.35742 12.526 1.63876 12.2447 1.98127 12.2447C2.76415 12.2447 4.03632 11.3761 5.25957 10.5321C6.75192 9.50459 8.2932 8.44037 9.651 8.44037C11.0944 8.44037 13.0394 9.3945 15.1067 10.3976C16.9538 11.3028 18.862 12.2324 20.0119 12.2324C20.9171 12.2324 22.5562 11.2661 23.9996 10.422C25.7366 9.40673 27.3758 8.44037 28.6112 8.44037C30.1158 8.44037 31.8161 9.3945 33.6143 10.3976C35.229 11.3028 36.9048 12.2324 38.1281 12.2324C38.4706 12.2324 38.7519 12.5138 38.7519 12.8563C38.7519 13.211 38.4706 13.4801 38.1281 13.4801Z"
fill="#066fde"
/>
<path
d="M38.1281 27.8285C36.5745 27.8285 34.7642 26.8133 33.0027 25.8347C31.4247 24.9539 29.7856 24.0365 28.6112 24.0365C27.706 24.0365 26.0669 25.0029 24.6235 25.8469C22.8865 26.8622 21.2473 27.8285 20.0119 27.8285C18.5684 27.8285 16.6235 26.8744 14.5562 25.8714C12.7091 24.9662 10.8008 24.0365 9.651 24.0365C8.68464 24.0365 7.24121 25.0273 5.95681 25.9081C4.51338 26.8989 3.15558 27.8408 1.98127 27.8408C1.63876 27.8408 1.35742 27.5594 1.35742 27.2169C1.35742 26.8744 1.63876 26.5931 1.98127 26.5931C2.76415 26.5931 4.03632 25.7246 5.25957 24.8805C6.75192 23.853 8.2932 22.7888 9.651 22.7888C11.0944 22.7888 13.0394 23.7429 15.1067 24.746C16.9538 25.6512 18.862 26.5808 20.0119 26.5808C20.9171 26.5808 22.5562 25.6145 23.9996 24.7704C25.7366 23.7552 27.3758 22.7888 28.6112 22.7888C30.1158 22.7888 31.8161 23.7429 33.6143 24.746C35.229 25.6512 36.9048 26.5808 38.1281 26.5808C38.4706 26.5808 38.7519 26.8622 38.7519 27.2047C38.7519 27.5472 38.4706 27.8285 38.1281 27.8285Z"
fill="#066fde"
/>
<path
d="M20.0013 35.8043C18.5579 35.8043 16.613 34.8501 14.5457 33.8471C12.6986 32.9419 10.7903 32.0122 9.64048 32.0122C8.67412 32.0122 6.86372 33.003 5.89736 33.529C5.59155 33.688 5.22458 33.578 5.05332 33.2844C4.8943 32.9786 5.0044 32.6116 5.29797 32.4403C7.18176 31.4128 8.56402 30.7767 9.62824 30.7767C11.0717 30.7767 13.0166 31.7309 15.0839 32.7339C16.931 33.6391 18.8393 34.5688 19.9891 34.5688C20.8943 34.5688 22.5334 33.6024 23.9769 32.7584C25.7139 31.7431 27.353 30.7767 28.5885 30.7767C30.0686 30.7767 32.0625 31.7186 34.1787 32.7217L34.2154 32.7462C34.5212 32.8929 34.6558 33.2599 34.509 33.5657C34.3622 33.8715 33.9952 34.0061 33.6894 33.8593L33.6527 33.8348C31.7567 32.9419 29.7995 32.0122 28.6007 32.0122C27.6955 32.0122 26.0564 32.9786 24.613 33.8226C22.8882 34.8379 21.249 35.8043 20.0013 35.8043Z"
fill="#066fde"
/>
</svg>
<span>Water</span>
</Button>
<Button
type="button"
active={steps.storedValue === ResonatedElementChoice.Fire}
onClick={() => onNext(ResonatedElementChoice.Fire)}
>
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="19.9339" cy="19.9591" r="19.5198" fill="#ffffff"></circle>
<path
d="M22.9126 39.8166C22.8759 39.8166 22.8392 39.8166 22.8148 39.8043C22.6191 39.7676 17.8362 38.997 13.1879 36.0001C10.4356 34.2264 8.31937 32.049 6.87594 29.5047C5.07778 26.3365 4.36829 22.6178 4.7475 18.471C4.77196 18.153 5.02885 17.9083 5.33466 17.8716C5.6527 17.8349 5.94628 18.0429 6.0319 18.3365C6.80255 20.9297 8.35606 23.0949 9.616 24.5383C9.39582 23.7432 9.18787 22.8013 9.05331 21.7982C8.50285 17.7004 9.44475 14.3365 11.7689 12.049C13.5548 10.2998 15.3408 9.22331 16.9188 8.26918C18.46 7.33952 19.671 6.60557 20.2949 5.59028C20.9555 4.51383 20.9188 3.11933 20.197 1.05205C20.0992 0.758476 20.2093 0.428198 20.4784 0.269177C20.7475 0.110155 21.09 0.159088 21.298 0.379272C23.7322 2.98478 24.564 5.68814 23.8545 8.66062C23.2307 11.2539 21.5671 13.7004 19.7934 16.3059C17.6894 19.4007 15.512 22.5933 15.0961 26.1407C14.8392 28.2936 15.5732 31.0215 17.0411 33.4557C18.6068 36.049 20.7964 37.8839 23.0472 38.4955C23.3408 38.5566 23.561 38.8258 23.561 39.1316C23.561 39.4863 23.2918 39.7677 22.9371 39.7921C22.9493 39.8166 22.9249 39.8166 22.9126 39.8166ZM5.99521 21.6637C6.12976 24.3181 6.81478 26.7401 8.02579 28.8686C9.35912 31.2172 11.3285 33.2478 13.9096 34.8992C15.3897 35.8533 16.8943 36.575 18.2399 37.101C17.3958 36.2692 16.6129 35.2784 15.9279 34.153C14.3132 31.4741 13.5181 28.4282 13.7995 26.0062C14.2521 22.1407 16.5273 18.8013 18.7169 15.5719C20.4172 13.0765 22.0197 10.7157 22.5824 8.36704C22.9738 6.72789 22.8148 5.19884 22.0808 3.71872C22.1298 6.67896 20.0625 7.92667 17.5915 9.40679C16.0747 10.3242 14.3499 11.3517 12.6863 12.9909C10.6435 14.997 9.86065 17.8839 10.3499 21.5903C10.7292 24.4282 11.7444 26.6912 11.7567 26.7157C11.879 26.997 11.8056 27.3273 11.561 27.5108C11.3163 27.6943 10.986 27.6943 10.7414 27.5108C10.6191 27.4129 7.879 25.1866 5.99521 21.6637Z"
fill="#066fde"
/>
<path
d="M24.2577 34.1285C20.8694 34.1285 19.1324 32.5383 18.2761 31.1927C17.6033 30.153 17.2119 28.8808 17.1629 27.5108C17.114 26.2631 17.3342 25.0154 17.8112 23.9878C18.3495 22.8135 19.377 21.5414 20.5635 20.0735C23.695 16.1958 27.5972 11.364 24.588 5.57806C24.4412 5.29672 24.5268 4.96644 24.7837 4.78296C25.0406 4.59947 25.3831 4.63617 25.5911 4.86858C29.4198 9.0276 30.6186 13.3456 30.9366 16.2325C31.3036 19.5352 30.7164 22.7401 29.3097 25.1866C30.8632 25.0765 32.2333 23.9634 33.1262 23.0215C34.1905 21.9083 34.8265 20.783 34.8265 20.7707C34.9733 20.5261 35.2669 20.4037 35.536 20.4771C35.8174 20.5628 36.0009 20.8196 35.9764 21.101C35.9764 21.2111 35.8174 23.9022 34.6064 26.8258C32.9794 30.7646 30.2149 33.2111 26.5941 33.8839C25.7746 34.0429 24.9917 34.1285 24.2577 34.1285ZM26.8021 8.45268C27.4993 13.4313 24.1109 17.627 21.5054 20.8563C20.3678 22.2631 19.3892 23.4741 18.9244 24.5016C18.2272 26.0307 18.0559 28.5628 19.3158 30.52C20.3067 32.0735 22.0192 32.8808 24.2577 32.8808C24.9183 32.8808 25.6278 32.8074 26.3739 32.6729C29.6033 32.0735 31.9886 29.945 33.4687 26.3609C33.8846 25.3456 34.1782 24.3426 34.3617 23.4863C33.1385 24.8686 31.2791 26.4221 29.0406 26.4221C28.7226 26.4221 28.4045 26.3854 28.0987 26.3242C27.8908 26.2875 27.7195 26.1408 27.6461 25.945C27.5727 25.7493 27.5972 25.5291 27.7195 25.3579C29.3709 23.0704 30.0926 19.7921 29.7012 16.3548C29.4565 14.2998 28.747 11.4374 26.8021 8.45268Z"
fill="#066fde"
/>
<path
d="M20 40C14.6544 40 9.63914 37.9205 5.85933 34.1407C2.07951 30.3609 0 25.3456 0 20C0 14.6544 2.07951 9.63915 5.85933 5.85933C9.63914 2.07951 14.6544 0 20 0C25.3456 0 30.3609 2.07951 34.1407 5.85933C37.9205 9.63915 39.9878 14.6667 39.9878 20C39.9878 25.3456 37.9083 30.3609 34.1284 34.1407C30.3609 37.9205 25.3333 40 20 40ZM20 1.24771C14.9847 1.24771 10.2752 3.2049 6.74006 6.74007C3.19266 10.2875 1.24771 14.9969 1.24771 20C1.24771 25.0153 3.20489 29.7248 6.74006 33.2599C10.2875 36.8073 14.9969 38.7523 20 38.7523C25.0153 38.7523 29.7248 36.7951 33.2599 33.2599C36.8073 29.7125 38.7523 25.0031 38.7523 20C38.7523 14.9847 36.7951 10.2752 33.2599 6.74007C29.7125 3.19267 25.0031 1.24771 20 1.24771Z"
fill="#066fde"
/>
</svg>
<span>Fire</span>
</Button>
<Button
type="button"
active={steps.storedValue === ResonatedElementChoice.Air}
onClick={() => onNext(ResonatedElementChoice.Air)}
>
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="19.9396" cy="20.0349" r="19.5138" fill="#ffffff"></circle>
<path d="M36.8083 9.15946C36.0501 7.98551 35.1574 6.8727 34.1302 5.85772C33.8368 5.56423 33.5433 5.28297 33.2375 5.01394C29.5812 1.77334 24.922 0.000183105 19.9939 0.000183105C14.65 0.000183105 9.6362 2.07906 5.85754 5.85772C2.07887 9.63638 0 14.6501 0 19.9941C0 25.338 2.07887 30.3518 5.85754 34.1304C9.6362 37.9091 14.65 39.988 19.9939 39.988C25.3378 39.988 30.3516 37.9091 34.1302 34.1304C37.9089 30.3518 39.9878 25.3258 39.9878 19.9941C39.9878 16.0931 38.8872 12.3634 36.8083 9.15946ZM33.262 33.25C29.7157 36.7963 25.0076 38.7406 20.0061 38.7406C14.9924 38.7406 10.2843 36.784 6.75023 33.25C3.20391 29.7036 1.25955 24.9956 1.25955 19.9941C1.25955 14.9803 3.21614 10.2723 6.75023 6.73818C10.2965 3.19187 15.0046 1.24751 20.0061 1.24751C25.0199 1.24751 29.7279 3.2041 33.262 6.73818C33.3231 6.79933 33.3843 6.86047 33.4454 6.92161C34.2403 7.72871 34.9129 8.68254 35.402 9.67307C35.7689 10.3946 36.0501 11.0671 36.2091 11.862C36.6371 13.574 36.6983 15.4083 36.5271 17.3038C36.1847 21.2292 34.3259 24.7877 31.3054 27.3068C28.2849 29.8382 24.4574 31.0366 20.5319 30.6942C14.1241 30.1316 9.36717 24.4453 9.92968 18.0375C10.3821 12.9748 14.8578 9.23283 19.9205 9.67307C21.8526 9.84427 23.5891 10.7492 24.8364 12.2411C26.0715 13.7208 26.6707 15.604 26.4995 17.5239C26.365 19.028 25.6558 20.3976 24.494 21.3637C23.3323 22.3297 21.8649 22.7944 20.3607 22.6599C19.1868 22.5621 18.1351 21.9996 17.377 21.1069C16.6188 20.202 16.2641 19.0647 16.3742 17.8907C16.4476 16.9858 16.8756 16.1787 17.5726 15.5917C18.2696 15.0048 19.1501 14.7357 20.0428 14.8091C20.7276 14.8703 21.3513 15.1882 21.7915 15.7263C22.2317 16.2521 22.4396 16.9247 22.3907 17.6095C22.2929 18.6734 21.3513 19.456 20.2874 19.3704C19.9327 19.3337 19.6148 19.6028 19.5781 19.9574C19.5414 20.312 19.8105 20.63 20.1651 20.6544C21.9382 20.8134 23.5157 19.4927 23.6747 17.7195C23.7603 16.6923 23.4546 15.6773 22.782 14.8825C22.1217 14.0876 21.1801 13.5985 20.1529 13.5129C18.9055 13.4028 17.6949 13.7819 16.7288 14.589C15.7628 15.3961 15.1758 16.5211 15.0657 17.7685C14.9312 19.2848 15.3959 20.7645 16.3742 21.9262C17.3525 23.0879 18.7221 23.8094 20.2385 23.9439C22.085 24.1029 23.8948 23.5404 25.3134 22.3542C26.7441 21.1558 27.6124 19.4805 27.7836 17.6339C27.9792 15.3594 27.2944 13.146 25.827 11.3973C24.3595 9.64861 22.3051 8.57248 20.0306 8.37683C14.2586 7.86322 9.14705 12.1433 8.63345 17.9152C7.99756 25.0445 13.2926 31.3423 20.4097 31.9782C24.6775 32.3573 28.8474 31.0488 32.137 28.2973C35.4265 25.5459 37.4442 21.6816 37.8233 17.4138C37.9211 16.3377 37.9211 15.2738 37.8478 14.2221C38.4347 16.0564 38.7404 18.0008 38.7404 19.9818C38.7527 24.9956 36.8083 29.7036 33.262 33.25Z" fill="#066fde"/>
<path d="M20.0056 39.9998C14.6617 39.9998 9.64792 37.9209 5.86926 34.1423C2.09059 30.3636 0.0117188 25.3498 0.0117188 20.0059C0.0117188 14.662 2.09059 9.64822 5.86926 5.86956C9.64792 2.0909 14.6617 0.0120239 20.0056 0.0120239C25.3495 0.0120239 30.3633 2.0909 34.142 5.86956C37.9206 9.64822 39.9873 14.662 39.9873 20.0059C39.9873 25.3498 37.9084 30.3636 34.1297 34.1423C30.3511 37.9209 25.3373 39.9998 20.0056 39.9998ZM20.0056 1.24712C14.9918 1.24712 10.2838 3.20371 6.74972 6.7378C3.2034 10.2841 1.25904 14.9922 1.25904 19.9937C1.25904 25.0074 3.21563 29.7155 6.74972 33.2496C10.296 36.7959 15.0041 38.7402 20.0056 38.7402C25.0194 38.7402 29.7274 36.7837 33.2615 33.2496C36.8078 29.7032 38.7522 24.9952 38.7522 19.9937C38.7522 14.9799 36.7956 10.2719 33.2615 6.7378C29.7152 3.20371 25.0071 1.24712 20.0056 1.24712Z" fill="#066fde"/>
</svg>
<span>Air</span>
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,86 @@
import Button from '../button/button';
import BiometricData from '../biometric-data/biometric-data';
import useSteps from '../../../hooks/palmistry/use-steps';
export default function StepScanInfo() {
const steps = useSteps();
const onNext = () => {
steps.goNext();
};
return (
<>
<svg
version="1.1"
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
width="201"
height="200"
x="200"
y="200"
enableBackground="new 0 0 201 200"
xmlSpace="preserve"
>
<defs>
<path id="SVGID_1_" d="M.5 0h200v200H.5z"></path>
</defs>
<clipPath id="SVGID_00000063599037366629822520000002470084699890516397_">
<use xlinkHref="#SVGID_1_" overflow="visible"></use>
</clipPath>
<g clipPath="url(#SVGID_00000063599037366629822520000002470084699890516397_)">
<path fill="transparent" d="M.5 0h200v200H.5z"></path>
<linearGradient
id="SVGID_00000067238656879815263510000016374417917591180681_"
gradientUnits="userSpaceOnUse"
x1="100.5"
y1="202"
x2="100.5"
y2="57.46"
gradientTransform="matrix(1 0 0 -1 0 202)"
>
<stop offset=".15" stopColor="#fff" stopOpacity="0"></stop>
<stop offset="1" stopColor="#dee5f8"></stop>
</linearGradient>
<path
fill="url(#SVGID_00000067238656879815263510000016374417917591180681_)"
d="M200.5 0H.5v144.5h200V0z"
></path>
<path
fill="#ffffff"
d="M45.2 147c1.4 29.4 25.5 53 54.9 53s53.5-23.5 54.9-53H45.2zM155.4 144.5V85.2c0-4.4-3.4-7.5-8.3-7.6-4.1-.1-7.8 1.5-10.9 4.5-.7.7-1.3 1.4-1.9 2.2v-45c0-7.2-5.9-13.1-13.1-13.1-3 0-5.8 1-8 2.8v-.1c0-7.2-5.9-13.1-13.1-13.1-7.2 0-13.1 5.9-13.1 13.1v.1c-2.2-1.7-5-2.8-8-2.8-7.2 0-13.1 5.8-13.1 13.1v15c-2.2-1.7-5-2.8-8-2.8-7.2 0-13.1 5.8-13.1 13.1v80h110.6v-.1zM21.4 89.9c-.3 4.3-3.7 7.8-8 8.1-.4 0-.6.3-.6.7v.5c0 .3.3.6.6.7 4.3.2 7.7 3.7 8 8 0 .3.3.7.7.7h.4c.4 0 .7-.3.7-.6.4-3.8 4.3-7.7 8-8 .3 0 .6-.3.6-.6v-.6c0-.3-.2-.6-.5-.6-3.8-.3-7.8-4.2-8.1-8 0-.3-.3-.6-.6-.6h-.5c-.4-.3-.7 0-.7.3z"
></path>
<path
fill="#dee5f8"
d="M167.6 26.9c-.4 5.9-5.3 10.8-11.3 11.1-.5 0-.9.4-.9.9v.6c0 .5.4.9.9.9 6 .3 10.9 5.1 11.3 11 0 .5.5.9 1 .9h.5c.5 0 .9-.4 1-.9.6-5.2 6-10.6 11.4-11 .5 0 .8-.4.8-.8v-.8c0-.4-.3-.8-.8-.8-5.4-.5-11-5.8-11.4-11 0-.4-.4-.8-.9-.8h-.8c-.4-.1-.7.3-.8.7zM49.9 64.5c0-4.4 3.6-8 8-8s8 3.6 8 8v38.3c0 1.4 1.1 2.5 2.5 2.5s2.5-1.1 2.5-2.5V39.2c0-4.4 3.6-8 8-8s8 3.6 8 8v63.6c0 1.4 1.1 2.5 2.5 2.5s2.5-1.1 2.5-2.5V28.9c0-4.4 3.6-8 8-8s8 3.6 8 8v74c0 1.4 1.1 2.5 2.5 2.5s2.5-1.1 2.5-2.5V39.3c0-4.4 3.6-8 8-8s8 3.6 8 8v59.1c0 .2 0 .3.1.5 0 .5-.1 1.1-.1 1.6v27.4c0 1.4 1.1 2.5 2.5 2.5s2.5-1.1 2.5-2.5v-27.4c0-5.7 2.1-11.5 5.4-14.7 2.1-2.1 4.5-3 7.3-3 1.3 0 3.3.4 3.3 2.6v36.2c0 .3.1.5.1.7h-.1V147h5.1V85.2c0-4.4-3.4-7.5-8.3-7.6-4.1-.1-7.8 1.5-10.9 4.5-.7.7-1.3 1.4-1.9 2.2v-45c0-7.2-5.9-13.1-13.1-13.1-3 0-5.8 1-8 2.8v-.1c0-7.2-5.9-13.1-13.1-13.1-7.2 0-13.1 5.9-13.1 13.1v.1c-2.2-1.7-5-2.8-8-2.8-7.2 0-13.1 5.8-13.1 13.1v15c-2.2-1.7-5-2.8-8-2.8-7.2 0-13.1 5.8-13.1 13.1V147H50l-.1-82.5zM100.1 194.9c-26.7 0-48.5-21.2-49.9-47.9h-5c1.4 29.4 25.5 53 54.9 53s53.5-23.5 54.9-53h-5c-1.4 26.7-23.2 47.9-49.9 47.9z"
></path>
<path
d="M200.5 144.5c0-1.4-1.4-2.5-3.1-2.5H3.6c-1.7 0-3.1 1.1-3.1 2.5s1.4 2.5 3.1 2.5h193.9c1.6 0 3-1.1 3-2.5z"
fill="#6B7BAA"
></path>
<path
fill="#ffffff"
d="M178.2 105.8h-.5c-.3 0-.6.2-.6.5-.3 3.7-4.1 7.4-7.7 7.7-.3 0-.5.3-.5.6v.5c0 .3.2.5.5.6 3.6.3 7.3 4 7.7 7.7 0 .3.3.6.7.6h.4c.4 0 .6-.3.7-.6.3-4.1 3.6-7.4 7.7-7.7.3 0 .6-.3.6-.6v-.5c0-.3-.3-.6-.6-.6-4.1-.2-7.4-3.6-7.7-7.7-.1-.3-.4-.5-.7-.5z"
></path>
</g>
</svg>
<div className="palmistry-container__content">
<div>
<span className="palmistry-container__title palmistry-container__title_for-image">Lets scan your palms</span>
</div>
<div className="palmistry-container__description">
Follow the on-screen instructions, so we can analyze your palm lines and reveal your future, and the secrets
of your destiny!
</div>
</div>
<div className="palmistry-container__bottom-content">
<Button type="button" onClick={onNext} active>Let's do it</Button>
<BiometricData/>
</div>
</>
);
}

View File

@ -0,0 +1,96 @@
import React from 'react';
import { Step } from '@/hooks/palmistry/use-steps';
import useSteps from '@/hooks/palmistry/use-steps';
import ScannedPhoto from '@/components/palmistry/scanned-photo/scanned-photo';
enum PalmElement {
ThumbFinger = 'Thumb finger',
IndexFinger = 'Index finger',
MiddleFinger = 'Middle finger',
RingFinger = 'Ring finger',
LittleFinger = 'Little finger',
LifeLine = 'Life line',
HeadLine = 'Head line',
FateLine = 'Fate line',
HeartLine = 'Heart line',
}
const fingers = [
PalmElement.ThumbFinger,
PalmElement.IndexFinger,
PalmElement.MiddleFinger,
PalmElement.RingFinger,
PalmElement.LittleFinger,
];
const lines = [
PalmElement.LifeLine,
PalmElement.HeadLine,
PalmElement.FateLine,
PalmElement.HeartLine,
];
const palmElements = [
...fingers,
...lines,
];
const fingerChangeDelay = 1000;
const lineChangeDelay = 1500;
const goNextDelay = 12000;
export default function StepScanPhoto() {
const steps = useSteps();
const storedPhoto = steps.getStoredValue(Step.Upload);
const [curentElementIndex, setCurrentElementIndex] = React.useState(0);
const [photo, setPhoto] = React.useState('');
const [smallPhotoState, setSmallPhotoState] = React.useState(false);
const [title, setTitle] = React.useState(palmElements[0]);
const [sholdDisplayPalmLines, setSholdDisplayPalmLines] = React.useState(false);
const prevElementIndex = React.useRef<number | null>(null);
const goNextElement = (delay: number) => {
setTimeout(() => {
setCurrentElementIndex((prevState) => prevState + 1);
}, delay);
};
React.useEffect(() => {
if (storedPhoto) {
setPhoto(storedPhoto);
}
}, [storedPhoto]);
React.useEffect(() => {
if (curentElementIndex < palmElements.length && curentElementIndex !== prevElementIndex.current) {
prevElementIndex.current = curentElementIndex;
setTitle(palmElements[curentElementIndex]);
goNextElement(fingers.includes(palmElements[curentElementIndex]) ? fingerChangeDelay : lineChangeDelay);
setSholdDisplayPalmLines(lines.includes(palmElements[curentElementIndex]));
}
if (curentElementIndex >= palmElements.length) {
setSmallPhotoState(true);
setTimeout(steps.goNext, goNextDelay);
}
}, [curentElementIndex]);
if (!photo) return null;
return (
<>
<h2 className="palmistry-container__title">{title}</h2>
<ScannedPhoto photo={photo} small={smallPhotoState} displayLines={sholdDisplayPalmLines}/>
<h2 className="palmistry-container__waiting-title">We are putting together a comprehensive Palmistry Reading just for you!</h2>
<h3 className="palmistry-container__waiting-description">Wow, looks like there is a lot we can tell about your ambitious and strong self-confident future.</h3>
</>
);
}

View File

@ -0,0 +1,151 @@
import React from 'react';
import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { selectors } from "@/store";
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
import Button from '@/components/palmistry/button/button';
import EmailHeader from '@/components/palmistry/email-header/email-header';
import { ISubscriptionPlan } from "@/api/resources/SubscriptionPlans";
import { actions } from "@/store";
import { useApi } from "@/api";
const bestPlanId = 'stripe.15';
const getFormattedPrice = (plan: ISubscriptionPlan) => {
return (plan.trial!.price_cents / 100).toFixed(2);
}
export default function StepSubscriptionPlan() {
const steps = useSteps();
const dispatch = useDispatch();
const api = useApi();
const { i18n } = useTranslation();
const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan);
const storedEmail = steps.getStoredValue(Step.Email);
const [subscriptionPlan, setSubscriptionPlan] = React.useState('');
const [subscriptionPlans, setSubscriptionPlans] = React.useState<ISubscriptionPlan[]>([]);
const [email, setEmail] = React.useState(steps.getStoredValue(Step.Email));
const locale = i18n.language;
React.useEffect(() => {
if (activeSubPlanFromStore) {
setSubscriptionPlan(activeSubPlanFromStore.id);
}
}, [activeSubPlanFromStore]);
React.useEffect(() => {
(async () => {
const { sub_plans } = await api.getSubscriptionPlans({ locale });
const plans = sub_plans
.filter((plan: ISubscriptionPlan) => plan.provider === "stripe")
.sort((a, b) => {
if (!a.trial || !b.trial) {
return 0;
}
if (a?.trial?.price_cents < b?.trial?.price_cents) {
return -1;
}
if (a?.trial?.price_cents > b?.trial?.price_cents) {
return 1;
}
return 0;
});
setSubscriptionPlans(plans.filter((plan) => plan.trial?.price_cents));
})();
}, [api, locale]);
React.useEffect(() => {
if (subscriptionPlan) {
const targetSubPlan = subscriptionPlans.find((sub_plan) => sub_plan.id === subscriptionPlan);
if (targetSubPlan) {
dispatch(actions.payment.update({ activeSubPlan: targetSubPlan }));
}
}
}, [subscriptionPlan]);
React.useEffect(() => {
setEmail(storedEmail || '');
}, [storedEmail]);
const onNext = () => {
steps.saveCurrent(subscriptionPlan);
steps.goNext();
};
return (
<>
<EmailHeader email={email}/>
<div className="palmistry-container__title">
We've helped millions of people to reveal the destiny of their love life and what the future holds for them and
their families.
</div>
<div className="palmistry-container__image">
<svg width="153" height="133" viewBox="0 0 153 133" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_16903_24136)">
<rect width="153" height="133" fill=""></rect>
<path
d="M20.5004 33.3398H19.899C19.5382 33.3398 19.2375 33.5995 19.2375 33.9458C18.9368 38.0145 14.4866 42.1697 10.2469 42.5449C9.91613 42.5737 9.64551 42.8623 9.64551 43.1797V43.7857C9.64551 44.1319 9.91612 44.3916 10.2769 44.4205C14.4866 44.709 18.7864 48.8931 19.2375 52.9618C19.2675 53.3369 19.5983 53.6255 20.0193 53.6255H20.4402C20.8612 53.6255 21.192 53.3369 21.222 52.933C21.5829 48.3737 25.4016 44.6225 30.1525 44.3916C30.5434 44.3628 30.814 44.0742 30.814 43.6991V43.1797C30.814 42.8046 30.5133 42.516 30.1525 42.4871C25.3715 42.2563 21.5227 38.4762 21.222 33.8592C21.1619 33.5995 20.8612 33.3398 20.5004 33.3398Z"
fill="rgba(172, 209, 255, 0.7)"
></path>
<path
d="M90.0847 6.81456C86.8721 6.81456 84.2788 4.22585 84.2788 1.01896C84.2788 0.65834 83.995 0.375 83.6337 0.375C83.2725 0.375 82.9886 0.65834 82.9886 1.01896C82.9886 4.22585 80.3953 6.81456 77.1827 6.81456C76.8214 6.81456 76.5376 7.0979 76.5376 7.45851C76.5376 7.81913 76.8214 8.10247 77.1827 8.10247C80.3953 8.10247 82.9886 10.6912 82.9886 13.8981C82.9886 14.2587 83.2725 14.542 83.6337 14.542C83.995 14.542 84.2788 14.2587 84.2788 13.8981C84.2788 10.6912 86.8721 8.10247 90.0847 8.10247C90.446 8.10247 90.7298 7.81913 90.7298 7.45851C90.7298 7.0979 90.446 6.81456 90.0847 6.81456Z"
fill="rgba(172, 209, 255, 0.3)"
></path>
<path
d="M145.334 117.4C139.059 117.4 133.994 112.343 133.994 106.08C133.994 105.376 133.44 104.822 132.734 104.822C132.029 104.822 131.474 105.376 131.474 106.08C131.474 112.343 126.409 117.4 120.135 117.4C119.429 117.4 118.875 117.953 118.875 118.657C118.875 119.362 119.429 119.915 120.135 119.915C126.409 119.915 131.474 124.971 131.474 131.235C131.474 131.939 132.029 132.492 132.734 132.492C133.44 132.492 133.994 131.939 133.994 131.235C133.994 124.971 139.059 119.915 145.334 119.915C146.04 119.915 146.594 119.362 146.594 118.657C146.594 117.953 146.04 117.4 145.334 117.4Z"
fill="rgba(172, 209, 255, 0.45)"
></path>
<path
d="M-5.56678 124.119L138.066 29.6205C142.669 26.5921 148.878 28.0499 151.652 32.8107C154.427 37.5714 152.628 43.6796 147.716 46.1774L-5.56678 124.119Z"
fill="url(#paint0_linear_16903_24136)"
></path>
</g>
<defs>
<linearGradient
id="paint0_linear_16903_24136"
x1="141.466"
y1="50.4613"
x2="13.2256"
y2="125.204"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#9babd9"></stop>
<stop offset="1" stopColor="#EBEFFF"></stop>
</linearGradient>
<clipPath id="clip0_16903_24136">
<rect width="153" height="133" fill="white"></rect>
</clipPath>
</defs>
</svg>
</div>
<div className="palmistry-container__plans">
{subscriptionPlans.map((plan) => (
<div
key={plan.id}
className={`palmistry-container__plan ${subscriptionPlan === plan.id ? 'palmistry-container__plan_active' : ''}`}
onClick={() => setSubscriptionPlan(plan.id)}
>
<h3>${getFormattedPrice(plan)}</h3>
</div>
))}
</div>
<span className={`palmistry-container__subscription-text ${subscriptionPlan === bestPlanId ? 'palmistry-container__subscription-text_active' : ''}`}>
It costs us $13.21 to compensate our AURA employees for the trial, but please choose the amount you are comfortable with.
</span>
<Button className="palmistry-container__button" type="button" onClick={onNext} active>
Continue
</Button>
</>
);
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,72 @@
import Button from '@/components/palmistry/button/button';
import useSteps from '@/hooks/palmistry/use-steps';
export default function StepWelcome() {
const steps = useSteps();
const onNext = () => {
steps.goNext();
};
return (
<>
<svg width="200" height="200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8.4 92.45c-.26 4.21-3.63 7.671-7.82 7.881-.34.03-.58.29-.58.63v.47c0 .34.26.61.58.63 4.16.21 7.5 3.61 7.82 7.8.03.34.32.63.68.63h.37c.34 0 .63-.26.68-.61.39-3.71 4.16-7.53 7.84-7.8.32-.03.55-.29.55-.58v-.55c0-.32-.24-.55-.53-.58-3.71-.34-7.61-4.14-7.87-7.85a.595.595 0 0 0-.58-.55h-.53c-.37-.08-.63.16-.63.47l.02.01z"
fill="rgba(222, 229, 249, 0.45)"
></path>
<path
d="M153.83 0h-.5c-.3 0-.56.23-.56.53-.25 3.56-3.99 7.2-7.54 7.53a.57.57 0 0 0-.5.56v.53c0 .3.23.53.53.56 3.53.25 7.14 3.92 7.52 7.48.03.33.3.58.66.58h.35c.35 0 .63-.25.66-.61.3-3.99 3.51-7.28 7.49-7.48.33-.03.56-.28.56-.61v-.45a.61.61 0 0 0-.56-.61c-4.01-.2-7.24-3.51-7.49-7.55-.05-.23-.3-.45-.61-.45l-.01-.01z"
fill="rgba(222, 229, 249, 0.3)"
></path>
<path
d="M185.65 64.52c-.39 5.78-5.14 10.51-11.07 10.79-.47.03-.84.41-.84.84v.64c0 .46.37.84.84.84 5.9.28 10.62 4.96 11.07 10.69.03.48.45.87.97.87h.52c.5 0 .89-.36.94-.84.55-5.09 5.88-10.34 11.12-10.69.45-.03.79-.38.79-.81v-.76c0-.41-.31-.76-.76-.81-5.27-.46-10.75-5.68-11.15-10.79a.825.825 0 0 0-.84-.76h-.76c-.45.05-.81.38-.84.81l.01-.02z"
fill="#dee5f9"
></path>
<path
d="M42.1 67.67c0-4.31 3.52-7.82 7.84-7.82s7.84 3.51 7.84 7.82v37.42c0 1.36 1.1 2.46 2.47 2.46s2.47-1.1 2.47-2.46V42.97c0-4.31 3.52-7.82 7.84-7.82s7.84 3.51 7.84 7.82v62.1c0 1.36 1.1 2.46 2.47 2.46s2.47-1.1 2.47-2.46V32.84c0-4.31 3.52-7.82 7.84-7.82s7.84 3.51 7.84 7.82v72.25c0 1.36 1.1 2.46 2.47 2.46s2.47-1.1 2.47-2.46v-62.1c0-4.31 3.52-7.82 7.84-7.82s7.84 3.51 7.84 7.82v57.77c0 .15.03.31.05.46-.03.51-.05 1.03-.05 1.51v26.78c0 1.36 1.1 2.46 2.47 2.46s2.47-1.1 2.47-2.46V102.7c0-5.56 2.08-11.2 5.32-14.38 2.03-2 4.42-2.97 7.09-2.92 1.23.03 3.26.38 3.26 2.49v35.4c0 .26.05.49.13.72l-.13.03v24.23h4.96V87.9c0-4.31-3.34-7.36-8.12-7.43-4.01-.08-7.66 1.44-10.64 4.36-.67.64-1.28 1.36-1.85 2.13V42.99c0-7.02-5.73-12.76-12.8-12.76-2.96 0-5.68 1-7.84 2.69v-.08c0-7.02-5.73-12.76-12.8-12.76s-12.8 5.72-12.8 12.76v.08a12.669 12.669 0 0 0-7.84-2.69c-7.04 0-12.8 5.72-12.8 12.76V57.6a12.669 12.669 0 0 0-7.84-2.69c-7.04 0-12.8 5.72-12.8 12.76v80.59h5.04V67.67h-.02z"
fill="#9babd9"
></path>
<path
d="M91.12 195.01c-26.04 0-47.38-20.75-48.76-46.74h-4.91c1.38 28.77 24.92 51.74 53.67 51.74s52.29-22.97 53.67-51.74h-4.93c-1.35 26.02-22.69 46.74-48.74 46.74z"
fill="#dee5f9"
></path>
<path
d="M171.18 140.539H11.84c-1.41 0-2.57 1.16-2.57 2.57v2.57c0 1.42 1.16 2.57 2.57 2.57h159.34c1.41 0 2.57-1.16 2.57-2.57v-2.57c0-1.42-1.16-2.57-2.57-2.57z"
fill="#6B7BAA"
></path>
</svg>
<div className="palmistry-container__content">
<div className="palmistry-container__description">
<span className="palmistry-container__title">Find your happiness with highly-personalized predictions.</span>
</div>
</div>
<div className="palmistry-container__bottom-content">
<Button type="button" onClick={onNext} active>
Lets Begin
</Button>
<div className="palmistry-container__notification-wrapper">
<div className="palmistry-container__policy">
<p>
By continuing, you agree to our{' '}
<a href="https://aura.wit.life/terms" target="_blank" rel="noreferrer nofollow">
EULA
</a>{' '}
and{' '}
<a href="https://aura.wit.life/privacy" target="_blank" rel="noreferrer nofollow">
Privacy Notice
</a>
.
</p>
</div>
<span className="palmistry-container__purposes">
This Palm Reading App is for entertainment purposes only and will not make death predictions
</span>
</div>
</div>
</>
);
}

View File

@ -0,0 +1,45 @@
import Button from '../button/button';
import useSteps, { WishChoice } from '../../../hooks/palmistry/use-steps';
export default function StepWish() {
const steps = useSteps();
const onNext = (choice: WishChoice) => {
steps.saveCurrent(choice);
steps.goNext(choice);
};
return (
<>
<div className="palmistry-container__title-wrapper">
<h3>What aspects of your life do you wish to gain insight into through palmistry?</h3>
</div>
<div className="palmistry-container__button-wrapper">
<Button
type="button"
active={steps.storedValue === WishChoice.Love}
onClick={() => onNext(WishChoice.Love)}
>
Love & Relationship
</Button>
<Button
type="button"
active={steps.storedValue === WishChoice.Health}
onClick={() => onNext(WishChoice.Health)}
>
Health & Vitality
</Button>
<Button
type="button"
active={steps.storedValue === WishChoice.Career}
onClick={() => onNext(WishChoice.Career)}
>
Career & Destiny
</Button>
</div>
</>
);
}

View File

@ -0,0 +1,112 @@
.steps-manager {
--font-family-main: "SF Pro Text", sans-serif;
--stone-grey: #95959d;
--button-color: #121620;
--svg-blue: var(--strong-blue);
--pale-lavender: #dee5f9;
--pale-lavender-20: #dee5f9;
--orange: #ff9649;
--coral: #ff5c5d;
--rich-blue: #2b7cf6;
--bright-white: #fbfbfb;
--bright-red: #ff5758;
--light-gray: #d9d9d9;
--vivid-yellow: #ffc700;
--pale-gray: #c2cad8;
--pale-green: #75db9c;
--pale-cerulean: #82b7ef;
--greyish: #afafaf;
--vivid-green: #00ff38;
--dark-charcoal: #191f2d;
--blueish-gray: #6b76aa;
--violet: #9949ff;
--light-lavender: #c5c5d1;
--pale-pink: #fcd3df;
--cream-yellow: #fffbcd;
--pale-aqua: #c9fae6;
--pale-seafoam: #d3f1e1;
--pale-lilac: #dec6fe;
--pale-peach: #fdddc8;
--deep-charcoal: #1e1e1e;
--black: #000;
--bright-sea-green: #04a777;
--deep-cornflower-blue: #4663b7;
--charcoal-grey: #505051;
--pale-light-cerulean: #acd1ff;
--main-gradient: #fff;
--strong-blue: #066fde;
--strong-blue-text: #066fde;
--strong-blue-80: rgba(6, 111, 222, 0.8);
--midnight-black: #121620;
--footer-small-text: #121620;
--button-active: #fff;
--button-background: var(--pale-blue);
--button-active-bg: var(--strong-blue);
--slate-blue: #6b7baa;
--slate-blue-placeholder: #6b7baa;
--pale-blue: #eff2fd;
--pale-blue-input: #eff2fd;
--midnight-black-input: #121620;
--greyish-blue: #8e8e93;
--soft-blue: #4a567a;
--soft-blue-gray: #4a567a;
--soft-blue-periwinkle: #4a567a;
--gentle-blue: #9babd9;
--gentle-blue-svg: #9babd9;
--light-silver: #c7c7c7;
--light-silver-to-white: #c7c7c7;
--light-silver-to-lilac-blue: #c7c7c7;
--light-cornflower-blue: #c2ceee;
--white: #fff;
--dark-blue: #202b47;
--progress-line: #00a3ff;
--footer-shield: #b5c4ff;
--blue-color-text: #0066fd;
--black-color-text: #0066fd;
--transparent-to-gold: transparent;
--transparent-to-white: transparent;
--transparent-to-periwinkle: transparent;
--white-to-transparent: #fff;
--loader-background: rgba(16, 32, 77, 0.35);
display: flex;
flex-direction: column;
height: 100%;
margin: 0 auto;
max-width: 560px;
position: relative;
width: 100%;
}
.steps-manager__main {
display: flex;
height: 100vh;
position: relative;
width: 100%;
}
.steps-manager__motion-div_no-transform {
transform: none !important;
}
* {
scrollbar-color: #cde8f9 #fff;
scrollbar-color: #cde8f9 var(--white);
scrollbar-width: auto;
}
::-webkit-scrollbar {
width: 13px;
}
::-webkit-scrollbar-track {
margin: 3px;
}
::-webkit-scrollbar-thumb {
background-color: #cde8f9;
border: 3px solid #fff;
border: 3px solid var(--white);
border-radius: 10px;
height: 20px;
}

View File

@ -0,0 +1,170 @@
import React from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { useLocation } from 'react-router-dom';
import { useSelector } from "react-redux";
import { useNavigate } from 'react-router-dom';
import './steps-manager.css';
import routes from '@/routes';
import { selectors } from "@/store";
import Progressbar from '@/components/palmistry/progress-bar/progress-bar';
import PalmistryContainer from '@/components/palmistry/palmistry-container/palmistry-container';
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
import StepWelcome from '@/components/palmistry/step-welcome/step-welcome';
import StepGender from '@/components/palmistry/step-gender/step-gender';
import StepBirthdate from '@/components/palmistry/step-birthdate/step-birthdate';
import StepPalmsHold from '@/components/palmistry/step-palms-hold/step-palms-hold';
import StepWish from '@/components/palmistry/step-wish/step-wish';
import StepRelationshipStatus from '@/components/palmistry/step-relationship-status/step-relationship-status';
import StepResonatedElement from '@/components/palmistry/step-resonated-element/step-resonated-element';
import StepColorYouLike from '@/components/palmistry/step-color-you-like/step-color-you-like';
import StepDecisions from '@/components/palmistry/step-decisions/step-decisions';
import StepGuidancePlan from '@/components/palmistry/step-guidance-plan/step-guidance-plan';
import StepPersonalStatement from '@/components/palmistry/step-personal-statement/step-personal-statement';
import StepScanInfo from '@/components/palmistry/step-scan-info/step-scan-info';
import StepUpload from '@/components/palmistry/step-upload/step-upload';
import StepScanPhoto from '@/components/palmistry/step-scan-photo/step-scan-photo';
import StepEmail from '@/components/palmistry/step-email/step-email';
import StepSubscriptionPlan from '@/components/palmistry/step-subscription-plan/step-subscription-plan';
import StepPaywall from '@/components/palmistry/step-paywall/step-paywall';
import PaymentScreen from '@/components/palmistry/payment-screen/payment-screen';
import DiscountScreen from '@/components/palmistry/discount-screen/discount-screen';
import PremiumBundleScreen from '@/components/palmistry/premium-bundle-screen/premium-bundle-screen';
const PalmistryContainerWrapper = (props: { children: React.ReactNode, currentStep: Step }) => {
return (
<PalmistryContainer
singleQuestion={[
Step.Wish,
Step.RelationshipStatus,
Step.ResonatedElement,
Step.ColorYouLike,
Step.Decisions,
].includes(props.currentStep)}
type={props.currentStep}
>{props.children}</PalmistryContainer>
);
};
const animationDuration = 0.2;
export default function StepsManager() {
const steps = useSteps();
const { pathname } = useLocation();
const subscriptionStatus = useSelector(selectors.selectStatus);
const navigate = useNavigate();
const [modalIsOpen, setModalIsOpen] = React.useState(false);
React.useLayoutEffect(() => {
if (!steps.isInited) return;
steps.goFirstUnpassedStep();
}, [steps.isInited]);
React.useEffect(() => {
if (subscriptionStatus === "subscribed" && steps.current !== Step.Payment) {
navigate(routes.client.home());
}
}, [subscriptionStatus]);
const motionDivClassName = [
'steps-manager__motion-div',
modalIsOpen ? 'steps-manager__motion-div_no-transform' : '',
];
const nonSliderSteps = [
Step.Payment,
Step.Discount,
Step.PremiumBundle,
];
return (
<div className="steps-manager">
{steps.currentNumber >= steps.progressBarRange[0] && steps.currentNumber <= steps.progressBarRange[1] && (
<Progressbar step={steps.currentNumber}/>
)}
<main className="steps-manager__main">
{nonSliderSteps.includes(steps.current as Step) && (
<PalmistryContainerWrapper currentStep={steps.current as Step}>
{steps.current === Step.Payment && <PaymentScreen/>}
{steps.current === Step.Discount && <DiscountScreen/>}
{steps.current === Step.PremiumBundle && <PremiumBundleScreen/>}
</PalmistryContainerWrapper>
)}
{!nonSliderSteps.includes(steps.current as Step) && (
<AnimatePresence
mode="wait"
initial={false}
>
<motion.div
className={motionDivClassName.join(' ')}
key={pathname}
initial="pageInitial"
animate="pageAnimate"
exit="pageExit"
variants={{
pageInitial: {
transform: 'translateX(100vw)',
width: '100%',
},
pageAnimate: {
transform: 'translateX(0)',
width: '100%',
},
pageExit: {
transform: 'translateX(-200vw)',
opacity: 0,
width: '100%',
},
}}
transition={{
duration: animationDuration,
ease: 'linear',
}}
>
<PalmistryContainerWrapper currentStep={steps.current as Step}>
{steps.current === Step.Welcome && <StepWelcome/>}
{steps.current === Step.Gender && <StepGender/>}
{steps.current === Step.Birthdate && <StepBirthdate/>}
{steps.current === Step.PalmsHold && <StepPalmsHold/>}
{steps.current === Step.Wish && <StepWish/>}
{steps.current === Step.RelationshipStatus && <StepRelationshipStatus/>}
{steps.current === Step.ResonatedElement && <StepResonatedElement/>}
{steps.current === Step.ColorYouLike && <StepColorYouLike/>}
{steps.current === Step.Decisions && <StepDecisions/>}
{steps.current === Step.GuidancePlan && <StepGuidancePlan/>}
{steps.current === Step.PersonalStatement && <StepPersonalStatement/>}
{steps.current === Step.ScanInfo && <StepScanInfo/>}
{steps.current === Step.Upload && <StepUpload onOpenModal={setModalIsOpen}/>}
{steps.current === Step.ScanPhoto && <StepScanPhoto/>}
{steps.current === Step.Email && <StepEmail/>}
{steps.current === Step.SubscriptionPlan && <StepSubscriptionPlan/>}
{steps.current === Step.Paywall && <StepPaywall/>}
</PalmistryContainerWrapper>
</motion.div>
</AnimatePresence>
)}
</main>
</div>
);
}

View File

@ -0,0 +1,3 @@
.stripe-form__button {
margin-top: 16px;
}

View File

@ -0,0 +1,64 @@
import React from 'react';
import { StripeError } from '@stripe/stripe-js';
import {
PaymentElement,
useElements,
useStripe,
} from '@stripe/react-stripe-js';
import './stripe-form.css';
import Button from '../button/button';
type Props = {
subscriptionReceiptId: string;
isProcessing: boolean;
paymentResultUrl: string;
onSubmit: () => void;
onSuccess: () => void;
onError: (error: StripeError) => void;
};
export default function StripeForm(props: Props) {
const stripe = useStripe();
const elements = useElements();
const [formReady, setFormReady] = React.useState(false);
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!stripe || !elements) return;
props.onSubmit();
try {
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: props.paymentResultUrl,
},
});
if (error) {
props.onError(error);
} else {
props.onSuccess();
}
} catch (error) {
props.onError(error as StripeError);
}
};
return (
<form className="stripe-form" onSubmit={onSubmit}>
<PaymentElement onReady={() => setFormReady(true)}/>
<div className="stripe-form__button">
<Button type="submit" disabled={props.isProcessing || !formReady} active>
Pay
</Button>
</div>
</form>
);
}

View File

@ -0,0 +1,33 @@
.upload-modal {
position: absolute;
top: 300px;
width: calc(100% - 62px);
z-index: 1;
}
.upload-modal__menu {
background: var(--main-gradient);
border: 2px solid var(--transparent-to-periwinkle);
border-radius: 8px;
filter: drop-shadow(0 0 14px rgba(12, 31, 65, .24));
padding: 0 10px;
width: 100%;
}
.upload-modal__menu li {
align-items: center;
cursor: pointer;
display: flex;
height: 50px;
justify-content: space-between;
padding: 0 5px;
}
.upload-modal__menu li:not(:last-child) {
border-bottom: 1px solid var(--light-silver-to-white);
}
.upload-modal__menu li > div, .upload-modal__menu li > label {
align-items: center;
color: var(--midnight-black);
display: flex;
justify-content: space-between;
width: 100%;
cursor: pointer;
}

View File

@ -0,0 +1,100 @@
import './upload-modal.css';
import ModalOverlay from '../modal-overlay/modal-overlay';
type Props = {
onClose: () => void;
onSelectFile: (event: React.ChangeEvent<HTMLInputElement>) => void;
onChooseCamera: () => void;
};
export default function UploadModal(props: Props) {
return (
<div className="upload-modal">
<ModalOverlay onClick={props.onClose}/>
<ul className="upload-modal__menu">
<li>
<div onClick={props.onChooseCamera}>
Take Photo
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="gradient_svg"
x1="11.1879"
y1="1"
x2="11.1879"
y2="18"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FDDAA6"></stop>
<stop offset="1" stopColor="#DEB475"></stop>
</linearGradient>
</defs>
<path
d="M11.8799 15.6202C14.8844 15.6202 17.3199 13.1847 17.3199 10.1802C17.3199 7.17581 14.8844 4.74023 11.8799 4.74023C8.87551 4.74023 6.43994 7.17581 6.43994 10.1802C6.43994 13.1847 8.87551 15.6202 11.8799 15.6202Z"
stroke="#121620"
strokeMiterlimit="10"
></path>
<path
d="M8.47998 10.1793C8.47998 8.2753 9.97598 6.7793 11.88 6.7793"
stroke="#121620"
strokeMiterlimit="10"
strokeLinecap="round"
></path>
<path
d="M18.068 4.604L15.416 1H8.344L5.692 4.604H1V18H22.76V4.604H18.068Z"
stroke="#121620"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M4.33186 2.56445H2.35986"
stroke="#121620"
strokeMiterlimit="10"
strokeLinecap="round"
strokeLinejoin="round"
></path>
</svg>
</div>
</li>
<li>
<input
id="upload-input"
type="file"
accept="image/*"
style={{ display: 'none' }}
onChange={props.onSelectFile}
/>
<label htmlFor="upload-input">
Choose File
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="gradient_svg"
x1="11.1879"
y1="1"
x2="11.1879"
y2="18"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FDDAA6"></stop>
<stop offset="1" stopColor="#DEB475"></stop>
</linearGradient>
</defs>
<path
d="M2.81178 17.9977H22.5658V5.59397C22.5658 5.08863 22.1524 4.67517 21.6471 4.67517H5.10877C4.60343 4.67517 4.18997 5.08863 4.18997 5.59397V16.5276C4.18997 17.2626 3.6387 17.9517 2.90367 17.9977C2.12269 18.0436 1.43359 17.4005 1.43359 16.6195V1.91879C1.43359 1.41346 1.84705 1 2.35239 1H8.32455L9.70274 2.37819H20.2689V3.75638"
stroke="#121620"
strokeMiterlimit="10"
strokeLinejoin="round"
></path>
</svg>
</label>
</li>
</ul>
</div>
);
}

View File

@ -36,3 +36,39 @@
font-style: normal;
src: url(./assets/media/sf-mono-bold.otf) format("opentype")
}
@font-face {
font-display: swap;
font-family: Alata Regular;
font-style: normal;
font-weight: 400;
src: url(./assets/media/alata-regular.woff2)
format("woff2");
}
@font-face {
font-display: swap;
font-family: OpenSans Regular;
font-style: normal;
font-weight: 400;
src: url(./assets/media/open-sans-regular.woff2)
format("woff2");
}
@font-face {
font-display: swap;
font-family: OpenSans Regular;
font-style: normal;
font-weight: 600;
src: url(./assets/media/open-sans-semibold.woff2)
format("woff2");
}
@font-face {
font-display: swap;
font-family: OpenSans Regular;
font-style: normal;
font-weight: 700;
src: url(./assets/media/open-sans-bold.woff2)
format("woff2");
}

View File

@ -0,0 +1,204 @@
import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import routes from '@/routes';
export enum Step {
Welcome = 'welcome',
Gender = 'gender',
Birthdate = 'birthdate',
PalmsHold = 'palms-hold',
Wish = 'wish',
RelationshipStatus = 'relationship-status',
ResonatedElement = 'resonated-element',
ColorYouLike = 'color-you-like',
Decisions = 'decisions',
GuidancePlan = 'guidance-plan',
PersonalStatement = 'personal-statement',
ScanInfo = 'scan-info',
Upload = 'upload',
ScanPhoto = 'scan-photo',
Email = 'email',
SubscriptionPlan = 'subscription-plan',
Paywall = 'paywall',
Payment = 'payment',
Discount = 'discount',
PremiumBundle = 'premium-bundle',
}
export const sortedList = [
Step.Welcome,
Step.Gender,
Step.Birthdate,
Step.PalmsHold,
Step.Wish,
Step.RelationshipStatus,
Step.ResonatedElement,
Step.ColorYouLike,
Step.Decisions,
Step.GuidancePlan,
Step.PersonalStatement,
Step.ScanInfo,
Step.Upload,
Step.ScanPhoto,
Step.Email,
Step.SubscriptionPlan,
Step.Paywall,
Step.Payment,
Step.Discount,
Step.PremiumBundle,
];
export enum GenderChoice {
Male = 'male',
Female = 'female',
}
export enum WishChoice {
Love = 'Love & Relationship',
Health = 'Health & Vitality',
Career = 'Career & Destiny',
}
export enum RelationshipStatusChoice {
Single = 'single',
InRelationship = 'relationship',
}
export enum ResonatedElementChoice {
Earth = 'Earth',
Water = 'Water',
Fire = 'Fire',
Air = 'Air',
}
export enum ColorYouLikeChoice {
Red = 'Red',
Yellow = 'Yellow',
Blue = 'Blue',
Orange = 'Orange',
Green = 'Green',
Violet = 'Violet',
}
export enum DecisionsChoice {
Heart = 'Heart',
Head = 'Head',
Both = 'Both',
}
export type Choice = GenderChoice | WishChoice | RelationshipStatusChoice | ResonatedElementChoice | ColorYouLikeChoice | DecisionsChoice;
const buildStoredValues = (value: string | ((s: Step) => string)) => {
return sortedList.reduce((acc, step) => ({
...acc,
[step]: typeof value === 'function' ? value(step) : value,
}), {} as Record<Step, string>);
};
export default function useSteps() {
const { pathname } = useLocation();
const navigate = useNavigate();
const pathnameTail = pathname.split('/').pop();
const current = pathnameTail === 'palmistry' ? Step.Welcome : pathnameTail;
const list = Object.values(Step);
const count = list.length - 1;
const progressBarRange = [1, 10];
const isWelcome = current === Step.Welcome;
const defaultStep = Step.Welcome;
const currentNumber = React.useMemo(() => sortedList.findIndex((s) => s === current), [current]);
const isInvalid = currentNumber === -1;
const [isInited, setIsInited] = React.useState(false);
const [storedValues, setStoredValues] = React.useState(buildStoredValues(''));
const [firstUnpassedStep, setFirstUnpassedStep] = React.useState<Step | null>(null);
const getFromStorage = (key: Step | 'firstUnpassedStep') => {
return localStorage.getItem(`palmistry.${key}`) || '';
};
React.useEffect(() => {
if (pathnameTail === 'palmistry') {
navigate(routes.client.palmistryWelcome());
}
setIsInited(true);
setStoredValues(buildStoredValues(getFromStorage));
setFirstUnpassedStep(getFromStorage('firstUnpassedStep') as Step | null);
}, []);
const getStoredValue = (key: Step) => {
return storedValues[key] || '';
};
function saveToStorage(key: Step | 'firstUnpassedStep', value: string) {
localStorage.setItem(`palmistry.${key}`, value);
}
function getPreviousStep() {
if (current === Step.ResonatedElement && getStoredValue(Step.Wish) !== WishChoice.Love) {
return sortedList[currentNumber - 2];
} else {
return sortedList[currentNumber - 1];
}
}
function getNextStep(choice?: Choice) {
if (current === Step.Wish && choice !== WishChoice.Love) {
return sortedList[currentNumber + 2];
} else {
return sortedList[currentNumber + 1];
}
}
function goBack() {
navigate(`/palmistry/${getPreviousStep()}`);
}
function goNext(choice?: Choice) {
const nextStep = getNextStep();
setFirstUnpassedStep(nextStep as Step);
if (sortedList.indexOf(nextStep) > sortedList.indexOf(firstUnpassedStep as Step)) {
saveToStorage('firstUnpassedStep', nextStep as Step);
}
navigate(`/palmistry/${getNextStep(choice)}`);
}
function goFirstUnpassedStep() {
if (!firstUnpassedStep) {
navigate(`/palmistry/${sortedList[0]}`);
return;
}
navigate(`/palmistry/${firstUnpassedStep}`);
}
function saveCurrent(value: string) {
saveToStorage(current as Step, value);
}
return {
isInited,
current,
list,
count,
progressBarRange,
isWelcome,
defaultStep,
currentNumber,
isInvalid,
storedValue: storedValues[current as Step],
firstUnpassedStep,
goBack,
goNext,
saveToStorage,
saveCurrent,
getStoredValue,
goFirstUnpassedStep,
setFirstUnpassedStep,
};
}

View File

@ -0,0 +1,49 @@
import React from 'react';
const timerMinutes = 15;
const initialTimeLeft = timerMinutes * 60 * 1000;
const storageKey = 'palmistry.timeLeft';
const addLeadingZero = (value: number) => (value < 10 ? `0${value}` : value);
const buildTimeCaption = (time: number) => {
const minutes = Math.floor(time / 60000);
const seconds = Math.floor((time % 60000) / 1000);
return `${addLeadingZero(minutes)}:${addLeadingZero(seconds)}`;
};
export default function useTimer() {
const [timeLeft, setTimeLeft] = React.useState<number | null>(null);
const time = React.useMemo(() => {
if (timeLeft == null) return buildTimeCaption(initialTimeLeft);
return buildTimeCaption(timeLeft);
}, [timeLeft]);
React.useEffect(() => {
const storedTimeLeft = localStorage.getItem(storageKey);
setTimeLeft(storedTimeLeft ? parseInt(storedTimeLeft) : initialTimeLeft);
}, []);
React.useEffect(() => {
if (timeLeft === null) return;
if (timeLeft <= 0) {
localStorage.removeItem(storageKey);
return;
}
const interval = setInterval(() => {
const newTimeLeft = timeLeft - 1000;
setTimeLeft(newTimeLeft);
localStorage.setItem(storageKey, `${newTimeLeft}`);
}, 1000);
return () => clearInterval(interval);
}, [timeLeft]);
return time;
}

View File

@ -0,0 +1,105 @@
import { DecisionsChoice } from './use-steps';
export enum ZodiacSign {
Aries = 'Aries',
Taurus = 'Taurus',
Gemini = 'Gemini',
Cancer = 'Cancer',
Leo = 'Leo',
Virgo = 'Virgo',
Libra = 'Libra',
Scorpio = 'Scorpio',
Sagittarius = 'Sagittarius',
Capricorn = 'Capricorn',
Aquarius = 'Aquarius',
Pisces = 'Pisces',
}
export default function useZodiacSign() {
const getSignByDate = (month: number, day: number): ZodiacSign => {
if ((month === 3 && day >= 21) || (month === 4 && day <= 19)) return ZodiacSign.Aries;
if ((month === 4 && day >= 20) || (month === 5 && day <= 20)) return ZodiacSign.Taurus;
if ((month === 5 && day >= 21) || (month === 6 && day <= 20)) return ZodiacSign.Gemini;
if ((month === 6 && day >= 21) || (month === 7 && day <= 22)) return ZodiacSign.Cancer;
if ((month === 7 && day >= 23) || (month === 8 && day <= 22)) return ZodiacSign.Leo;
if ((month === 8 && day >= 23) || (month === 9 && day <= 22)) return ZodiacSign.Virgo;
if ((month === 9 && day >= 23) || (month === 10 && day <= 22)) return ZodiacSign.Libra;
if ((month === 10 && day >= 23) || (month === 11 && day <= 21)) return ZodiacSign.Scorpio;
if ((month === 11 && day >= 22) || (month === 12 && day <= 21)) return ZodiacSign.Sagittarius;
if ((month === 12 && day >= 22) || (month === 1 && day <= 19)) return ZodiacSign.Capricorn;
if ((month === 1 && day >= 20) || (month === 2 && day <= 18)) return ZodiacSign.Aquarius;
if ((month === 2 && day >= 19) || (month === 3 && day <= 20)) return ZodiacSign.Pisces;
throw new Error('Invalid date');
}
const getDecisionMakingStatistics = (sign: ZodiacSign) => {
return {
[ZodiacSign.Aries]: {
[DecisionsChoice.Heart]: 49,
[DecisionsChoice.Head]: 35,
[DecisionsChoice.Both]: 16,
},
[ZodiacSign.Taurus]: {
[DecisionsChoice.Heart]: 48,
[DecisionsChoice.Head]: 31,
[DecisionsChoice.Both]: 21,
},
[ZodiacSign.Gemini]: {
[DecisionsChoice.Heart]: 33,
[DecisionsChoice.Head]: 48,
[DecisionsChoice.Both]: 19,
},
[ZodiacSign.Cancer]: {
[DecisionsChoice.Heart]: 44,
[DecisionsChoice.Head]: 39,
[DecisionsChoice.Both]: 17,
},
[ZodiacSign.Leo]: {
[DecisionsChoice.Heart]: 30,
[DecisionsChoice.Head]: 55,
[DecisionsChoice.Both]: 15,
},
[ZodiacSign.Virgo]: {
[DecisionsChoice.Heart]: 38,
[DecisionsChoice.Head]: 40,
[DecisionsChoice.Both]: 22,
},
[ZodiacSign.Libra]: {
[DecisionsChoice.Heart]: 36,
[DecisionsChoice.Head]: 46,
[DecisionsChoice.Both]: 18,
},
[ZodiacSign.Scorpio]: {
[DecisionsChoice.Heart]: 29,
[DecisionsChoice.Head]: 52,
[DecisionsChoice.Both]: 19,
},
[ZodiacSign.Sagittarius]: {
[DecisionsChoice.Heart]: 29,
[DecisionsChoice.Head]: 53,
[DecisionsChoice.Both]: 18,
},
[ZodiacSign.Capricorn]: {
[DecisionsChoice.Heart]: 28,
[DecisionsChoice.Head]: 56,
[DecisionsChoice.Both]: 16,
},
[ZodiacSign.Aquarius]: {
[DecisionsChoice.Heart]: 27,
[DecisionsChoice.Head]: 55,
[DecisionsChoice.Both]: 18,
},
[ZodiacSign.Pisces]: {
[DecisionsChoice.Heart]: 42,
[DecisionsChoice.Head]: 38,
[DecisionsChoice.Both]: 20,
},
}[sign];
};
return {
getSignByDate,
getDecisionMakingStatistics,
};
}

View File

@ -8,6 +8,27 @@ const prefix = "api/v1";
const routes = {
client: {
root: () => [host, ""].join("/"),
palmistry: () => [host, "palmistry"].join("/"),
palmistryWelcome: () => [host, "palmistry", "welcome"].join("/"),
palmistryGender: () => [host, "palmistry", "gender"].join("/"),
palmistryBirthdate: () => [host, "palmistry", "birthdate"].join("/"),
palmistryPalmsHold: () => [host, "palmistry", "palms-hold"].join("/"),
palmistryWish: () => [host, "palmistry", "wish"].join("/"),
palmistryRelationship: () => [host, "palmistry", "relationship-status"].join("/"),
palmistryResonatedElement: () => [host, "palmistry", "resonated-element"].join("/"),
palmistryColorYouLike: () => [host, "palmistry", "color-you-like"].join("/"),
palmistryDecisions: () => [host, "palmistry", "decisions"].join("/"),
palmistryGuidancePlan: () => [host, "palmistry", "guidance-plan"].join("/"),
palmistryPersonalStatement: () => [host, "palmistry", "personal-statement"].join("/"),
palmistryScanInfo: () => [host, "palmistry", "scan-info"].join("/"),
palmistryUpload: () => [host, "palmistry", "upload"].join("/"),
palmistryScanPhoto: () => [host, "palmistry", "scan-photo"].join("/"),
palmistryEmail: () => [host, "palmistry", "email"].join("/"),
palmistrySubscriptionPlan: () => [host, "palmistry", "subscription-plan"].join("/"),
palmistryPaywall: () => [host, "palmistry", "paywall"].join("/"),
palmistryPayment: () => [host, "palmistry", "payment"].join("/"),
palmistryDiscount: () => [host, "palmistry", "discount"].join("/"),
palmistryPremiumBundle: () => [host, "palmistry", "premium-bundle"].join("/"),
birthday: () => [host, "birthday"].join("/"),
didYouKnow: () => [host, "did-you-know"].join("/"),
freePeriodInfo: () => [host, "free-period"].join("/"),
@ -160,6 +181,7 @@ export const entrypoints = [
routes.client.breathResult(),
routes.client.magicBall(),
routes.client.trialChoice(),
routes.client.palmistry(),
];
export const isEntrypoint = (path: string) => entrypoints.includes(path);
export const isNotEntrypoint = (path: string) => !isEntrypoint(path);
@ -236,6 +258,8 @@ export const withoutFooterRoutes = [
routes.client.trialPayment(),
routes.client.additionalDiscount(),
routes.client.trialPaymentWithDiscount(),
routes.client.palmistryPaywall(),
routes.client.palmistryPayment(),
routes.client.email("marketing-landing"),
routes.client.email("marketing-trial-payment"),
routes.client.tryApp(),
@ -266,6 +290,9 @@ export const hasNavbarFooter = (path: string) =>
withNavbarFooterRoutes.includes(path);
export const withoutHeaderRoutes = [
routes.client.palmistryPayment(),
routes.client.palmistryDiscount(),
routes.client.palmistryPremiumBundle(),
routes.client.compatibility(),
routes.client.subscription(),
routes.client.paymentMethod(),
@ -312,7 +339,10 @@ export const hasNoHeader = (path: string) => {
let result = true;
withoutHeaderRoutes.forEach((route) => {
if (path.includes(route)) {
if (
!path.includes("palmistry") && path.includes(route) ||
path.includes("palmistry") && path === route
) {
result = false;
}
});