From 22c1f6f7b45781d68cc454cc952c1190caeab95b Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 18 Jul 2022 20:43:41 -0700 Subject: [PATCH] Implement UI for email login and registration --- .../components/elements/ModalPrimitives.tsx | 1 - .../web/components/elements/StyledText.tsx | 3 +- .../web/components/templates/EmailLogin.tsx | 134 +++++++++++++ .../templates/EmailResetPassword.tsx | 94 +++++++++ .../web/components/templates/EmailSignup.tsx | 184 ++++++++++++++++++ .../web/components/templates/LoginForm.tsx | 43 ++-- .../components/templates/ProfileLayout.tsx | 9 +- packages/web/pages/email-login.tsx | 96 ++++----- packages/web/pages/email-registration.tsx | 53 ----- packages/web/pages/email-reset-password.tsx | 15 ++ packages/web/pages/email-signup.tsx | 15 ++ 11 files changed, 527 insertions(+), 120 deletions(-) create mode 100644 packages/web/components/templates/EmailLogin.tsx create mode 100644 packages/web/components/templates/EmailResetPassword.tsx create mode 100644 packages/web/components/templates/EmailSignup.tsx delete mode 100644 packages/web/pages/email-registration.tsx create mode 100644 packages/web/pages/email-reset-password.tsx create mode 100644 packages/web/pages/email-signup.tsx diff --git a/packages/web/components/elements/ModalPrimitives.tsx b/packages/web/components/elements/ModalPrimitives.tsx index a8e6db4d2..876104de3 100644 --- a/packages/web/components/elements/ModalPrimitives.tsx +++ b/packages/web/components/elements/ModalPrimitives.tsx @@ -97,7 +97,6 @@ export const ModalButtonBar = (props: ModalButtonBarProps) => { }} > + + + + Don't have an account? {' '} + + Sign up + + + + Forgot your password? {' '} + + Click here + + + + + ) +} diff --git a/packages/web/components/templates/EmailResetPassword.tsx b/packages/web/components/templates/EmailResetPassword.tsx new file mode 100644 index 000000000..4d4b256db --- /dev/null +++ b/packages/web/components/templates/EmailResetPassword.tsx @@ -0,0 +1,94 @@ +import { SpanBox, VStack } from '../elements/LayoutPrimitives' +import { Button } from '../elements/Button' +import { StyledText } from '../elements/StyledText' +import { useEffect, useState } from 'react' +import { FormInput } from '../elements/FormElements' +import { TermAndConditionsFooter } from './LoginForm' +import { fetchEndpoint } from '../../lib/appConfig' +import { logoutMutation } from '../../lib/networking/mutations/logoutMutation' +import { styled } from '@stitches/react' +import { useRouter } from 'next/router' +import { formatMessage } from '../../locales/en/messages' +import { parseErrorCodes } from '../../lib/queryParamParser' + +const StyledTextSpan = styled('span', StyledText) + +const BorderedFormInput = styled(FormInput, { + height: '40px', + paddingLeft: '6px', + borderRadius: '6px', + background: 'white', + border: `1px solid 1px solid rgba(0, 0, 0, 0.06)`, +}) + +const FormLabel = styled('label', { + fontSize: '16px', + color: '$omnivoreGray', +}) + +export function EmailResetPassword(): JSX.Element { + const router = useRouter() + const [email, setEmail] = useState(undefined) + const [errorMessage, setErrorMessage] = useState(undefined) + + useEffect(() => { + if (!router.isReady) return + const errorCode = parseErrorCodes(router.query) + const errorMsg = errorCode + ? formatMessage({ id: `error.${errorCode}` }) + : undefined + setErrorMessage(errorMsg) + }, [router.isReady, router.query]) + + return ( +
+ + Reset your password + + + Email + { e.preventDefault(); setEmail(e.target.value); }} + /> + + + + {errorMessage && ( + {errorMessage} + )} + + + +
+ ) +} diff --git a/packages/web/components/templates/EmailSignup.tsx b/packages/web/components/templates/EmailSignup.tsx new file mode 100644 index 000000000..8c12b5b30 --- /dev/null +++ b/packages/web/components/templates/EmailSignup.tsx @@ -0,0 +1,184 @@ +import { HStack, SpanBox, VStack } from '../elements/LayoutPrimitives' +import { Button } from '../elements/Button' +import { StyledText } from '../elements/StyledText' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { FormInput } from '../elements/FormElements' +import { TermAndConditionsFooter } from './LoginForm' +import { fetchEndpoint } from '../../lib/appConfig' +import { useValidateUsernameQuery } from '../../lib/networking/queries/useValidateUsernameQuery' +import { logoutMutation } from '../../lib/networking/mutations/logoutMutation' +import { styled } from '@stitches/react' +import { useRouter } from 'next/router' +import { formatMessage } from '../../locales/en/messages' +import { parseErrorCodes } from '../../lib/queryParamParser' +import Link from 'next/link' + +const StyledTextSpan = styled('span', StyledText) + +const BorderedFormInput = styled(FormInput, { + height: '40px', + paddingLeft: '6px', + borderRadius: '6px', + background: 'white', + border: `1px solid 1px solid rgba(0, 0, 0, 0.06)`, +}) + +const FormLabel = styled('label', { + fontSize: '16px', + color: '$omnivoreGray', +}) + +export function EmailSignup(): JSX.Element { + const router = useRouter() + const [email, setEmail] = useState(undefined) + const [password, setPassword] = useState(undefined) + const [fullname, setFullname] = useState(undefined) + const [username, setUsername] = useState(undefined) + const [debouncedUsername, setDebouncedUsername] = useState(undefined) + const [errorMessage, setErrorMessage] = useState(undefined) + + useEffect(() => { + if (!router.isReady) return + const errorCode = parseErrorCodes(router.query) + const errorMsg = errorCode + ? formatMessage({ id: `error.${errorCode}` }) + : undefined + setErrorMessage(errorMsg) + }, [router.isReady, router.query]) + + const { isUsernameValid, usernameErrorMessage } = useValidateUsernameQuery({ + username: debouncedUsername ?? '', + }) + + const handleUsernameChange = useCallback( + (event: React.ChangeEvent): void => { + setUsername(event.target.value) + setTimeout(() => { + setDebouncedUsername(event.target.value) + }, 400) + }, + [] + ) + + return ( +
+ + Sign Up + + + Email + { e.preventDefault(); setEmail(e.target.value); }} + /> + + + + Password + setPassword(e.target.value)} + /> + + + + Full Name + setFullname(e.target.value)} + /> + + + + Username + + + {username && username.length > 0 && usernameErrorMessage && ( + + {usernameErrorMessage} + + )} + {isUsernameValid && ( + + Username is available. + + )} + + + {errorMessage && ( + {errorMessage} + )} + + + + + + + + Already have an account? {' '} + + Login instead + + + + +
+ ) +} diff --git a/packages/web/components/templates/LoginForm.tsx b/packages/web/components/templates/LoginForm.tsx index 48996afcb..d0e4ace3c 100644 --- a/packages/web/components/templates/LoginForm.tsx +++ b/packages/web/components/templates/LoginForm.tsx @@ -9,6 +9,8 @@ import { } from '../../lib/appConfig' import AppleLogin from 'react-apple-login' +const StyledTextSpan = styled('span', StyledText) + export type LoginFormProps = { errorMessage?: string } @@ -104,22 +106,39 @@ export function LoginForm(props: LoginFormProps): JSX.Element { /> )} - + + + + Use your email address to{' '} + + + Login + + {' '} + or{' '} + + + Signup + + {' '} + with your email address. + + + + ) } -function LoginFormHeader() { - - - return ( - <> - - - ) -} - function GoogleAuthButton() { return ( @@ -148,8 +167,6 @@ function GoogleAuthButton() { } export function TermAndConditionsFooter(): JSX.Element { - const StyledTextSpan = styled('span', StyledText) - return ( - {props.children} @@ -37,7 +30,7 @@ export function ProfileLayout(props: ProfileLayoutProps): JSX.Element { alignment="center" distribution="between" css={{ - mt: '1px', + mt: '18px', ml: '18px', mr: '0', '@smDown': { diff --git a/packages/web/pages/email-login.tsx b/packages/web/pages/email-login.tsx index c402990ea..6011118f0 100644 --- a/packages/web/pages/email-login.tsx +++ b/packages/web/pages/email-login.tsx @@ -1,48 +1,56 @@ -import { PrimaryLayout } from '../components/templates/PrimaryLayout' -import { useEffect, useState } from 'react' -import { useRouter } from 'next/router' -import { StyledText } from '../components/elements/StyledText' -import { fetchEndpoint } from '../lib/appConfig' -import { parseErrorCodes } from '../lib/queryParamParser' -import { formatMessage } from '../locales/en/messages' - -export default function EmailLogin(): JSX.Element { - const [errorMessage, setErrorMessage] = useState( - undefined - ) - const [message, setMessage] = useState(undefined) - const router = useRouter() - - useEffect(() => { - if (!router.isReady) return - const errorCode = parseErrorCodes(router.query) - const errorMsg = errorCode - ? formatMessage({ id: `error.${errorCode}` }) - : undefined - setErrorMessage(errorMsg) - - const message = router.query.message - ? formatMessage({ id: `login.${router.query.message}` }) - : undefined - setMessage(message) - }, [router.isReady, router.query]) +import { PageMetaData } from '../components/patterns/PageMetaData' +import { ProfileLayout } from '../components/templates/ProfileLayout' +import { EmailLogin } from '../components/templates/EmailLogin' +export default function EmailLoginPage(): JSX.Element { return ( - - {message && {message}} -

Email Login

-
-
- - -
-
- - -
- {errorMessage && {errorMessage}} - -
-
+ <> + + + + +
+ ) } + +// export default function EmailLogin(): JSX.Element { +// const [errorMessage, setErrorMessage] = useState( +// undefined +// ) +// const [message, setMessage] = useState(undefined) +// const router = useRouter() + +// useEffect(() => { +// if (!router.isReady) return +// const errorCode = parseErrorCodes(router.query) +// const errorMsg = errorCode +// ? formatMessage({ id: `error.${errorCode}` }) +// : undefined +// setErrorMessage(errorMsg) + +// const message = router.query.message +// ? formatMessage({ id: `login.${router.query.message}` }) +// : undefined +// setMessage(message) +// }, [router.isReady, router.query]) + +// return ( +// +// {message && {message}} +//

Email Login

+//
+//
+// +// +//
+//
+// +// +//
+// {errorMessage && {errorMessage}} +// +//
+//
+// ) +// } diff --git a/packages/web/pages/email-registration.tsx b/packages/web/pages/email-registration.tsx deleted file mode 100644 index 468569262..000000000 --- a/packages/web/pages/email-registration.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { PrimaryLayout } from '../components/templates/PrimaryLayout' -import { useEffect, useState } from 'react' -import { useRouter } from 'next/router' -import { StyledText } from '../components/elements/StyledText' -import { fetchEndpoint } from '../lib/appConfig' -import { parseErrorCodes } from '../lib/queryParamParser' -import { formatMessage } from '../locales/en/messages' - -export default function EmailRegistration(): JSX.Element { - const [errorMessage, setErrorMessage] = useState( - undefined - ) - const router = useRouter() - - useEffect(() => { - if (!router.isReady) return - const errorCode = parseErrorCodes(router.query) - const message = errorCode - ? formatMessage({ id: `error.${errorCode}` }) - : undefined - setErrorMessage(message) - }, [router.isReady, router.query]) - - return ( - -

Email Registration

-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- {errorMessage && {errorMessage}} - -
-
- ) -} diff --git a/packages/web/pages/email-reset-password.tsx b/packages/web/pages/email-reset-password.tsx new file mode 100644 index 000000000..88b0e4b8c --- /dev/null +++ b/packages/web/pages/email-reset-password.tsx @@ -0,0 +1,15 @@ +import { PageMetaData } from '../components/patterns/PageMetaData' +import { ProfileLayout } from '../components/templates/ProfileLayout' +import { EmailResetPassword } from '../components/templates/EmailResetPassword' + +export default function EmailRegistrationPage(): JSX.Element { + return ( + <> + + + + +
+ + ) +} diff --git a/packages/web/pages/email-signup.tsx b/packages/web/pages/email-signup.tsx new file mode 100644 index 000000000..5fa84d37b --- /dev/null +++ b/packages/web/pages/email-signup.tsx @@ -0,0 +1,15 @@ +import { PageMetaData } from '../components/patterns/PageMetaData' +import { ProfileLayout } from '../components/templates/ProfileLayout' +import { EmailSignup } from '../components/templates/EmailSignup' + +export default function EmailRegistrationPage(): JSX.Element { + return ( + <> + + + + +
+ + ) +}