Skip to content

Commit

Permalink
fix: password confirmation field and minor improvements (#2479)
Browse files Browse the repository at this point in the history
* fix: password confirmation field and minor improvements

* fix: import order

* fix: address comments

* fix: address comments
  • Loading branch information
hoyyeva committed Jul 6, 2022
1 parent ff1f71e commit 3a69150
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 33 deletions.
66 changes: 54 additions & 12 deletions ui/pages/login/finish.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { useRouter } from 'next/router'
import { useState } from 'react'
import { useSWRConfig } from 'swr'

import ErrorMessage from '../../components/error-message'
import Login from '../../components/layouts/login'

export default function Finish() {
const router = useRouter()

const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [error, setError] = useState('')
const [errors, setErrors] = useState('')

const { mutate } = useSWRConfig()

const { query } = router
Expand All @@ -21,6 +25,13 @@ export default function Finish() {
async function finish(e) {
e.preventDefault()

if (password !== confirmPassword) {
setErrors({
confirmPassword: 'passwords do not match',
})
return false
}

try {
const res = await fetch(`/api/users/${user}`, {
method: 'PUT',
Expand All @@ -33,11 +44,19 @@ export default function Finish() {

await mutate('/api/users/self')

router.replace('/')
await router.replace('/')
} catch (e) {
setError(e.message || 'Invalid password')
if (e.fieldErrors) {
const errors = {}
for (const error of e.fieldErrors) {
errors[error.fieldName.toLowerCase()] =
error.errors[0] || 'invalid value'
}
setErrors(errors)
} else {
setError(e.message || 'Invalid password')
}
}

return false
}

Expand All @@ -54,7 +73,7 @@ export default function Finish() {
onSubmit={finish}
className='relative flex w-full max-w-sm flex-col'
>
<div className='my-4 w-full'>
<div className='my-2 w-full'>
<label
htmlFor='password'
className='text-3xs uppercase text-gray-500'
Expand All @@ -68,24 +87,47 @@ export default function Finish() {
placeholder='enter your new password'
onChange={e => {
setPassword(e.target.value)
setErrors({})
setError('')
}}
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.password ? 'border-pink-500/60' : ''
}`}
/>
{errors.password && <ErrorMessage message={errors.password} />}
</div>
<div className='my-2 w-full'>
<label
htmlFor='password'
className='text-3xs uppercase text-gray-500'
>
Confirm Password
</label>
<input
required
name='confirmPassword'
type='password'
placeholder='confirm your password'
onChange={e => {
setConfirmPassword(e.target.value)
setErrors({})
setError('')
}}
className={`w-full border-b border-gray-800 bg-transparent px-px py-3 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
error ? 'border-pink-500/60' : ''
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.confirmPassword ? 'border-pink-500/60' : ''
}`}
/>
{errors.confirmPassword && (
<ErrorMessage message={errors.confirmPassword} />
)}
</div>
<button
disabled={!password}
disabled={!password || !confirmPassword}
className='my-2 rounded-lg border border-violet-300 px-4 py-3 text-2xs text-violet-100 hover:border-violet-100 disabled:pointer-events-none disabled:opacity-30'
>
Finish
</button>
{error && (
<p className='absolute -bottom-3.5 mx-auto w-full text-center text-2xs text-pink-400'>
{error}
</p>
)}
{error && <ErrorMessage message={error} />}
</form>
</>
)
Expand Down
32 changes: 24 additions & 8 deletions ui/pages/settings/password-reset.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ export default function PasswordReset() {
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [error, setError] = useState('')
const [errors, setErrors] = useState({})

async function onSubmit(e) {
e.preventDefault()

if (password !== confirmPassword) {
setError('password does not match')
setErrors({
confirmPassword: 'passwords do not match',
})
return false
}

setError('')

try {
const rest = await fetch(`/api/users/${auth?.id}`, {
method: 'PUT',
Expand All @@ -43,7 +44,16 @@ export default function PasswordReset() {

router.replace('/settings?resetPassword=success')
} catch (e) {
setError(e.message || 'something went wrong, please try again')
if (e.fieldErrors) {
const errors = {}
for (const error of e.fieldErrors) {
errors[error.fieldName.toLowerCase()] =
error.errors[0] || 'invalid value'
}
setErrors(errors)
} else {
setError(e.message)
}
}
}

Expand All @@ -70,12 +80,14 @@ export default function PasswordReset() {
placeholder='enter your new password'
onChange={e => {
setPassword(e.target.value)
setErrors({})
setError('')
}}
className={`w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:border-gray-200 focus:outline-none ${
error ? 'border-pink-500/60' : ''
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.password ? 'border-pink-500/60' : ''
}`}
/>
{errors.password && <ErrorMessage message={errors.password} />}
</div>
<div className='my-2 w-full'>
<label
Expand All @@ -91,12 +103,16 @@ export default function PasswordReset() {
placeholder='confirm your new password'
onChange={e => {
setConfirmPassword(e.target.value)
setErrors({})
setError('')
}}
className={`w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
error ? 'border-pink-500/60' : ''
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.confirmPassword ? 'border-pink-500/60' : ''
}`}
/>
{errors.confirmPassword && (
<ErrorMessage message={errors.confirmPassword} />
)}
</div>
<div className='mt-6 flex flex-row items-center justify-end'>
<Link href='/settings'>
Expand Down
63 changes: 50 additions & 13 deletions ui/pages/signup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ export default function Signup() {

const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [error, setError] = useState('')
const [errors, setErrors] = useState({})

async function onSubmit(e) {
e.preventDefault()

setErrors({})
setError('')
if (password !== confirmPassword) {
setErrors({
confirmPassword: 'passwords do not match',
})
return false
}

try {
// signup
Expand Down Expand Up @@ -78,47 +83,79 @@ export default function Signup() {
Set up your admin user to get started.
</h2>
<form onSubmit={onSubmit} className='flex w-full max-w-sm flex-col'>
<div className='my-4 w-full'>
<label htmlFor='email' className='text-3xs uppercase text-gray-400'>
<div className='my-2 w-full'>
<label htmlFor='email' className='text-3xs uppercase text-gray-500'>
Email
</label>
<input
autoFocus
name='email'
type='email'
placeholder='email@address.com'
onChange={e => setEmail(e.target.value)}
className={`mt-2 w-full border-b border-gray-800 bg-transparent px-px py-3 text-2xs placeholder:italic focus:border-b focus:border-gray-200 focus:outline-none ${
onChange={e => {
setEmail(e.target.value)
setErrors({})
setError('')
}}
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.email ? 'border-pink-500/60' : ''
}`}
/>
{errors.email && <ErrorMessage message={errors.email} />}
</div>
<div className='my-4 w-full'>
<div className='my-2 w-full'>
<label
htmlFor='password'
className='text-3xs uppercase text-gray-400'
className='text-3xs uppercase text-gray-500'
>
Password
</label>
<input
type='password'
placeholder='enter your password'
onChange={e => setPassword(e.target.value)}
className={`mt-2 w-full border-b border-gray-800 bg-transparent px-px py-3 text-2xs placeholder:italic focus:border-b focus:border-gray-200 focus:outline-none ${
onChange={e => {
setPassword(e.target.value)
setErrors({})
setError('')
}}
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.password ? 'border-pink-500/60' : ''
}`}
/>
{errors.password && <ErrorMessage message={errors.password} />}
</div>

<div className='my-2 w-full'>
<label
htmlFor='password'
className='text-3xs uppercase text-gray-500'
>
Confirm Password
</label>
<input
required
name='confirmPassword'
type='password'
placeholder='confirm your password'
onChange={e => {
setConfirmPassword(e.target.value)
setErrors({})
setError('')
}}
className={`mb-1 w-full border-b border-gray-800 bg-transparent px-px py-2 text-2xs placeholder:italic focus:border-b focus:outline-none focus:ring-gray-200 ${
errors.confirmPassword ? 'border-pink-500/60' : ''
}`}
/>
{errors.confirmPassword && (
<ErrorMessage message={errors.confirmPassword} />
)}
</div>
<button
disabled={!email || !password}
disabled={!email || !password || !confirmPassword}
className='my-2 rounded-lg border border-violet-300 px-4 py-3 text-2xs text-violet-100 hover:border-violet-100 disabled:pointer-events-none disabled:opacity-30'
>
Get Started
{error && <ErrorMessage message={error} center />}
</button>
{error && <ErrorMessage message={error} center />}
</form>
</>
)
Expand Down

0 comments on commit 3a69150

Please sign in to comment.