From b08b23453a52b2dc5ec815a7bb867fc092c5e50a Mon Sep 17 00:00:00 2001 From: wb-ts Date: Tue, 20 Dec 2022 14:32:15 +0000 Subject: [PATCH] integrate backend --- .gitignore | 2 + env.example | 3 + package-lock.json | 104 ++++++++++ package.json | 2 + public/assets/copiedIcon.svg | 9 + public/assets/copiedIconGreen.svg | 9 + src/App.js | 5 +- src/component/Header.js | 32 ++- src/component/Home.js | 29 ++- src/component/RecoverAccount.js | 41 +++- src/component/SetupPassPhraseNewAccount.js | 40 +++- src/component/VerifyPharse.js | 29 ++- src/index.css | 229 ++++----------------- src/useCookie.js | 31 +++ 14 files changed, 336 insertions(+), 229 deletions(-) create mode 100644 env.example create mode 100644 public/assets/copiedIcon.svg create mode 100644 public/assets/copiedIconGreen.svg create mode 100644 src/useCookie.js diff --git a/.gitignore b/.gitignore index 4d29575..8b182cf 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +.env diff --git a/env.example b/env.example new file mode 100644 index 0000000..2777b4f --- /dev/null +++ b/env.example @@ -0,0 +1,3 @@ +REACT_APP_BACKEND_ENDPOINT = +REACT_APP_COOKIE_EXPIRATION_DAY = +REACT_APP_DENOM_DECIMAL = \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b1a3b7d..bb29f5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,15 +5,18 @@ "requires": true, "packages": { "": { + "name": "coreum-wallet", "version": "0.1.0", "dependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", + "axios": "^1.2.1", "react": "17.0.2", "react-dom": "17.0.2", "react-router-dom": "^5.2.0", "react-scripts": "5.0.1", + "react-use-clipboard": "^1.0.9", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -5078,6 +5081,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz", + "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -5946,6 +5972,14 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, "node_modules/core-js": { "version": "3.26.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.1.tgz", @@ -14009,6 +14043,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -14440,6 +14479,18 @@ } } }, + "node_modules/react-use-clipboard": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/react-use-clipboard/-/react-use-clipboard-1.0.9.tgz", + "integrity": "sha512-OcMzc14usXhqQnAkvzmhCXAbW5WBT2LSgscVh2vKHXZfg72jFsSOsEearqdeC/nUj8YxEfLnziqe7AE7YkWFwA==", + "dependencies": { + "copy-to-clipboard": "^3.3.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -15906,6 +15957,11 @@ "node": ">=8.0" } }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -20764,6 +20820,28 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.5.2.tgz", "integrity": "sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA==" }, + "axios": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz", + "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -21431,6 +21509,14 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, "core-js": { "version": "3.26.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.1.tgz", @@ -27071,6 +27157,11 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -27395,6 +27486,14 @@ "workbox-webpack-plugin": "^6.4.1" } }, + "react-use-clipboard": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/react-use-clipboard/-/react-use-clipboard-1.0.9.tgz", + "integrity": "sha512-OcMzc14usXhqQnAkvzmhCXAbW5WBT2LSgscVh2vKHXZfg72jFsSOsEearqdeC/nUj8YxEfLnziqe7AE7YkWFwA==", + "requires": { + "copy-to-clipboard": "^3.3.1" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -28475,6 +28574,11 @@ "is-number": "^7.0.0" } }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", diff --git a/package.json b/package.json index 08d14a2..fc2816d 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,12 @@ "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", + "axios": "^1.2.1", "react": "17.0.2", "react-dom": "17.0.2", "react-router-dom": "^5.2.0", "react-scripts": "5.0.1", + "react-use-clipboard": "^1.0.9", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/public/assets/copiedIcon.svg b/public/assets/copiedIcon.svg new file mode 100644 index 0000000..279a6e4 --- /dev/null +++ b/public/assets/copiedIcon.svg @@ -0,0 +1,9 @@ + + copyIcon-svg + + + + + + \ No newline at end of file diff --git a/public/assets/copiedIconGreen.svg b/public/assets/copiedIconGreen.svg new file mode 100644 index 0000000..815c48b --- /dev/null +++ b/public/assets/copiedIconGreen.svg @@ -0,0 +1,9 @@ + + copyIconGreen-svg + + + + + + \ No newline at end of file diff --git a/src/App.js b/src/App.js index b77ede3..e4d517d 100644 --- a/src/App.js +++ b/src/App.js @@ -8,16 +8,15 @@ import RecoverAccount from './component/RecoverAccount'; function App() { - const [isLogged, setIsLogged] = useState(false); return ( - + - + diff --git a/src/component/Header.js b/src/component/Header.js index f6c7f9a..0ade4a6 100644 --- a/src/component/Header.js +++ b/src/component/Header.js @@ -1,21 +1,35 @@ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react'; +import { useHistory } from 'react-router-dom'; import { Link } from 'react-router-dom'; +import useClipboard from 'react-use-clipboard'; +import useCookie from '../useCookie'; function classNames(...classes) { return classes.filter(Boolean).join(' ') } -export default function Header({isLogged, setIsLogged}) { +export default function Header() { - const [account, setAccount] = useState('39d01814113b4c7d3bcd05549fa6b8845316b39407525cbf45b052e47455c557'); + const [account, setAccount] = useCookie('address', ''); const [showAccount, isShowAccount] = useState(false); + const [isLogged, updateIsLogged] = useCookie('isLogged', 0); + const history = useHistory(); + const [isCopied, setIsCopied] = useClipboard(account, { + successDuration: 200, + }); + + const handleLogout = () => { + updateIsLogged(0, 0); + setAccount('', 0); + window.location.reload(); + } return (
{ - isLogged ? + isLogged == 1 ?
isShowAccount((p) => p ? false : true)} @@ -41,15 +55,13 @@ export default function Header({isLogged, setIsLogged}) {
{account}
- Copy Icon + Copy Icon +
- diff --git a/src/component/Home.js b/src/component/Home.js index 465c3cb..999ce69 100644 --- a/src/component/Home.js +++ b/src/component/Home.js @@ -1,16 +1,37 @@ import React, { useState } from 'react'; import { Link } from 'react-router-dom'; import Header from './Header'; +import useCookie from '../useCookie'; +import axios from 'axios'; -export default function Home({isLogged, setIsLogged}) { +export default function Home() { - const [balance, setBalance] = useState(12555); + const [balance, setBalance] = useState(0); + const [isLogged, updateIsLogged] = useCookie('isLogged', 0); + const [account, setAccount] = useCookie('address', ''); + const backend_endpoint = process.env.REACT_APP_BACKEND_ENDPOINT; + const denomDecimal = Number(process.env.REACT_APP_DENOM_DECIMAL); + + const getBalance = async (_account) => { + try { + const response = await axios.get(`${backend_endpoint}/get-balance/${_account}`, (res, err) => { + return res.data; + }); + if (response.data.type == "success") setBalance(Number(response.data.data) / (10 ** denomDecimal)); + } catch (err) { + console.log(err); + } + } + + useState(() => { + if (account) getBalance(account); + }, [account]); return (
-
+
{ - isLogged ? + isLogged == 1 ?

{balance} CORE diff --git a/src/component/RecoverAccount.js b/src/component/RecoverAccount.js index bd0f938..26be0ef 100644 --- a/src/component/RecoverAccount.js +++ b/src/component/RecoverAccount.js @@ -1,6 +1,8 @@ import React, { useEffect, useState } from 'react'; import { Link, useHistory } from 'react-router-dom'; +import axios from 'axios'; import Header from './Header'; +import useCookie from '../useCookie'; function classNames(...classes) { return classes.filter(Boolean).join(' ') @@ -8,10 +10,34 @@ function classNames(...classes) { export default function RecoverAccount() { const [wordInputValue, setWordInputValue] = useState(''); + const [isLogged, updateIsLogged] = useCookie('isLogged', 0); + const [account, setAccount] = useCookie('address', ''); + const [wordInputValueIsCorrect, setWordInputValueIsCorrect] = useState(true); + const history = useHistory(); + const backend_endpoint = process.env.REACT_APP_BACKEND_ENDPOINT; + const cookieExpirationDay = process.env.REACT_APP_COOKIE_EXPIRATION_DAY; - const findAccount = () => { - history.push("/"); + const findAccount = async () => { + console.log("wordInputValue:", wordInputValue); + var bodyFormData = new FormData(); + bodyFormData.append('mnemonic', wordInputValue); + try { + const response = await axios.post(`${backend_endpoint}/recovery-wallet`, bodyFormData , (res, err) => { + return res.data; + }); + if (response.data.type == "failed") { + setWordInputValueIsCorrect(false); + } else { + updateIsLogged(1, cookieExpirationDay); + setAccount(response.data, cookieExpirationDay); + history.push("/"); + } + + } catch (err) { + setWordInputValueIsCorrect(false); + console.log(err); + } } return

@@ -25,16 +51,19 @@ export default function RecoverAccount() { Enter the backup passpharse associated with the account.

-

Passpharse (12 words)

+

Passpharse (24 words)

setWordInputValue(e.target.value)} + onChange={(e) => { + setWordInputValueIsCorrect(true); + setWordInputValue(e.target.value); + }} />
diff --git a/src/component/SetupPassPhraseNewAccount.js b/src/component/SetupPassPhraseNewAccount.js index 32a7db9..c174e66 100644 --- a/src/component/SetupPassPhraseNewAccount.js +++ b/src/component/SetupPassPhraseNewAccount.js @@ -2,14 +2,40 @@ import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import Header from './Header'; import VerfiyPharse from './VerifyPharse'; +import axios from 'axios'; +import useClipboard from 'react-use-clipboard'; -export default function SetupPassPhraseNewAccount({isLogged, setIsLogged}) { +export default function SetupPassPhraseNewAccount() { const [passphrase, setPassphrase] = useState([]); const [step, setStep] = useState('displayPasspharse'); - const [account, setAccount] = useState('39d01814113b4c7d3bcd05549fa6b8845316b39407525cbf45b052e47455c557'); + const [mnemonicStr, setMnemonicStr] = useState(''); + const [selectedWordIndex, setSelectedWordIndex] = useState(); + const [account, setAccount] = useState(); + const [isCopied, setIsCopied] = useClipboard(mnemonicStr, { + successDuration: 200, + }); + const backend_endpoint = process.env.REACT_APP_BACKEND_ENDPOINT; + + const createNewAccount = async () => { + try { + const response = await axios.get(`${backend_endpoint}/create-new-wallet`, (res, err) => { + return res.data; + }); + setMnemonicStr(response.data.mnemonic); + setPassphrase(response.data.mnemonic.split(/[ ,]+/)); + setAccount(response.data.address); + } catch (err) { + console.log(err); + } + } + + const handleContinue = () => { + setSelectedWordIndex(Math.floor(Math.random() * passphrase.length)); + setStep('verifyPasspharse'); + } useEffect(() => { - setPassphrase(["prize", 'modify', 'ridge', 'advice', 'middle', 'vague', 'kiss', 'camp', 'cricket', 'bring', 'manual', 'smile']) + createNewAccount(); }, []); return ( @@ -42,12 +68,14 @@ export default function SetupPassPhraseNewAccount({isLogged, setIsLogged}) {
Cancel
: - + }
diff --git a/src/component/VerifyPharse.js b/src/component/VerifyPharse.js index 5114314..a3e8c1b 100644 --- a/src/component/VerifyPharse.js +++ b/src/component/VerifyPharse.js @@ -1,19 +1,29 @@ import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; import { Link } from 'react-router-dom'; +import useCookie from '../useCookie'; function classNames(...classes) { return classes.filter(Boolean).join(' ') } -export default function VerfiyPharse({setIsLogged}) { - const [seedPhraseVerificationWordNumber, setSeedPhraseVerificationWordNumber] = useState(7); +export default function VerfiyPharse({targetWord, targetIndex, account}) { + const [seedPhraseVerificationWordNumber, setSeedPhraseVerificationWordNumber] = useState(targetIndex); const [wordInputValue, setWordInputValue] = useState(''); const history = useHistory(); + const [isLogged, updateIsLogged] = useCookie('isLogged', 0); + const [address, setAddress] = useCookie('address', ''); + const [wordInputValueIsCorrect, setWordInputValueIsCorrect] = useState(true); + const cookieExpirationDay = process.env.REACT_APP_COOKIE_EXPIRATION_DAY; const verifyComplete = () => { - setIsLogged(true); - history.push("/"); + if (targetWord == wordInputValue) { + updateIsLogged(1, cookieExpirationDay); + setAddress(account, cookieExpirationDay); + history.push("/"); + } else { + setWordInputValueIsCorrect(false); + } } return
@@ -26,15 +36,18 @@ export default function VerfiyPharse({setIsLogged}) { Enter the following word from your recovery pharse to complete the setup process.

-

Word #{seedPhraseVerificationWordNumber}

+

Word #{seedPhraseVerificationWordNumber + 1}

setWordInputValue(e.target.value)} + onChange={(e) => { + setWordInputValueIsCorrect(true); + setWordInputValue(e.target.value); + }} />
diff --git a/src/index.css b/src/index.css index 4dbeb08..29c3e65 100644 --- a/src/index.css +++ b/src/index.css @@ -559,75 +559,34 @@ video { --tw-backdrop-sepia: ; } -.pointer-events-none { - pointer-events: none; -} - -.fixed { - position: fixed; -} - .absolute { position: absolute; } -.relative { - position: relative; -} - .bottom-10 { bottom: 2.5rem; } -.bottom-1 { - bottom: 0.25rem; -} - -.bottom-0 { - bottom: 0px; -} - -.bottom-5 { - bottom: 1.25rem; -} - -.top-0 { - top: 0px; -} - -.left-0 { - left: 0px; -} - -.top-1 { - top: 0.25rem; +.z-20 { + z-index: 20; } .z-10 { z-index: 10; } -.z-20 { - z-index: 20; +.m-auto { + margin: auto; } .m-3 { margin: 0.75rem; } -.m-auto { - margin: auto; -} - .m-2 { margin: 0.5rem; } -.mx-1 { - margin-left: 0.25rem; - margin-right: 0.25rem; -} - .my-8 { margin-top: 2rem; margin-bottom: 2rem; @@ -648,65 +607,26 @@ video { margin-bottom: 2.5rem; } -.mx-5 { - margin-left: 1.25rem; - margin-right: 1.25rem; -} - -.mx-4 { - margin-left: 1rem; - margin-right: 1rem; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; +.mt-3 { + margin-top: 0.75rem; } -.mt-2 { - margin-top: 0.5rem; +.mb-1 { + margin-bottom: 0.25rem; } .mr-2 { margin-right: 0.5rem; } -.mt-12 { - margin-top: 3rem; -} - -.mt-10 { - margin-top: 2.5rem; -} - -.mt-3 { - margin-top: 0.75rem; -} - .mb-10 { margin-bottom: 2.5rem; } -.mb-1 { - margin-bottom: 0.25rem; -} - .ml-2 { margin-left: 0.5rem; } -.mt-\[30\%\] { - margin-top: 30%; -} - -.mt-\[40\%\] { - margin-top: 40%; -} - -.mt-5 { - margin-top: 1.25rem; -} - .block { display: block; } @@ -739,22 +659,6 @@ video { height: 18px; } -.h-0 { - height: 0px; -} - -.h-10 { - height: 2.5rem; -} - -.h-8 { - height: 2rem; -} - -.h-screen { - height: 100vh; -} - .min-h-\[25px\] { min-height: 25px; } @@ -763,8 +667,8 @@ video { min-height: 100vh; } -.min-h-full { - min-height: 100%; +.w-full { + width: 100%; } .w-auto { @@ -776,14 +680,6 @@ video { width: max-content; } -.w-full { - width: 100%; -} - -.w-0 { - width: 0px; -} - .min-w-\[25px\] { min-width: 25px; } @@ -796,28 +692,6 @@ video { max-width: 100%; } -.max-w-fit { - max-width: -webkit-fit-content; - max-width: -moz-fit-content; - max-width: fit-content; -} - -.max-w-\[100\%\] { - max-width: 100%; -} - -.max-w-\[70\%\] { - max-width: 70%; -} - -.max-w-\[300px\] { - max-width: 300px; -} - -.max-w-md { - max-width: 28rem; -} - .rotate-90 { --tw-rotate: 90deg; -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -883,14 +757,14 @@ video { border-radius: 9999px; } -.rounded-md { - border-radius: 0.375rem; -} - .rounded-lg { border-radius: 0.5rem; } +.rounded-md { + border-radius: 0.375rem; +} + .border-2 { border-width: 2px; } @@ -905,6 +779,11 @@ video { border-color: rgb(16 87 60 / var(--tw-border-opacity)); } +.border-\[\#b70f36\] { + --tw-border-opacity: 1; + border-color: rgb(183 15 54 / var(--tw-border-opacity)); +} + .bg-\[\#122633\] { --tw-bg-opacity: 1; background-color: rgb(18 38 51 / var(--tw-bg-opacity)); @@ -924,11 +803,6 @@ video { background-color: transparent; } -.bg-\[\#fff\] { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - .bg-gradient-to-r { background-image: linear-gradient(to right, var(--tw-gradient-stops)); } @@ -947,12 +821,17 @@ video { padding: 0.5rem; } +.p-5 { + padding: 1.25rem; +} + .p-3 { padding: 0.75rem; } -.p-5 { - padding: 1.25rem; +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; } .px-3 { @@ -970,18 +849,12 @@ video { padding-bottom: 0.75rem; } -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -.py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; +.pt-20 { + padding-top: 5rem; } -.pt-2 { - padding-top: 0.5rem; +.pt-32 { + padding-top: 8rem; } .pb-2 { @@ -992,24 +865,8 @@ video { padding-top: 0.75rem; } -.pt-10 { - padding-top: 2.5rem; -} - -.pt-20 { - padding-top: 5rem; -} - -.pt-0 { - padding-top: 0px; -} - -.pt-\[40\%\] { - padding-top: 40%; -} - -.pt-32 { - padding-top: 8rem; +.pt-2 { + padding-top: 0.5rem; } .text-left { @@ -1043,6 +900,11 @@ video { color: rgb(153 153 153 / var(--tw-text-opacity)); } +.text-\[\#727279\] { + --tw-text-opacity: 1; + color: rgb(114 114 121 / var(--tw-text-opacity)); +} + .text-\[\#A1A1A8\] { --tw-text-opacity: 1; color: rgb(161 161 168 / var(--tw-text-opacity)); @@ -1073,11 +935,6 @@ video { color: rgb(38 214 149 / var(--tw-text-opacity)); } -.text-\[\#727279\] { - --tw-text-opacity: 1; - color: rgb(114 114 121 / var(--tw-text-opacity)); -} - .text-\[\#A2A2A7\] { --tw-text-opacity: 1; color: rgb(162 162 167 / var(--tw-text-opacity)); @@ -1101,16 +958,4 @@ video { .filter { -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} - -.duration-75 { - transition-duration: 75ms; -} - -.duration-200 { - transition-duration: 200ms; -} - -.duration-500 { - transition-duration: 500ms; } \ No newline at end of file diff --git a/src/useCookie.js b/src/useCookie.js new file mode 100644 index 0000000..db822da --- /dev/null +++ b/src/useCookie.js @@ -0,0 +1,31 @@ +import React, { useState } from 'react'; + + +const getItem = key => + document.cookie.split("; ").reduce((total, currentCookie) => { + const item = currentCookie.split("="); + const storedKey = item[0]; + const storedValue = item[1]; + return key === storedKey + ? decodeURIComponent(storedValue) + : total; + }, ''); + +const setItem = (key, value, numberOfDays) => { + const now = new Date(); + // set the time to be now + numberOfDays + now.setTime(now.getTime() + (numberOfDays * 60 * 60 * 24 * 1000)); + document.cookie = `${key}=${value}; expires=${now.toUTCString()}; path=/`; +}; + +const useCookie = (key, defaultValue) => { + const getCookie = () => getItem(key) || defaultValue; + const [cookie, setCookie] = useState(getCookie()); + const updateCookie = (value, numberOfDays) => { + setCookie(value); + setItem(key, value, numberOfDays); + }; + return [cookie, updateCookie]; +}; + +export default useCookie; \ No newline at end of file