Skip to content

Commit d0aea9a

Browse files
refactor(auth): prepare user profile auth migration (#356)
1 parent 87000ff commit d0aea9a

39 files changed

Lines changed: 1748 additions & 980 deletions

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
8484

8585
### Set to 1 to enable verbose logging
8686
# NEXT_PUBLIC_VERBOSE=0
87+
88+
### Set to 1 to pause sign-ups and sign-ins during auth migration.
89+
# NEXT_PUBLIC_AUTH_MIGRATION_IN_PROGRESS=0

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spec/openapi.dashboard-api.yaml linguist-generated=true
2+
src/core/shared/contracts/dashboard-api.types.ts linguist-generated=true
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
'use client'
2+
3+
import { zodResolver } from '@hookform/resolvers/zod'
4+
import { useHookFormAction } from '@next-safe-action/adapter-react-hook-form/hooks'
5+
import { useSearchParams } from 'next/navigation'
6+
import { useEffect, useState } from 'react'
7+
import { AUTH_URLS } from '@/configs/urls'
8+
import {
9+
getTimeoutMsFromUserMessage,
10+
USER_MESSAGES,
11+
} from '@/configs/user-messages'
12+
import { forgotPasswordAction } from '@/core/server/actions/auth-actions'
13+
import { forgotPasswordSchema } from '@/core/server/functions/auth/auth.types'
14+
import { AuthFormMessage, type AuthMessage } from '@/features/auth/form-message'
15+
import { Button } from '@/ui/primitives/button'
16+
import { Input } from '@/ui/primitives/input'
17+
import { Label } from '@/ui/primitives/label'
18+
19+
export default function ForgotPassword() {
20+
const searchParams = useSearchParams()
21+
const [message, setMessage] = useState<AuthMessage | undefined>()
22+
23+
const {
24+
form,
25+
handleSubmitWithAction,
26+
action: { isExecuting },
27+
} = useHookFormAction(
28+
forgotPasswordAction,
29+
zodResolver(forgotPasswordSchema),
30+
{
31+
actionProps: {
32+
onSuccess: () => {
33+
form.reset()
34+
setMessage({ success: USER_MESSAGES.passwordReset.message })
35+
},
36+
onError: ({ error }) => {
37+
if (error.serverError) {
38+
setMessage({ error: error.serverError })
39+
}
40+
},
41+
},
42+
}
43+
)
44+
45+
useEffect(() => {
46+
const email = searchParams.get('email')
47+
if (email) {
48+
form.setValue('email', email)
49+
}
50+
}, [searchParams, form])
51+
52+
useEffect(() => {
53+
if (!message) return
54+
55+
const messageText =
56+
'success' in message
57+
? message.success
58+
: 'error' in message
59+
? message.error
60+
: undefined
61+
62+
if (!messageText) return
63+
64+
const timer = setTimeout(
65+
() => setMessage(undefined),
66+
getTimeoutMsFromUserMessage(messageText) || 5000
67+
)
68+
return () => clearTimeout(timer)
69+
}, [message])
70+
71+
const handleBackToSignIn = () => {
72+
const email = form.getValues('email')
73+
const searchParams = email ? `?email=${encodeURIComponent(email)}` : ''
74+
window.location.href = `${AUTH_URLS.SIGN_IN}${searchParams}`
75+
}
76+
77+
return (
78+
<div className="flex w-full flex-col">
79+
<h1>Reset Password</h1>
80+
<p className="text-fg-secondary leading-6">
81+
Remember your password?{' '}
82+
<button
83+
type="button"
84+
onClick={handleBackToSignIn}
85+
className="text-fg underline"
86+
>
87+
Sign in
88+
</button>
89+
.
90+
</p>
91+
92+
<form
93+
onSubmit={handleSubmitWithAction}
94+
className="mt-5 flex flex-col gap-2"
95+
>
96+
<Label htmlFor="email">E-Mail</Label>
97+
<Input
98+
{...form.register('email')}
99+
id="email"
100+
name="email"
101+
type="email"
102+
placeholder="you@example.com"
103+
required
104+
/>
105+
<Button type="submit" loading={isExecuting ? 'Sending...' : undefined}>
106+
Reset Password
107+
</Button>
108+
</form>
109+
110+
{message && <AuthFormMessage className="mt-4" message={message} />}
111+
</div>
112+
)
113+
}
Lines changed: 3 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,5 @@
1-
'use client'
1+
import ForgotPassword from './forgot-password-form'
22

3-
import { zodResolver } from '@hookform/resolvers/zod'
4-
import { useHookFormAction } from '@next-safe-action/adapter-react-hook-form/hooks'
5-
import { useSearchParams } from 'next/navigation'
6-
import { useEffect, useState } from 'react'
7-
import { AUTH_URLS } from '@/configs/urls'
8-
import {
9-
getTimeoutMsFromUserMessage,
10-
USER_MESSAGES,
11-
} from '@/configs/user-messages'
12-
import { forgotPasswordAction } from '@/core/server/actions/auth-actions'
13-
import { forgotPasswordSchema } from '@/core/server/functions/auth/auth.types'
14-
import { AuthFormMessage, type AuthMessage } from '@/features/auth/form-message'
15-
import { Button } from '@/ui/primitives/button'
16-
import { Input } from '@/ui/primitives/input'
17-
import { Label } from '@/ui/primitives/label'
18-
19-
export default function ForgotPassword() {
20-
const searchParams = useSearchParams()
21-
const [message, setMessage] = useState<AuthMessage | undefined>()
22-
23-
const {
24-
form,
25-
handleSubmitWithAction,
26-
action: { isExecuting },
27-
} = useHookFormAction(
28-
forgotPasswordAction,
29-
zodResolver(forgotPasswordSchema),
30-
{
31-
actionProps: {
32-
onSuccess: () => {
33-
form.reset()
34-
setMessage({ success: USER_MESSAGES.passwordReset.message })
35-
},
36-
onError: ({ error }) => {
37-
if (error.serverError) {
38-
setMessage({ error: error.serverError })
39-
}
40-
},
41-
},
42-
}
43-
)
44-
45-
useEffect(() => {
46-
const email = searchParams.get('email')
47-
if (email) {
48-
form.setValue('email', email)
49-
}
50-
}, [searchParams, form])
51-
52-
useEffect(() => {
53-
if (
54-
message &&
55-
(('success' in message && message.success) ||
56-
('error' in message && message.error))
57-
) {
58-
const timer = setTimeout(
59-
() => setMessage(undefined),
60-
getTimeoutMsFromUserMessage(
61-
'success' in message
62-
? message.success!
63-
: 'error' in message
64-
? message.error!
65-
: ''
66-
) || 5000
67-
)
68-
return () => clearTimeout(timer)
69-
}
70-
}, [message])
71-
72-
const handleBackToSignIn = () => {
73-
const email = form.getValues('email')
74-
const searchParams = email ? `?email=${encodeURIComponent(email)}` : ''
75-
window.location.href = `${AUTH_URLS.SIGN_IN}${searchParams}`
76-
}
77-
78-
return (
79-
<div className="flex w-full flex-col">
80-
<h1>Reset Password</h1>
81-
<p className="text-fg-secondary leading-6">
82-
Remember your password?{' '}
83-
<button
84-
type="button"
85-
onClick={handleBackToSignIn}
86-
className="text-fg underline"
87-
>
88-
Sign in
89-
</button>
90-
.
91-
</p>
92-
93-
<form
94-
onSubmit={handleSubmitWithAction}
95-
className="mt-5 flex flex-col gap-2"
96-
>
97-
<Label htmlFor="email">E-Mail</Label>
98-
<Input
99-
{...form.register('email')}
100-
id="email"
101-
name="email"
102-
type="email"
103-
placeholder="you@example.com"
104-
required
105-
/>
106-
<Button type="submit" loading={isExecuting ? 'Sending...' : undefined}>
107-
Reset Password
108-
</Button>
109-
</form>
110-
111-
{message && <AuthFormMessage className="mt-4" message={message} />}
112-
</div>
113-
)
3+
export default function Page() {
4+
return <ForgotPassword />
1145
}

0 commit comments

Comments
 (0)