Skip to content

Commit 77d506f

Browse files
Merge pull request #178 from guillermoscript:qa-auth-change
Qa-auth-change
2 parents 7d42b11 + c7aca12 commit 77d506f

File tree

3 files changed

+191
-166
lines changed

3 files changed

+191
-166
lines changed

app/[locale]/auth/forgot-password/page.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client'
22

33
import { zodResolver } from '@hookform/resolvers/zod'
4+
import { Loader } from 'lucide-react'
45
import Link from 'next/link'
56
import { useForm } from 'react-hook-form'
67
import { z } from 'zod'
@@ -96,8 +97,17 @@ export default function ForgotPassword({
9697
</FormItem>
9798
)}
9899
/>
99-
<Button type="submit">
100-
{t('auth.forgotPassword.submit')}
100+
<Button
101+
disabled={form.formState.isSubmitting}
102+
type="submit"
103+
>
104+
{form.formState.isSubmitting ? (
105+
<>
106+
<Loader className="animate-spin" />
107+
</>
108+
) : (
109+
t('auth.forgotPassword.submit')
110+
)}
101111
</Button>
102112
</form>
103113
</Form>
Lines changed: 2 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,4 @@
1-
'use client'
2-
3-
import { zodResolver } from '@hookform/resolvers/zod'
4-
import { EyeIcon, EyeOffIcon } from 'lucide-react'
5-
import Link from 'next/link'
6-
import { useRouter } from 'next/navigation'
7-
import { useState } from 'react'
8-
import { useForm } from 'react-hook-form'
9-
import { z } from 'zod'
10-
11-
import { resetPasswordFun } from '@/actions/auth/authActions'
12-
import { useI18n } from '@/app/locales/client'
13-
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
14-
import { Button } from '@/components/ui/button'
15-
import {
16-
Form,
17-
FormControl,
18-
FormField,
19-
FormItem,
20-
FormLabel,
21-
FormMessage,
22-
} from '@/components/ui/form'
23-
import { Input } from '@/components/ui/input'
24-
import { useToast } from '@/components/ui/use-toast'
25-
26-
const FormSchema = z.object({
27-
password: z
28-
.string()
29-
.min(8, { message: 'Password must be at least 8 characters.' })
30-
.max(100, {
31-
message: 'Password must be at most 100 characters.',
32-
}),
33-
})
1+
import ResetPasswordForm from '@/components/auth/ResetPasswordForm'
342

