mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Implement UI for email login and registration
This commit is contained in:
parent
db2dceec4b
commit
22c1f6f7b4
11 changed files with 527 additions and 120 deletions
|
|
@ -97,7 +97,6 @@ export const ModalButtonBar = (props: ModalButtonBarProps) => {
|
|||
}}
|
||||
>
|
||||
<Button style={'ctaOutlineYellow'} type="button" onClick={(event) => {
|
||||
console.log('cancelinmg')
|
||||
event.preventDefault()
|
||||
props.onOpenChange(false)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ const textVariants = {
|
|||
fontWeight: '500',
|
||||
},
|
||||
subHeadline: {
|
||||
fontSize: '$5',
|
||||
fontSize: '24px',
|
||||
fontWeight: '500',
|
||||
},
|
||||
boldHeadline: {
|
||||
fontWeight: 'bold',
|
||||
|
|
|
|||
134
packages/web/components/templates/EmailLogin.tsx
Normal file
134
packages/web/components/templates/EmailLogin.tsx
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import { HStack, 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 { parseErrorCodes } from '../../lib/queryParamParser'
|
||||
import { formatMessage } from '../../locales/en/messages'
|
||||
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 EmailLogin(): JSX.Element {
|
||||
const router = useRouter()
|
||||
const [email, setEmail] = useState<string | undefined>(undefined)
|
||||
const [password, setPassword] = useState<string | undefined>(undefined)
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(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 (
|
||||
<form action={`${fetchEndpoint}/auth/email-login`} method="POST">
|
||||
<VStack alignment="center" css={{ padding: '16px' }}>
|
||||
<StyledText style="subHeadline">Login</StyledText>
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="email"
|
||||
type="text"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
onChange={(e) => { e.preventDefault(); setEmail(e.target.value); }}
|
||||
/>
|
||||
</SpanBox>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="password"
|
||||
type="password"
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
|
||||
{errorMessage && (
|
||||
<StyledText style="error">{errorMessage}</StyledText>
|
||||
)}
|
||||
|
||||
<HStack
|
||||
alignment="center"
|
||||
distribution="end"
|
||||
css={{
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
height: '80px',
|
||||
}}
|
||||
>
|
||||
<Button style={'ctaOutlineYellow'} css={{ borderColor: '$omnivoreLightGray' }} type="button" onClick={async (event) => {
|
||||
window.localStorage.removeItem('authVerified')
|
||||
window.localStorage.removeItem('authToken')
|
||||
try {
|
||||
await logoutMutation()
|
||||
} catch (e) {
|
||||
console.log('error logging out', e)
|
||||
}
|
||||
window.location.href = '/'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" style={'ctaDarkYellow'}>Login</Button>
|
||||
</HStack>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
m: '0px',
|
||||
pt: '16px',
|
||||
width: '100%',
|
||||
color: '$omnivoreLightGray',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Don't have an account? {' '}
|
||||
<Link href="/email-signup" passHref>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>Sign up</StyledTextSpan>
|
||||
</Link>
|
||||
</StyledText>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
mt: '0px',
|
||||
pt: '4px',
|
||||
width: '100%',
|
||||
color: '$omnivoreLightGray',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Forgot your password? {' '}
|
||||
<Link href="/email-reset-password" passHref>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>Click here</StyledTextSpan>
|
||||
</Link>
|
||||
</StyledText>
|
||||
</VStack>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
94
packages/web/components/templates/EmailResetPassword.tsx
Normal file
94
packages/web/components/templates/EmailResetPassword.tsx
Normal file
|
|
@ -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<string | undefined>(undefined)
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(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 (
|
||||
<form action={`${fetchEndpoint}/auth/email-signup`} method="POST">
|
||||
<VStack alignment="center" css={{ padding: '16px' }}>
|
||||
<StyledText style="subHeadline">Reset your password</StyledText>
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="email"
|
||||
type="text"
|
||||
name="email"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
onChange={(e) => { e.preventDefault(); setEmail(e.target.value); }}
|
||||
/>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
|
||||
{errorMessage && (
|
||||
<StyledText style="error">{errorMessage}</StyledText>
|
||||
)}
|
||||
<Button type="submit" style="ctaDarkYellow" css={{ my: '$2' }}>
|
||||
Reset Password
|
||||
</Button>
|
||||
<Button
|
||||
style="ghost"
|
||||
onClick={async (e) => {
|
||||
e.preventDefault()
|
||||
window.localStorage.removeItem('authVerified')
|
||||
window.localStorage.removeItem('authToken')
|
||||
try {
|
||||
await logoutMutation()
|
||||
} catch (e) {
|
||||
console.log('error logging out', e)
|
||||
}
|
||||
window.location.href = '/'
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
css={{
|
||||
color: '$omnivoreRed',
|
||||
textDecoration: 'underline',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</StyledText>
|
||||
</Button>
|
||||
</VStack>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
184
packages/web/components/templates/EmailSignup.tsx
Normal file
184
packages/web/components/templates/EmailSignup.tsx
Normal file
|
|
@ -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<string | undefined>(undefined)
|
||||
const [password, setPassword] = useState<string | undefined>(undefined)
|
||||
const [fullname, setFullname] = useState<string | undefined>(undefined)
|
||||
const [username, setUsername] = useState<string | undefined>(undefined)
|
||||
const [debouncedUsername, setDebouncedUsername] = useState<string | undefined>(undefined)
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(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<HTMLInputElement>): void => {
|
||||
setUsername(event.target.value)
|
||||
setTimeout(() => {
|
||||
setDebouncedUsername(event.target.value)
|
||||
}, 400)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<form action={`${fetchEndpoint}/auth/email-signup`} method="POST">
|
||||
<VStack alignment="center" css={{ padding: '16px' }}>
|
||||
<StyledText style="subHeadline">Sign Up</StyledText>
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="email"
|
||||
type="text"
|
||||
name="email"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
onChange={(e) => { e.preventDefault(); setEmail(e.target.value); }}
|
||||
/>
|
||||
</SpanBox>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</SpanBox>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Full Name</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="fullname"
|
||||
type="text"
|
||||
name="name"
|
||||
value={fullname}
|
||||
placeholder="Full Name"
|
||||
onChange={(e) => setFullname(e.target.value)}
|
||||
/>
|
||||
</SpanBox>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="username"
|
||||
type="text"
|
||||
name="username"
|
||||
value={username}
|
||||
placeholder="Username"
|
||||
onChange={handleUsernameChange}
|
||||
/>
|
||||
</SpanBox>
|
||||
{username && username.length > 0 && usernameErrorMessage && (
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
m: 0,
|
||||
pl: '$2',
|
||||
color: '$error',
|
||||
alignSelf: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{usernameErrorMessage}
|
||||
</StyledText>
|
||||
)}
|
||||
{isUsernameValid && (
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ m: 0, pl: '$2', alignSelf: 'flex-start' }}
|
||||
>
|
||||
Username is available.
|
||||
</StyledText>
|
||||
)}
|
||||
</VStack>
|
||||
|
||||
{errorMessage && (
|
||||
<StyledText style="error">{errorMessage}</StyledText>
|
||||
)}
|
||||
|
||||
<HStack
|
||||
alignment="center"
|
||||
distribution="end"
|
||||
css={{
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
height: '80px',
|
||||
}}
|
||||
>
|
||||
<Button style={'ctaOutlineYellow'} css={{ borderColor: 'rgba(0, 0, 0, 0.06)' }} type="button" onClick={async (event) => {
|
||||
window.localStorage.removeItem('authVerified')
|
||||
window.localStorage.removeItem('authToken')
|
||||
try {
|
||||
await logoutMutation()
|
||||
} catch (e) {
|
||||
console.log('error logging out', e)
|
||||
}
|
||||
window.location.href = '/'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" style={'ctaDarkYellow'}>Sign Up</Button>
|
||||
</HStack>
|
||||
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
pt: '16px',
|
||||
color: '$omnivoreLightGray',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Already have an account? {' '}
|
||||
<Link href="/email-login" passHref>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>Login instead</StyledTextSpan>
|
||||
</Link>
|
||||
</StyledText>
|
||||
<TermAndConditionsFooter />
|
||||
</VStack>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
|
@ -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 {
|
|||
/>
|
||||
</Box>
|
||||
)}
|
||||
</VStack>
|
||||
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
pt: '16px',
|
||||
maxWidth: '220px',
|
||||
textAlign: 'left',
|
||||
color: '$omnivoreLightGray',
|
||||
}}
|
||||
>
|
||||
<SpanBox>
|
||||
Use your email address to{' '}
|
||||
<Link href="/email-login" passHref>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>
|
||||
Login
|
||||
</StyledTextSpan>
|
||||
</Link>{' '}
|
||||
or{' '}
|
||||
<Link href="/email-signup" passHref>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>
|
||||
Signup
|
||||
</StyledTextSpan>
|
||||
</Link>{' '}
|
||||
with your email address.
|
||||
</SpanBox>
|
||||
</StyledText>
|
||||
|
||||
</VStack>
|
||||
<TermAndConditionsFooter />
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
||||
function LoginFormHeader() {
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function GoogleAuthButton() {
|
||||
return (
|
||||
<Box css={{ overflow: 'hidden' }}>
|
||||
|
|
@ -148,8 +167,6 @@ function GoogleAuthButton() {
|
|||
}
|
||||
|
||||
export function TermAndConditionsFooter(): JSX.Element {
|
||||
const StyledTextSpan = styled('span', StyledText)
|
||||
|
||||
return (
|
||||
<StyledText
|
||||
style="caption"
|
||||
|
|
|
|||
|
|
@ -14,13 +14,6 @@ export function ProfileLayout(props: ProfileLayoutProps): JSX.Element {
|
|||
distribution="center"
|
||||
css={{ bg: '$omnivoreYellow', height: '100vh' }}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
position: 'relative',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
></Box>
|
||||
{props.children}
|
||||
</VStack>
|
||||
|
||||
|
|
@ -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': {
|
||||
|
|
|
|||
|
|
@ -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<string | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [message, setMessage] = useState<string | undefined>(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 (
|
||||
<PrimaryLayout pageTestId="email-login">
|
||||
{message && <StyledText style={'headline'}>{message}</StyledText>}
|
||||
<h1>Email Login</h1>
|
||||
<form action={`${fetchEndpoint}/auth/email-login`} method="POST">
|
||||
<div>
|
||||
<label>Email</label>
|
||||
<input type="email" name={'email'} required />
|
||||
</div>
|
||||
<div>
|
||||
<label>Password</label>
|
||||
<input type="password" name={'password'} required />
|
||||
</div>
|
||||
{errorMessage && <StyledText style="error">{errorMessage}</StyledText>}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</PrimaryLayout>
|
||||
<>
|
||||
<PageMetaData title="Login - Omnivore" path="/email-login" />
|
||||
<ProfileLayout>
|
||||
<EmailLogin />
|
||||
</ProfileLayout>
|
||||
<div data-testid="email-login-page-tag" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// export default function EmailLogin(): JSX.Element {
|
||||
// const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
||||
// undefined
|
||||
// )
|
||||
// const [message, setMessage] = useState<string | undefined>(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 (
|
||||
// <PrimaryLayout pageTestId="email-login">
|
||||
// {message && <StyledText style={'headline'}>{message}</StyledText>}
|
||||
// <h1>Email Login</h1>
|
||||
// <form action={`${fetchEndpoint}/auth/email-login`} method="POST">
|
||||
// <div>
|
||||
// <label>Email</label>
|
||||
// <input type="email" name={'email'} required />
|
||||
// </div>
|
||||
// <div>
|
||||
// <label>Password</label>
|
||||
// <input type="password" name={'password'} required />
|
||||
// </div>
|
||||
// {errorMessage && <StyledText style="error">{errorMessage}</StyledText>}
|
||||
// <button type="submit">Login</button>
|
||||
// </form>
|
||||
// </PrimaryLayout>
|
||||
// )
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -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<string | undefined>(
|
||||
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 (
|
||||
<PrimaryLayout pageTestId="email-registration">
|
||||
<h1>Email Registration</h1>
|
||||
<form action={`${fetchEndpoint}/auth/email-signup`} method="POST">
|
||||
<div>
|
||||
<label>Email</label>
|
||||
<input type="email" name={'email'} required />
|
||||
</div>
|
||||
<div>
|
||||
<label>Password</label>
|
||||
<input type="password" name={'password'} required maxLength={40} />
|
||||
</div>
|
||||
<div>
|
||||
<label>Full Name</label>
|
||||
<input type="text" name={'name'} required />
|
||||
</div>
|
||||
<div>
|
||||
<label>Username</label>
|
||||
<input type="text" name={'username'} required />
|
||||
</div>
|
||||
<div>
|
||||
<label>Bio</label>
|
||||
<input type="text" name={'bio'} />
|
||||
</div>
|
||||
{errorMessage && <StyledText style="error">{errorMessage}</StyledText>}
|
||||
<button type="submit">Signup</button>
|
||||
</form>
|
||||
</PrimaryLayout>
|
||||
)
|
||||
}
|
||||
15
packages/web/pages/email-reset-password.tsx
Normal file
15
packages/web/pages/email-reset-password.tsx
Normal file
|
|
@ -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 (
|
||||
<>
|
||||
<PageMetaData title="Reset your password - Omnivore" path="/email-reset-password" />
|
||||
<ProfileLayout>
|
||||
<EmailResetPassword />
|
||||
</ProfileLayout>
|
||||
<div data-testid="email-reset-password-page-tag" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
15
packages/web/pages/email-signup.tsx
Normal file
15
packages/web/pages/email-signup.tsx
Normal file
|
|
@ -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 (
|
||||
<>
|
||||
<PageMetaData title="Sign up with Email - Omnivore" path="/email-signup" />
|
||||
<ProfileLayout>
|
||||
<EmailSignup />
|
||||
</ProfileLayout>
|
||||
<div data-testid="email-signup-page-tag" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in a new issue