From eb94d2dbf9cf7ef6521e59e1f17e6e968a57d617 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 25 Oct 2020 18:13:25 -0300 Subject: [PATCH 1/4] Modal Stable / Login View --- components/auth/LoginView.tsx | 79 +++++++++++------------- components/core/Layout/Layout.tsx | 25 ++++---- components/core/UserNav/DropdownMenu.tsx | 11 +++- components/core/UserNav/UserNav.tsx | 36 ++++++----- components/ui/Input/Input.module.css | 4 ++ components/ui/Input/Input.tsx | 25 ++++++++ components/ui/Input/index.ts | 1 + components/ui/Modal/Modal.tsx | 24 ++++--- components/ui/context.tsx | 2 - components/ui/index.ts | 1 + 10 files changed, 124 insertions(+), 84 deletions(-) create mode 100644 components/ui/Input/Input.module.css create mode 100644 components/ui/Input/Input.tsx create mode 100644 components/ui/Input/index.ts diff --git a/components/auth/LoginView.tsx b/components/auth/LoginView.tsx index fb7f99ada..9229799df 100644 --- a/components/auth/LoginView.tsx +++ b/components/auth/LoginView.tsx @@ -1,19 +1,23 @@ -import { FC, useEffect } from 'react' -import { Logo, Modal, Button } from '@components/ui' +import { FC, useEffect, useState } from 'react' +import { Logo, Modal, Button, Input } from '@components/ui' import useSignup from '@lib/bigcommerce/use-signup' import useLogin from '@lib/bigcommerce/use-login' -import useLogout from '@lib/bigcommerce/use-logout' -import useCustomer from '@lib/bigcommerce/use-customer' import { useUI } from '@components/ui/context' -interface Props { - open: boolean -} +interface Props {} + +const LoginView: FC = () => { + const [email, setEmail] = useState('') + const [pass, setPass] = useState('') + // const { openModal, closeModal } = useUI() + + // useEffect(() => { + // open ? openModal() : closeModal() + // }, [open]) -const LoginView: FC = ({ open }) => { const signup = useSignup() const login = useLogin() - const logout = useLogout() + // // Data about the currently logged in customer, it will update // // automatically after a signup/login/logout // const { data } = useCustomer() @@ -56,43 +60,30 @@ const LoginView: FC = ({ open }) => { } } - const { openModal, closeModal } = useUI() - useEffect(() => { - open ? openModal() : closeModal() - }, [open]) - return ( - -
-
- -
-
-
- -
-
- -
- - - Don't have an account? - {` `} - - Sign Up - - -
+
+
+
- +
+
+ +
+
+ +
+ + + Don't have an account? + {` `} + + Sign Up + + +
+
) } diff --git a/components/core/Layout/Layout.tsx b/components/core/Layout/Layout.tsx index 90a5bca35..3e3eac2a1 100644 --- a/components/core/Layout/Layout.tsx +++ b/components/core/Layout/Layout.tsx @@ -1,14 +1,14 @@ -import { FC, useEffect, useState } from 'react' import cn from 'classnames' -import type { Page } from '@lib/bigcommerce/api/operations/get-all-pages' -import { CommerceProvider } from '@lib/bigcommerce' -import { Navbar, Featurebar, Footer } from '@components/core' -import { Container, Sidebar } from '@components/ui' -import Button from '@components/ui/Button' -import { CartSidebarView } from '@components/cart' -import { useUI } from '@components/ui/context' import s from './Layout.module.css' +import { FC, useEffect, useState } from 'react' +import { CartSidebarView } from '@components/cart' +import { Container, Sidebar, Button, Modal } from '@components/ui' +import { Navbar, Featurebar, Footer } from '@components/core' +import { LoginView } from '@components/auth' +import { useUI } from '@components/ui/context' import { usePreventScroll } from '@react-aria/overlays' +import { CommerceProvider } from '@lib/bigcommerce' +import type { Page } from '@lib/bigcommerce/api/operations/get-all-pages' interface Props { pageProps: { pages?: Page[] @@ -16,7 +16,7 @@ interface Props { } const Layout: FC = ({ children, pageProps }) => { - const { displaySidebar, displayDropdown, closeSidebar } = useUI() + const { displaySidebar, displayModal, closeSidebar, closeModal } = useUI() const [acceptedCookies, setAcceptedCookies] = useState(false) const [hasScrolled, setHasScrolled] = useState(false) @@ -36,7 +36,7 @@ const Layout: FC = ({ children, pageProps }) => { }, []) usePreventScroll({ - isDisabled: !displaySidebar, + isDisabled: !(displaySidebar || displayModal), }) return ( @@ -54,11 +54,12 @@ const Layout: FC = ({ children, pageProps }) => {
{children}
- - + + + = ({ open = false }) => { const { theme, setTheme } = useTheme() - + const logout = useLogout() return ( = ({ open = false }) => { - Logout + logout()} + > + Logout + diff --git a/components/core/UserNav/UserNav.tsx b/components/core/UserNav/UserNav.tsx index f129c4a2e..d7e2adf28 100644 --- a/components/core/UserNav/UserNav.tsx +++ b/components/core/UserNav/UserNav.tsx @@ -22,7 +22,7 @@ const UserNav: FC = ({ className, children, ...props }) => { const { data } = useCart() const { data: customer } = useCustomer() - const { openSidebar, closeSidebar, displaySidebar } = useUI() + const { openSidebar, closeSidebar, displaySidebar, openModal } = useUI() const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0) return (
diff --git a/components/ui/Input/Input.module.css b/components/ui/Input/Input.module.css new file mode 100644 index 000000000..83570f065 --- /dev/null +++ b/components/ui/Input/Input.module.css @@ -0,0 +1,4 @@ +.root { + @apply focus:outline-none bg-primary focus:shadow-outline-gray border-none py-2 + px-6 w-full appearance-none transition duration-150 ease-in-out placeholder-accents-5 pr-10; +} diff --git a/components/ui/Input/Input.tsx b/components/ui/Input/Input.tsx new file mode 100644 index 000000000..86ae34fc9 --- /dev/null +++ b/components/ui/Input/Input.tsx @@ -0,0 +1,25 @@ +import cn from 'classnames' +import s from './Input.module.css' +import React, { InputHTMLAttributes } from 'react' + +export interface Props extends InputHTMLAttributes { + className?: string + onChange?: (...args: any[]) => any +} + +const Input: React.FC = (props) => { + const { className, children, onChange, ...rest } = props + + const rootClassName = cn(s.root, {}, className) + + const handleOnChange = (e: any) => { + if (onChange) { + onChange(e.target.value) + } + return null + } + + return +} + +export default Input diff --git a/components/ui/Input/index.ts b/components/ui/Input/index.ts new file mode 100644 index 000000000..aa97178e5 --- /dev/null +++ b/components/ui/Input/index.ts @@ -0,0 +1 @@ +export { default } from './Input' diff --git a/components/ui/Modal/Modal.tsx b/components/ui/Modal/Modal.tsx index bafc0ae6f..c19a21b10 100644 --- a/components/ui/Modal/Modal.tsx +++ b/components/ui/Modal/Modal.tsx @@ -8,7 +8,7 @@ import { useOverlay, useModal, OverlayContainer } from '@react-aria/overlays' interface Props { className?: string children?: any - open?: boolean + open: boolean onClose?: () => void } @@ -22,14 +22,22 @@ const Modal: FC = ({ const rootClassName = cn(s.root, className) let ref = useRef() as React.MutableRefObject let { modalProps } = useModal() - let { overlayProps } = useOverlay(props, ref) - let { dialogProps } = useDialog(props, ref) + let { dialogProps } = useDialog({}, ref) + let { overlayProps } = useOverlay( + { + isOpen: open, + isDismissable: true, + onClose: onClose, + ...props, + }, + ref + ) return ( -
- + +
= ({ leaveTo="opacity-0" >
{children}
- -
+
+
) diff --git a/components/ui/context.tsx b/components/ui/context.tsx index bacbca02f..ab1af74f1 100644 --- a/components/ui/context.tsx +++ b/components/ui/context.tsx @@ -101,8 +101,6 @@ export const UIProvider: FC = (props) => { closeModal, } - console.log('state', state) - return } diff --git a/components/ui/index.ts b/components/ui/index.ts index a53f0b513..581c12d53 100644 --- a/components/ui/index.ts +++ b/components/ui/index.ts @@ -9,3 +9,4 @@ export { default as LoadingDots } from './LoadingDots' export { default as Skeleton } from './Skeleton' export { default as Modal } from './Modal' export { default as Text } from './Text' +export { default as Input } from './Input' From d47fa2d29f16ca73c37dcc65ce9ed3adda7a5d3d Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 25 Oct 2020 18:26:32 -0300 Subject: [PATCH 2/4] Support for multiple modal views --- components/auth/LoginView.tsx | 11 ++-- components/auth/SignUpView.tsx | 88 +++++++++++++++++++++++++++++++ components/auth/index.ts | 1 + components/core/Layout/Layout.tsx | 15 ++++-- components/ui/context.tsx | 22 ++++++++ 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 components/auth/SignUpView.tsx diff --git a/components/auth/LoginView.tsx b/components/auth/LoginView.tsx index 9229799df..1587569eb 100644 --- a/components/auth/LoginView.tsx +++ b/components/auth/LoginView.tsx @@ -9,11 +9,7 @@ interface Props {} const LoginView: FC = () => { const [email, setEmail] = useState('') const [pass, setPass] = useState('') - // const { openModal, closeModal } = useUI() - - // useEffect(() => { - // open ? openModal() : closeModal() - // }, [open]) + const { setModalView } = useUI() const signup = useSignup() const login = useLogin() @@ -78,7 +74,10 @@ const LoginView: FC = () => { Don't have an account? {` `} - + setModalView('SIGNUP_VIEW')} + > Sign Up diff --git a/components/auth/SignUpView.tsx b/components/auth/SignUpView.tsx new file mode 100644 index 000000000..bb88f4b01 --- /dev/null +++ b/components/auth/SignUpView.tsx @@ -0,0 +1,88 @@ +import { FC, useEffect, useState } from 'react' +import { Logo, Modal, Button, Input } from '@components/ui' +import useSignup from '@lib/bigcommerce/use-signup' +import useLogin from '@lib/bigcommerce/use-login' +import { useUI } from '@components/ui/context' + +interface Props {} + +const LoginView: FC = () => { + const [email, setEmail] = useState('') + const [pass, setPass] = useState('') + + const signup = useSignup() + const login = useLogin() + const { setModalView } = useUI() + // // Data about the currently logged in customer, it will update + // // automatically after a signup/login/logout + // const { data } = useCustomer() + // TODO: use this method. It can take more than 5 seconds to do a signup + const handleSignup = async () => { + // TODO: validate the password and email before calling the signup + // Passwords must be at least 7 characters and contain both alphabetic + // and numeric characters. + try { + await signup({ + // This account already exists, so it will throw the "duplicated_email" error + email: 'luis@vercel.com', + firstName: 'Luis', + lastName: 'Alvarez', + password: 'luis123', + }) + } catch (error) { + if (error.code === 'duplicated_email') { + // TODO: handle duplicated email + } + // Show a generic error saying that something bad happened, try again later + } + } + + const handleLogin = async () => { + // TODO: validate the password and email before calling the signup + // Passwords must be at least 7 characters and contain both alphabetic + // and numeric characters. + try { + await login({ + email: 'luis@vercel.com', + // This is an invalid password so it will throw the "invalid_credentials" error + password: 'luis1234', // will work with `luis123` + }) + } catch (error) { + if (error.code === 'invalid_credentials') { + // The email and password didn't match an existing account + } + // Show a generic error saying that something bad happened, try again later + } + } + + return ( +
+
+ +
+
+
+ +
+
+ +
+ + + Don't have an account? + {` `} + setModalView('LOGIN_VIEW')} + > + Log In + + +
+
+ ) +} + +export default LoginView diff --git a/components/auth/index.ts b/components/auth/index.ts index fa4dd296f..e0f739bc5 100644 --- a/components/auth/index.ts +++ b/components/auth/index.ts @@ -1 +1,2 @@ export { default as LoginView } from './LoginView' +export { default as SignUpView } from './SignUpView' diff --git a/components/core/Layout/Layout.tsx b/components/core/Layout/Layout.tsx index 3e3eac2a1..9619a0643 100644 --- a/components/core/Layout/Layout.tsx +++ b/components/core/Layout/Layout.tsx @@ -1,10 +1,10 @@ import cn from 'classnames' import s from './Layout.module.css' -import { FC, useEffect, useState } from 'react' +import React, { FC, useEffect, useState } from 'react' import { CartSidebarView } from '@components/cart' import { Container, Sidebar, Button, Modal } from '@components/ui' import { Navbar, Featurebar, Footer } from '@components/core' -import { LoginView } from '@components/auth' +import { LoginView, SignUpView } from '@components/auth' import { useUI } from '@components/ui/context' import { usePreventScroll } from '@react-aria/overlays' import { CommerceProvider } from '@lib/bigcommerce' @@ -16,7 +16,13 @@ interface Props { } const Layout: FC = ({ children, pageProps }) => { - const { displaySidebar, displayModal, closeSidebar, closeModal } = useUI() + const { + displaySidebar, + displayModal, + closeSidebar, + closeModal, + modalView, + } = useUI() const [acceptedCookies, setAcceptedCookies] = useState(false) const [hasScrolled, setHasScrolled] = useState(false) @@ -58,7 +64,8 @@ const Layout: FC = ({ children, pageProps }) => { - + {modalView === 'LOGIN_VIEW' && } + {modalView === 'SIGNUP_VIEW' && } (initialState) @@ -76,6 +88,12 @@ function uiReducer(state: State, action: Action) { displayModal: false, } } + case 'SET_MODAL_VIEW': { + return { + ...state, + modalView: action.view, + } + } } } @@ -91,6 +109,9 @@ export const UIProvider: FC = (props) => { const openModal = () => dispatch({ type: 'OPEN_MODAL' }) const closeModal = () => dispatch({ type: 'CLOSE_MODAL' }) + const setModalView = (view: MODAL_VIEWS) => + dispatch({ type: 'SET_MODAL_VIEW', view }) + const value = { ...state, openSidebar, @@ -99,6 +120,7 @@ export const UIProvider: FC = (props) => { closeDropdown, openModal, closeModal, + setModalView, } return From 8c81ee1ffd99c12b72eee4bec988c01594172a8b Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 25 Oct 2020 19:18:18 -0300 Subject: [PATCH 3/4] Sign Up Working --- components/auth/SignUpView.tsx | 97 +++++++++++++------------- components/ui/Button/Button.module.css | 9 +++ components/ui/Button/Button.tsx | 5 +- components/ui/Input/Input.module.css | 5 +- package.json | 1 + yarn.lock | 5 ++ 6 files changed, 71 insertions(+), 51 deletions(-) diff --git a/components/auth/SignUpView.tsx b/components/auth/SignUpView.tsx index bb88f4b01..f7a064ee3 100644 --- a/components/auth/SignUpView.tsx +++ b/components/auth/SignUpView.tsx @@ -1,77 +1,78 @@ import { FC, useEffect, useState } from 'react' -import { Logo, Modal, Button, Input } from '@components/ui' +import { Logo, Button, Input } from '@components/ui' import useSignup from '@lib/bigcommerce/use-signup' -import useLogin from '@lib/bigcommerce/use-login' import { useUI } from '@components/ui/context' +import { validate } from 'email-validator' interface Props {} +interface Error { + code: string + message: string +} + const LoginView: FC = () => { + // Form State const [email, setEmail] = useState('') - const [pass, setPass] = useState('') + const [password, setPassword] = useState('') + const [firstName, setFirstName] = useState('') + const [lastName, setLastName] = useState('') + const [loading, setLoading] = useState(false) + const [disabled, setDisabled] = useState(true) + const [message, setMessage] = useState('') const signup = useSignup() - const login = useLogin() - const { setModalView } = useUI() - // // Data about the currently logged in customer, it will update - // // automatically after a signup/login/logout - // const { data } = useCustomer() - // TODO: use this method. It can take more than 5 seconds to do a signup + const { setModalView, closeModal } = useUI() + const handleSignup = async () => { - // TODO: validate the password and email before calling the signup - // Passwords must be at least 7 characters and contain both alphabetic - // and numeric characters. try { + setLoading(true) + setMessage('') await signup({ - // This account already exists, so it will throw the "duplicated_email" error - email: 'luis@vercel.com', - firstName: 'Luis', - lastName: 'Alvarez', - password: 'luis123', + email, + firstName, + lastName, + password, }) - } catch (error) { - if (error.code === 'duplicated_email') { - // TODO: handle duplicated email - } - // Show a generic error saying that something bad happened, try again later + setLoading(false) + closeModal() + } catch ({ errors }) { + setMessage(errors[0].message) + setLoading(false) } } - const handleLogin = async () => { - // TODO: validate the password and email before calling the signup - // Passwords must be at least 7 characters and contain both alphabetic - // and numeric characters. - try { - await login({ - email: 'luis@vercel.com', - // This is an invalid password so it will throw the "invalid_credentials" error - password: 'luis1234', // will work with `luis123` - }) - } catch (error) { - if (error.code === 'invalid_credentials') { - // The email and password didn't match an existing account - } - // Show a generic error saying that something bad happened, try again later - } - } + useEffect(() => { + // Test for Alphanumeric password + const validPassword = /^(?=.*[a-zA-Z])(?=.*[0-9])/.test(password) + + // Unable to send form unless fields are valid. + setDisabled(!validate(email) || password.length < 7 || !validPassword) + }, [email, password]) return ( -
+
-
- -
-
- -
- - Don't have an account? + Do you have an account? {` `} { Component?: string | JSXElementConstructor width?: string | number loading?: boolean + disabled?: boolean } const Button: React.FC = forwardRef((props, buttonRef) => { @@ -28,10 +29,10 @@ const Button: React.FC = forwardRef((props, buttonRef) => { children, active, onClick, - disabled, width, Component = 'button', loading = false, + disabled = false, style = {}, ...rest } = props @@ -52,6 +53,7 @@ const Button: React.FC = forwardRef((props, buttonRef) => { { [s.slim]: variant === 'slim', [s.loading]: loading, + [s.disabled]: disabled, }, className ) @@ -64,6 +66,7 @@ const Button: React.FC = forwardRef((props, buttonRef) => { {...buttonProps} data-active={isPressed ? '' : undefined} className={rootClassName} + disabled={disabled} style={{ width, ...style, diff --git a/components/ui/Input/Input.module.css b/components/ui/Input/Input.module.css index 83570f065..ccaf833db 100644 --- a/components/ui/Input/Input.module.css +++ b/components/ui/Input/Input.module.css @@ -1,4 +1,5 @@ .root { - @apply focus:outline-none bg-primary focus:shadow-outline-gray border-none py-2 - px-6 w-full appearance-none transition duration-150 ease-in-out placeholder-accents-5 pr-10; + @apply focus:outline-none bg-primary focus:shadow-outline-gray py-2 + px-6 w-full appearance-none transition duration-150 ease-in-out + placeholder-accents-5 pr-10 border border-accents-3 text-accents-6; } diff --git a/package.json b/package.json index 58bd461b4..39939bbaf 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "bowser": "^2.11.0", "classnames": "^2.2.6", "cookie": "^0.4.1", + "email-validator": "^2.0.4", "intersection-observer": "^0.11.0", "js-cookie": "^2.2.1", "keen-slider": "^5.2.4", diff --git a/yarn.lock b/yarn.lock index e4d916590..b01e9bda2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3907,6 +3907,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +email-validator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" + integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" From 4f4ac89cd93f229bc61a973242a4977dcabdd0c5 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Sun, 25 Oct 2020 19:43:06 -0300 Subject: [PATCH 4/4] Login and Signup views --- components/auth/LoginView.tsx | 94 +++++++++++++++++----------------- components/auth/SignUpView.tsx | 29 +++++++---- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/components/auth/LoginView.tsx b/components/auth/LoginView.tsx index 1587569eb..e597c9d26 100644 --- a/components/auth/LoginView.tsx +++ b/components/auth/LoginView.tsx @@ -1,74 +1,76 @@ import { FC, useEffect, useState } from 'react' import { Logo, Modal, Button, Input } from '@components/ui' -import useSignup from '@lib/bigcommerce/use-signup' import useLogin from '@lib/bigcommerce/use-login' import { useUI } from '@components/ui/context' +import { validate } from 'email-validator' interface Props {} const LoginView: FC = () => { + // Form State const [email, setEmail] = useState('') - const [pass, setPass] = useState('') - const { setModalView } = useUI() + const [password, setPassword] = useState('') + const [loading, setLoading] = useState(false) + const [message, setMessage] = useState('') + const [dirty, setDirty] = useState(false) + const [disabled, setDisabled] = useState(false) + const { setModalView, closeModal } = useUI() - const signup = useSignup() const login = useLogin() - // // Data about the currently logged in customer, it will update - // // automatically after a signup/login/logout - // const { data } = useCustomer() - // TODO: use this method. It can take more than 5 seconds to do a signup - const handleSignup = async () => { - // TODO: validate the password and email before calling the signup - // Passwords must be at least 7 characters and contain both alphabetic - // and numeric characters. + const handleLogin = async () => { + if (!dirty && !disabled) { + setDirty(true) + handleValidation() + } + try { - await signup({ - // This account already exists, so it will throw the "duplicated_email" error - email: 'luis@vercel.com', - firstName: 'Luis', - lastName: 'Alvarez', - password: 'luis123', + setLoading(true) + setMessage('') + await login({ + email, + password, }) - } catch (error) { - if (error.code === 'duplicated_email') { - // TODO: handle duplicated email - } - // Show a generic error saying that something bad happened, try again later + setLoading(false) + closeModal() + } catch ({ errors }) { + setMessage(errors[0].message) + setLoading(false) } } - const handleLogin = async () => { - // TODO: validate the password and email before calling the signup - // Passwords must be at least 7 characters and contain both alphabetic - // and numeric characters. - try { - await login({ - email: 'luis@vercel.com', - // This is an invalid password so it will throw the "invalid_credentials" error - password: 'luis1234', // will work with `luis123` - }) - } catch (error) { - if (error.code === 'invalid_credentials') { - // The email and password didn't match an existing account - } - // Show a generic error saying that something bad happened, try again later + const handleValidation = () => { + // Test for Alphanumeric password + const validPassword = /^(?=.*[a-zA-Z])(?=.*[0-9])/.test(password) + + // Unable to send form unless fields are valid. + if (dirty) { + setDisabled(!validate(email) || password.length < 7 || !validPassword) } } + useEffect(() => { + handleValidation() + }, [email, password, dirty]) + return ( -
+
-
- -
-
- -
- diff --git a/components/auth/SignUpView.tsx b/components/auth/SignUpView.tsx index f7a064ee3..f46184bd0 100644 --- a/components/auth/SignUpView.tsx +++ b/components/auth/SignUpView.tsx @@ -6,25 +6,26 @@ import { validate } from 'email-validator' interface Props {} -interface Error { - code: string - message: string -} - -const LoginView: FC = () => { +const SignUpView: FC = () => { // Form State const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [firstName, setFirstName] = useState('') const [lastName, setLastName] = useState('') const [loading, setLoading] = useState(false) - const [disabled, setDisabled] = useState(true) const [message, setMessage] = useState('') + const [dirty, setDirty] = useState(false) + const [disabled, setDisabled] = useState(false) const signup = useSignup() const { setModalView, closeModal } = useUI() const handleSignup = async () => { + if (!dirty && !disabled) { + setDirty(true) + handleValidation() + } + try { setLoading(true) setMessage('') @@ -42,13 +43,19 @@ const LoginView: FC = () => { } } - useEffect(() => { + const handleValidation = () => { // Test for Alphanumeric password const validPassword = /^(?=.*[a-zA-Z])(?=.*[0-9])/.test(password) // Unable to send form unless fields are valid. - setDisabled(!validate(email) || password.length < 7 || !validPassword) - }, [email, password]) + if (dirty) { + setDisabled(!validate(email) || password.length < 7 || !validPassword) + } + } + + useEffect(() => { + handleValidation() + }, [email, password, dirty]) return (
@@ -86,4 +93,4 @@ const LoginView: FC = () => { ) } -export default LoginView +export default SignUpView