diff --git a/index.html b/index.html index 100cf7a..ac1a9f6 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,14 @@ - - - Aura Web App + + + + + + + AURA diff --git a/package-lock.json b/package-lock.json index 54e3445..3bd0c69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "react": "^18.2.0", + "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.0" }, @@ -23,7 +24,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.3.4", "typescript": "^5.0.2", - "vite": "^4.3.2" + "vite": "^4.3.2", + "vite-plugin-copy": "^0.1.6" } }, "node_modules/@ampproject/remapping": { @@ -2551,6 +2553,14 @@ "node": ">=0.10.0" } }, + "node_modules/react-circular-progressbar": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz", + "integrity": "sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==", + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -2963,6 +2973,18 @@ } } }, + "node_modules/vite-plugin-copy": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/vite-plugin-copy/-/vite-plugin-copy-0.1.6.tgz", + "integrity": "sha512-bqIaefZOE2Jx8P5wJuHKL5GzCERa/pcwdUQWaocyTNXgalN2xkxXH7LmqRJ34V2OlKF2F9E/zj0zITS7U6PpUg==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7" + }, + "engines": { + "node": ">=14.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4724,6 +4746,12 @@ "loose-envify": "^1.1.0" } }, + "react-circular-progressbar": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz", + "integrity": "sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==", + "requires": {} + }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -4968,6 +4996,15 @@ "rollup": "^3.21.0" } }, + "vite-plugin-copy": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/vite-plugin-copy/-/vite-plugin-copy-0.1.6.tgz", + "integrity": "sha512-bqIaefZOE2Jx8P5wJuHKL5GzCERa/pcwdUQWaocyTNXgalN2xkxXH7LmqRJ34V2OlKF2F9E/zj0zITS7U6PpUg==", + "dev": true, + "requires": { + "fast-glob": "^3.2.7" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 65a41ce..b5bbe61 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "react": "^18.2.0", + "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.0" }, @@ -25,6 +26,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.3.4", "typescript": "^5.0.2", - "vite": "^4.3.2" + "vite": "^4.3.2", + "vite-plugin-copy": "^0.1.6" } } diff --git a/src/assets/android-chrome-192x192.png b/src/assets/android-chrome-192x192.png new file mode 100644 index 0000000..8ee328e Binary files /dev/null and b/src/assets/android-chrome-192x192.png differ diff --git a/src/assets/android-chrome-512x512.png b/src/assets/android-chrome-512x512.png new file mode 100644 index 0000000..1e190fc Binary files /dev/null and b/src/assets/android-chrome-512x512.png differ diff --git a/src/assets/apple-touch-icon.png b/src/assets/apple-touch-icon.png new file mode 100644 index 0000000..5b69426 Binary files /dev/null and b/src/assets/apple-touch-icon.png differ diff --git a/src/assets/browserconfig.xml b/src/assets/browserconfig.xml new file mode 100644 index 0000000..b3930d0 --- /dev/null +++ b/src/assets/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/src/assets/favicon-16x16.png b/src/assets/favicon-16x16.png new file mode 100644 index 0000000..0ce7744 Binary files /dev/null and b/src/assets/favicon-16x16.png differ diff --git a/src/assets/favicon-32x32.png b/src/assets/favicon-32x32.png new file mode 100644 index 0000000..ff73b7a Binary files /dev/null and b/src/assets/favicon-32x32.png differ diff --git a/src/assets/favicon.ico b/src/assets/favicon.ico new file mode 100644 index 0000000..45d15b1 Binary files /dev/null and b/src/assets/favicon.ico differ diff --git a/src/assets/mstile-150x150.png b/src/assets/mstile-150x150.png new file mode 100644 index 0000000..925d8af Binary files /dev/null and b/src/assets/mstile-150x150.png differ diff --git a/src/assets/site.webmanifest b/src/assets/site.webmanifest new file mode 100644 index 0000000..1e9747b --- /dev/null +++ b/src/assets/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/assets/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/assets/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/src/components/CreateProfilePage/ProcessFlow.tsx b/src/components/CreateProfilePage/ProcessFlow.tsx new file mode 100644 index 0000000..6b927db --- /dev/null +++ b/src/components/CreateProfilePage/ProcessFlow.tsx @@ -0,0 +1,67 @@ +import { useEffect, useState } from 'react' +import ProcessItem from "./ProcessItem" + +interface Task { + (): Promise +} + +type ProcessItem = { + task: Task + label: string +} + +type ProcessFlowProps = { + items: ProcessItem[] + onDone: () => void +} + +enum ProcessStatus { + Idle, + Pending, + Done, +} + +const createChaining = (tasks: Task[], callback: (idx: number) => void) => { + return tasks.reduce((chain, task, idx) => { + return chain.then(task).then(()=> callback(idx)) + }, Promise.resolve()) +} + +const getMultiplier = (currentIdx: number, length: number): number => { + return Math.max(length - (currentIdx + 1) - 1, 0) +} + +const calculateTop = (currentIdx: number, length: number): number => { + const itemHeight = 56 + return getMultiplier(currentIdx, length) * itemHeight +} + +function ProcessFlow({ items, onDone }: ProcessFlowProps): JSX.Element { + const [status, setStatus] = useState(ProcessStatus.Idle) + const [doneTaskIdx, setDoneTaskIdx] = useState(-1) + const tasks = items.map(({ task }) => task) + + useEffect(() => { + if (status !== ProcessStatus.Idle) return + setStatus(ProcessStatus.Pending) + createChaining(tasks, setDoneTaskIdx) + .then(() => setStatus(ProcessStatus.Done)) + .then(() => onDone()) + }, [status, tasks, onDone]) + + const toItems = ({ label }: ProcessItem, idx: number): JSX.Element => { + return + } + return ( +
+ {items.map(toItems)} +
+ ) +} + +export default ProcessFlow diff --git a/src/components/CreateProfilePage/ProcessItem.tsx b/src/components/CreateProfilePage/ProcessItem.tsx new file mode 100644 index 0000000..517a9c3 --- /dev/null +++ b/src/components/CreateProfilePage/ProcessItem.tsx @@ -0,0 +1,23 @@ +type ProcessItemProps = { + top: number + label: string + isDone: boolean +} + +function ProcessItem({ top, label, isDone }: ProcessItemProps): JSX.Element { + + return ( +
+
+ { + isDone + ?
+ :
+ } +
+
{label}
+
+ ) +} + +export default ProcessItem diff --git a/src/components/CreateProfilePage/index.tsx b/src/components/CreateProfilePage/index.tsx index f9042a6..c1ba642 100644 --- a/src/components/CreateProfilePage/index.tsx +++ b/src/components/CreateProfilePage/index.tsx @@ -1,19 +1,44 @@ -import { useEffect } from "react" +import { useState } from "react" import { useNavigate } from "react-router-dom" +import { CircularProgressbar, buildStyles } from 'react-circular-progressbar' +import ProcessFlow from "./ProcessFlow" import Title from "../Title" import routes from "../../routes" +import './styles.css' + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) function CreateProfilePage(): JSX.Element { const navigate = useNavigate() - - useEffect(() => { - const timerId = setTimeout(() => navigate(routes.client.emailEnter()), 3000) - return () => clearTimeout(timerId) - }, [navigate]) + const [progress, setProgress] = useState(0) + const processItems = [ + { task: () => sleep(3300).then(() => setProgress(35)), label: 'Zodiac data analysis' }, + { task: () => sleep(2550).then(() => setProgress(61)), label: 'Drawing Wallpapers' }, + { task: () => sleep(3789).then(() => setProgress(98)), label: 'Preparing results' }, + ] + const handleDone = () => Promise.resolve() + .then(() => setProgress(100)) + .then(() => sleep(1000)) + .then(() => navigate(routes.client.emailEnter())) return (
Creating your profile +
+ +
+
) } diff --git a/src/components/CreateProfilePage/styles.css b/src/components/CreateProfilePage/styles.css new file mode 100644 index 0000000..4ef8b68 --- /dev/null +++ b/src/components/CreateProfilePage/styles.css @@ -0,0 +1,91 @@ +.progressbar { + width: 100%; + max-width: 250px; + margin: 24px auto; +} + +.process-items { + overflow: hidden; +} + +.process-item { + display: flex; + font-size: 24px; + font-weight: 400; + margin-bottom: 24px; + line-height: 32px; + position: relative; + transition: top .4s ease-in-out; +} + +.process-item__pick { + position: relative; + margin-right: 15px; + width: 32px; + height: 32px; + clear: both; +} + +.process-item__icon { + font-size: 32px; +} + +.process-item__loader { + display: block; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin: auto; + width: 32px; + height: 32px; + animation: loader-1-1 4.8s linear infinite; +} + +@keyframes loader-1-1 { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.process-item__loader span { + display: block; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin: auto; + height: 32px; + width: 32px; + clip: rect(0, 32px, 32px, 16px); + animation: loader-1-2 1.2s linear infinite; +} + +@keyframes loader-1-2 { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(220deg); } +} + +.process-item__loader span::after { + position: absolute; + box-sizing: border-box; + content: ""; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin: auto; + height: 32px; + width: 32px; + clip: rect(0, 32px, 32px, 16px); + border: 3px solid #000; + border-radius: 50%; + animation: loader-1-3 1.2s cubic-bezier(0.770, 0.000, 0.175, 1.000) infinite; +} + +@keyframes loader-1-3 { + 0% { transform: rotate(-140deg); } + 50% { transform: rotate(-160deg); } + 100% { transform: rotate(140deg); } +} diff --git a/src/components/SubscriptionPage/index.tsx b/src/components/SubscriptionPage/index.tsx index 8d64f8d..4c059af 100644 --- a/src/components/SubscriptionPage/index.tsx +++ b/src/components/SubscriptionPage/index.tsx @@ -25,11 +25,8 @@ function SubscriptionPage(): JSX.Element { <>
- - Your personalized Aries Wallpaper has been created! Find your happiness now and get an additional individual horoscope based on your energies. - - + diff --git a/src/main.ts b/src/main.ts index 897a2a0..54dbd90 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import ReactDOM from 'react-dom/client' import init from './init' +import 'react-circular-progressbar/dist/styles.css' import './fonts.css' import './index.css' diff --git a/vite.config.ts b/vite.config.ts index 5a33944..20b8e9f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,21 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import { copy } from 'vite-plugin-copy' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + build: { + manifest: false, + }, + plugins: [ + react(), + copy([ + { src: 'src/assets/favicon.ico', dest: 'dist' }, + { src: 'src/assets/browserconfig.xml', dest: 'dist' }, + { src: 'src/assets/mstile-150x150.png', dest: 'dist' }, + { src: 'src/assets/android-chrome-192x192.png', dest: 'dist/assets' }, + { src: 'src/assets/android-chrome-512x512.png', dest: 'dist/assets' }, + { src: 'src/assets/android-chrome-512x512.png', dest: 'dist/assets' }, + ], { hook: 'writeBundle' }), + ], })