* fix: cannot login with email on PWA * adjust other email templates * restore manual url on new user email * no padding on button section * cleanup * generate 6-digit bechh32 token * token needs to be fed as lower case; validator case insensitive * delete token if user has failed 3 times * proposal: context-independent error page * include expiration time on email page message * add expiration time to emails * independent checkPWA function * restore token deletion if successful auth * final cleanup: remove unused function * compact useVerificationToken * email.js: magic code for non-PWA users * adjust email templates * MultiInput component; magic code via MultiInput * hotfix: revert length testing; larger width for inputs * manual bech32 token generation; no upperCase * reverting to string concatenation * layout tweaks, fix error placement * pastable inputs * small nit fixes * less ambiguous error path --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com> Co-authored-by: k00b <k00b@stacker.news>
71 lines
2.6 KiB
JavaScript
71 lines
2.6 KiB
JavaScript
import Image from 'react-bootstrap/Image'
|
|
import { StaticLayout } from '@/components/layout'
|
|
import { getGetServerSideProps } from '@/api/ssrApollo'
|
|
import { useRouter } from 'next/router'
|
|
import { useState, useEffect, useCallback } from 'react'
|
|
import { Form, SubmitButton, MultiInput } from '@/components/form'
|
|
import { emailTokenSchema } from '@/lib/validate'
|
|
|
|
// force SSR to include CSP nonces
|
|
export const getServerSideProps = getGetServerSideProps({ query: null })
|
|
|
|
export default function Email () {
|
|
const router = useRouter()
|
|
const [callback, setCallback] = useState(null) // callback.email, callback.callbackUrl
|
|
|
|
useEffect(() => {
|
|
setCallback(JSON.parse(window.sessionStorage.getItem('callback')))
|
|
}, [])
|
|
|
|
// build and push the final callback URL
|
|
const pushCallback = useCallback((token) => {
|
|
const params = new URLSearchParams()
|
|
if (callback.callbackUrl) params.set('callbackUrl', callback.callbackUrl)
|
|
params.set('token', token)
|
|
params.set('email', callback.email)
|
|
const url = `/api/auth/callback/email?${params.toString()}`
|
|
router.push(url)
|
|
}, [callback, router])
|
|
|
|
return (
|
|
<StaticLayout>
|
|
<div className='p-4 text-center'>
|
|
<video width='640' height='302' loop autoPlay muted preload='auto' playsInline style={{ maxWidth: '100%' }}>
|
|
<source src={`${process.env.NEXT_PUBLIC_ASSET_PREFIX}/cowboy-saloon.mp4`} type='video/mp4' />
|
|
<Image className='rounded-1 shadow-sm' width='640' height='302' src={`${process.env.NEXT_PUBLIC_ASSET_PREFIX}/cowboy-saloon.gif`} fluid />
|
|
</video>
|
|
<h2 className='pt-4'>Check your email</h2>
|
|
<h4 className='text-muted pt-2 pb-4'>a magic code has been sent to {callback ? callback.email : 'your email address'}</h4>
|
|
<MagicCodeForm onSubmit={(token) => pushCallback(token)} disabled={!callback} />
|
|
</div>
|
|
</StaticLayout>
|
|
)
|
|
}
|
|
|
|
export const MagicCodeForm = ({ onSubmit, disabled }) => {
|
|
return (
|
|
<Form
|
|
initial={{
|
|
token: ''
|
|
}}
|
|
schema={emailTokenSchema}
|
|
onSubmit={(values) => {
|
|
onSubmit(values.token.toLowerCase()) // token is displayed in uppercase but we need to check it in lowercase
|
|
}}
|
|
>
|
|
<MultiInput
|
|
length={6}
|
|
charLength={1}
|
|
name='token'
|
|
required
|
|
autoFocus
|
|
groupClassName='d-flex flex-column justify-content-center gap-2'
|
|
inputType='text'
|
|
hideError // hide error message on every input, allow custom error message
|
|
disabled={disabled} // disable the form if no callback is provided
|
|
/>
|
|
<SubmitButton variant='primary' className='px-4' disabled={disabled}>login</SubmitButton>
|
|
</Form>
|
|
)
|
|
}
|