353
export default function ResetPassword({
364
searchParams,
@@ -41,137 +9,7 @@ export default function ResetPassword({
419
code: string
4210
}
4311
}) {
44-
const form = useForm<z.infer<typeof FormSchema>>({
45-
resolver: zodResolver(FormSchema),
46-
defaultValues: {
47-
password: '',
48-
},
49-
})
50-
51-
const t = useI18n()
52-
53-
const [showPassword, setShowPassword] = useState(false)
54-
const { toast } = useToast()
55-
const router = useRouter()
56-
57-
const submit = async (data: z.infer<typeof FormSchema>) => {
58-
try {
59-
const res = await resetPasswordFun({
60-
password: data.password,
61-
code: searchParams.code,
62-
})
63-
64-
if (res.error) {
65-
return toast({
66-
title: 'Error',
67-
description: res.error,
68-
variant: 'destructive',
69-
})
70-
}
71-
72-
router.push('/')
73-
74-
return toast({
75-
title: 'Success',
76-
description: res.message,
77-
})
78-
} catch (error: any) {
79-
return toast({
80-
title: 'Error',
81-
description: error.message,
82-
variant: 'destructive',
83-
})
84-
}
85-
}
86-
8712
return (
88-
<>
89-
<div className="lg:p-8">
90-
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
91-
<div className="flex flex-col space-y-2 text-center">
92-
<h1 className="text-2xl font-semibold tracking-tight">
93-
{t('auth.resetPassword.header')}
94-
</h1>
95-
<p className="text-sm text-muted-foreground">
96-
{t('auth.resetPassword.description')}
97-
</p>
98-
</div>
99-
<Form {...form}>
100-
<form
101-
onSubmit={form.handleSubmit(submit)}
102-
className="animate-in flex-1 flex flex-col w-full justify-center gap-2 text-foreground"
103-
>
104-
<FormField
105-
control={form.control}
106-
name="password"
107-
render={({ field }) => (
108-
<FormItem>
109-
<FormLabel>
110-
{t(
111-
'auth.resetPassword.newPassword'
112-
)}
113-
</FormLabel>
114-
<FormControl>
115-
<div className="rounded-md px-4 py-2 w-full bg-inherit border mb-6 gap-4 flex items-center justify-between">
116-
<Input
117-
className="border-none w-full bg-transparent focus:outline-none"
118-
type={
119-
showPassword
120-
? 'text'
121-
: 'password'
122-
}
123-
{...field}
124-
/>
125-
<button
126-
type="button"
127-
onClick={() =>
128-
setShowPassword(
129-
!showPassword
130-
)
131-
}
132-
>
133-
{!showPassword ? (
134-
<EyeIcon />
135-
) : (
136-
<EyeOffIcon />
137-
)}
138-
</button>
139-
</div>
140-
<p className="text-xs text-muted-foreground">
141-
{t('auth.resetPassword.passwordHelp')}
142-
</p>
143-
</FormControl>
144-
<FormMessage />
145-
</FormItem>
146-
)}
147-
/>
148-
<Button
149-
disabled={form.formState.isSubmitting}
150-
type="submit"
151-
>
152-
{form.formState.isSubmitting
153-
? t('auth.resetPassword.loading')
154-
: t('auth.resetPassword.button')}
155-
</Button>
156-
</form>
157-
</Form>
158-
{searchParams.error && (
159-
<Alert variant="destructive">
160-
<AlertTitle>Error!</AlertTitle>
161-
<AlertDescription>
162-
{searchParams.error}
163-
</AlertDescription>
164-
</Alert>
165-
)}
166-
167-
<Link
168-
href="/auth/login"
169-
className="text-center text-sm cursor-pointer text-primary"
170-
>
171-
{t('auth.resetPassword.back')}
172-
</Link>
173-
</div>
174-
</div>
175-
</>
13+
<ResetPasswordForm searchParams={searchParams} />
17614
)
17715
}

components/auth/ResetPasswordForm.tsx

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
'use client'
2+
3+
import { zodResolver } from '@hookform/resolvers/zod'
4+
import { EyeIcon, EyeOffIcon } from 'lucide-react'
5+
import Link from 'next/link'
6+
import { useRouter } from 'next/navigation'
7+
import { useState } from 'react'
8+
import { useForm } from 'react-hook-form'
9+
import { z } from 'zod'
10+
11+
import { resetPasswordFun } from '@/actions/auth/authActions'
12+
import { useI18n } from '@/app/locales/client'
13+
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
14+
import { Button } from '@/components/ui/button'
15+
import {
16+
Form,
17+
FormControl,
18+
FormField,
19+
FormItem,
20+
FormLabel,
21+
FormMessage,
22+
} from '@/components/ui/form'
23+
import { Input } from '@/components/ui/input'
24+
import { useToast } from '@/components/ui/use-toast'
25+
26+
const FormSchema = z.object({
27+
password: z
28+
.string()
29+
.min(8, { message: 'Password must be at least 8 characters.' })
30+
.max(100, {
31+
message: 'Password must be at most 100 characters.',
32+
}),
33+
})
34+
35+
export default function ResetPasswordForm({
36+
searchParams,
37+
}: {
38+
searchParams: {
39+
message: string
40+
error: string
41+
code: string
42+
}
43+
}) {
44+
const form = useForm<z.infer<typeof FormSchema>>({
45+
resolver: zodResolver(FormSchema),
46+
defaultValues: {
47+
password: '',
48+
},
49+
})
50+
51+
const t = useI18n()
52+
53+
const [showPassword, setShowPassword] = useState(false)
54+
const { toast } = useToast()
55+
const router = useRouter()
56+
57+
const submit = async (data: z.infer<typeof FormSchema>) => {
58+
try {
59+
const res = await resetPasswordFun({
60+
password: data.password,
61+
code: searchParams.code,
62+
})
63+
64+
if (res.error) {
65+
return toast({
66+
title: 'Error',
67+
description: res.error,
68+
variant: 'destructive',
69+
})
70+
}
71+
72+
router.push('/')
73+
74+
return toast({
75+
title: 'Success',
76+
description: res.message,
77+
})
78+
} catch (error: any) {
79+
return toast({
80+
title: 'Error',
81+
description: error.message,
82+
variant: 'destructive',
83+
})
84+
}
85+
}
86+
87+
return (
88+
<>
89+
<div className="lg:p-8">
90+
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
91+
<div className="flex flex-col space-y-2 text-center">
92+
<h1 className="text-2xl font-semibold tracking-tight">
93+
{t('auth.resetPassword.header')}
94+
</h1>
95+
<p className="text-sm text-muted-foreground">
96+
{t('auth.resetPassword.description')}
97+
</p>
98+
</div>
99+
<Form {...form}>
100+
<form
101+
onSubmit={form.handleSubmit(submit)}
102+
className="animate-in flex-1 flex flex-col w-full justify-center gap-2 text-foreground"
103+
>
104+
<FormField
105+
control={form.control}
106+
name="password"
107+
render={({ field }) => (
108+
<FormItem>
109+
<FormLabel>
110+
{t(
111+
'auth.resetPassword.newPassword'
112+
)}
113+
</FormLabel>
114+
<FormControl>
115+
<div className="rounded-md px-4 py-2 w-full bg-inherit border mb-6 gap-4 flex items-center justify-between">
116+
<Input
117+
className="border-none w-full bg-transparent focus:outline-none"
118+
type={
119+
showPassword
120+
? 'text'
121+
: 'password'
122+
}
123+
{...field}
124+
/>
125+
<button
126+
type="button"
127+
onClick={() =>
128+
setShowPassword(
129+
!showPassword
130+
)
131+
}
132+
>
133+
{!showPassword ? (
134+
<EyeIcon />
135+
) : (
136+
<EyeOffIcon />
137+
)}
138+
</button>
139+
</div>
140+
<p className="text-xs text-muted-foreground">
141+
{t('auth.resetPassword.passwordHelp')}
142+
</p>
143+
</FormControl>
144+
<FormMessage />
145+
</FormItem>
146+
)}
147+
/>
148+
<Button
149+
disabled={form.formState.isSubmitting}
150+
type="submit"
151+
>
152+
{form.formState.isSubmitting
153+
? t('auth.resetPassword.loading')
154+
: t('auth.resetPassword.button')}
155+
</Button>
156+
</form>
157+
</Form>
158+
{searchParams.error && (
159+
<Alert variant="destructive">
160+
<AlertTitle>Error!</AlertTitle>
161+
<AlertDescription>
162+
{searchParams.error}
163+
</AlertDescription>
164+
</Alert>
165+
)}
166+
167+
<Link
168+
href="/auth/login"
169+
className="text-center text-sm cursor-pointer text-primary"
170+
>
171+
{t('auth.resetPassword.back')}
172+
</Link>
173+
</div>
174+
</div>
175+
</>
176+
)
177+
}

0 commit comments

Comments
 (0)