mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-10 23:48:09 -05:00
feat(auth): added better error handling for login/signup flow
This commit is contained in:
@@ -16,15 +16,16 @@ import {
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { client } from '@/lib/auth-client'
|
||||
import { useNotificationStore } from '@/stores/notifications/store'
|
||||
import { NotificationList } from '@/app/w/components/notifications/notifications'
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const { addNotification } = useNotificationStore()
|
||||
|
||||
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setIsLoading(true)
|
||||
|
||||
const formData = new FormData(e.currentTarget)
|
||||
@@ -34,8 +35,27 @@ export default function LoginPage() {
|
||||
try {
|
||||
await client.signIn.email({ email, password })
|
||||
router.push('/w/1')
|
||||
} catch (err) {
|
||||
setError('Invalid email or password')
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Invalid email or password'
|
||||
|
||||
if (err.message?.includes('not verified')) {
|
||||
errorMessage =
|
||||
'Please verify your email before signing in. Check your inbox for the verification link.'
|
||||
} else if (err.message?.includes('not found')) {
|
||||
errorMessage = 'No account found with this email. Please sign up first.'
|
||||
} else if (err.message?.includes('invalid password')) {
|
||||
errorMessage = 'Invalid password. Please try again or use the forgot password link.'
|
||||
} else if (err.message?.includes('too many attempts')) {
|
||||
errorMessage = 'Too many login attempts. Please try again later or reset your password.'
|
||||
} else if (err.message?.includes('account locked')) {
|
||||
errorMessage = 'Your account has been locked for security. Please reset your password.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many requests. Please wait a moment before trying again.'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
@@ -44,21 +64,44 @@ export default function LoginPage() {
|
||||
async function signInWithGithub() {
|
||||
try {
|
||||
await client.signIn.social({ provider: 'github' })
|
||||
} catch (err) {
|
||||
setError('Failed to sign in with GitHub')
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign in with GitHub'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage =
|
||||
'An account with this email already exists. Please sign in with email instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'GitHub sign in was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
}
|
||||
}
|
||||
|
||||
async function signInWithGoogle() {
|
||||
try {
|
||||
await client.signIn.social({ provider: 'google' })
|
||||
} catch (err) {
|
||||
setError('Failed to sign in with Google')
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign in with Google'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage =
|
||||
'An account with this email already exists. Please sign in with email instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'Google sign in was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gray-50">
|
||||
<NotificationList />
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<h1 className="text-2xl font-bold text-center mb-8">Sim Studio</h1>
|
||||
<Card className="w-full">
|
||||
@@ -102,7 +145,6 @@ export default function LoginPage() {
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input id="password" name="password" type="password" required />
|
||||
</div>
|
||||
{error && <p className="text-sm text-red-500">{error}</p>}
|
||||
<Button type="submit" className="w-full" disabled={isLoading}>
|
||||
{isLoading ? 'Signing in...' : 'Sign in'}
|
||||
</Button>
|
||||
|
||||
@@ -37,13 +37,22 @@ export default function SignupPage() {
|
||||
await client.signUp.email({ email, password, name })
|
||||
router.push('/verify-request')
|
||||
} catch (err: any) {
|
||||
// Handle specific error messages
|
||||
let errorMessage = 'Something went wrong. Please try again.'
|
||||
let errorMessage = 'Failed to create account'
|
||||
|
||||
if (err.message?.includes('Password is too short')) {
|
||||
errorMessage = 'Password must be at least 8 characters long'
|
||||
} else if (err.message?.includes('existing email')) {
|
||||
errorMessage = 'An account with this email already exists'
|
||||
errorMessage = 'An account with this email already exists. Please sign in instead.'
|
||||
} else if (err.message?.includes('invalid email')) {
|
||||
errorMessage = 'Please enter a valid email address'
|
||||
} else if (err.message?.includes('password too long')) {
|
||||
errorMessage = 'Password must be less than 128 characters'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many signup attempts. Please try again later.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('invalid name')) {
|
||||
errorMessage = 'Please enter a valid name'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
@@ -55,16 +64,40 @@ export default function SignupPage() {
|
||||
async function signUpWithGithub() {
|
||||
try {
|
||||
await client.signIn.social({ provider: 'github' })
|
||||
} catch (err) {
|
||||
addNotification('error', 'Failed to sign up with GitHub', null)
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign up with GitHub'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage = 'An account with this email already exists. Please sign in instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'GitHub sign up was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many attempts. Please try again later.'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
}
|
||||
}
|
||||
|
||||
async function signUpWithGoogle() {
|
||||
try {
|
||||
await client.signIn.social({ provider: 'google' })
|
||||
} catch (err) {
|
||||
addNotification('error', 'Failed to sign up with Google', null)
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign up with Google'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage = 'An account with this email already exists. Please sign in instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'Google sign up was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many attempts. Please try again later.'
|
||||
}
|
||||
|
||||
addNotification('error', errorMessage, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
lib/auth.ts
13
lib/auth.ts
@@ -6,11 +6,6 @@ import { Resend } from 'resend'
|
||||
import { db } from '@/db'
|
||||
import * as schema from '@/db/schema'
|
||||
|
||||
type EmailHandler = {
|
||||
user: { email: string }
|
||||
url: string
|
||||
}
|
||||
|
||||
// If there is no resend key, it might be a local dev environment
|
||||
// In that case, we don't want to send emails and just log them
|
||||
const resend = process.env.RESEND_API_KEY
|
||||
@@ -35,8 +30,8 @@ export const auth = betterAuth({
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
requireEmailVerification: true,
|
||||
sendResetPassword: async ({ user, url }: EmailHandler) => {
|
||||
await resend.emails.send({
|
||||
sendResetPassword: async ({ user, url, token }, request) => {
|
||||
const result = await resend.emails.send({
|
||||
from: 'Sim Studio <team@simstudio.ai>',
|
||||
to: user.email,
|
||||
subject: 'Reset your password',
|
||||
@@ -47,6 +42,10 @@ export const auth = betterAuth({
|
||||
<p>If you didn't request this, you can safely ignore this email.</p>
|
||||
`,
|
||||
})
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Failed to send reset password email')
|
||||
}
|
||||
},
|
||||
},
|
||||
emailVerification: {
|
||||
|
||||
Reference in New Issue
Block a user