Skip to content

Commit b2fc87b

Browse files
committed
fix: update login form error handling and improve user feedback
1 parent 021f5b2 commit b2fc87b

File tree

2 files changed

+89
-9
lines changed

2 files changed

+89
-9
lines changed

services/frontend/src/i18n/locales/en/login.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export default {
33
form: {
44
email: {
55
label: 'Email address',
6-
placeholder: 'name@example.com',
6+
placeholder: 'Enter your email address',
77
},
88
password: {
99
label: 'Password',
@@ -19,6 +19,11 @@ export default {
1919
noAccount: 'Not a member?',
2020
createAccount: 'Create an account',
2121
errors: {
22+
title: 'Error',
2223
invalidCredentials: 'Invalid email or password',
24+
networkError: 'Unable to connect to server. Please check your connection and try again.',
25+
serverError: 'Server error occurred. Please try again later.',
26+
unknownError: 'An unexpected error occurred. Please try again.',
27+
timeout: 'Request timed out. Please try again.',
2328
},
2429
}

services/frontend/src/views/Login.vue

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { toTypedSchema } from '@vee-validate/zod'
44
import * as z from 'zod'
55
import { ref } from 'vue'
66
import { useRouter } from 'vue-router'
7-
import { Mail, Lock } from 'lucide-vue-next'
7+
import { Mail, Lock, AlertTriangle } from 'lucide-vue-next'
88
import { useI18n } from 'vue-i18n'
99
1010
import {
@@ -13,6 +13,12 @@ import {
1313
CardFooter,
1414
} from '@/components/ui/card'
1515
16+
import {
17+
Alert,
18+
AlertDescription,
19+
AlertTitle,
20+
} from '@/components/ui/alert'
21+
1622
import { Button } from '@/components/ui/button'
1723
import {
1824
FormControl,
@@ -25,6 +31,7 @@ import { Input } from '@/components/ui/input'
2531
2632
const router = useRouter()
2733
const isLoading = ref(false)
34+
const errorMessage = ref('')
2835
const { t } = useI18n() // Initialize i18n composable
2936
3037
// Define validation schema using Zod
@@ -50,16 +57,73 @@ const form = useForm({
5057
},
5158
})
5259
53-
const onSubmit = form.handleSubmit((values) => {
54-
// Mock login functionality
60+
// Clear error when user starts typing
61+
const clearError = () => {
62+
errorMessage.value = ''
63+
}
64+
65+
// Handle different types of errors
66+
const handleError = (error: any) => {
67+
if (error.name === 'TypeError' && error.message.includes('fetch')) {
68+
// Network error - backend is down
69+
errorMessage.value = t('login.errors.networkError')
70+
} else if (error.status === 401) {
71+
// Unauthorized - invalid credentials
72+
errorMessage.value = t('login.errors.invalidCredentials')
73+
} else if (error.status >= 500) {
74+
// Server error
75+
errorMessage.value = t('login.errors.serverError')
76+
} else if (error.name === 'AbortError') {
77+
// Request timeout
78+
errorMessage.value = t('login.errors.timeout')
79+
} else {
80+
// Unknown error
81+
errorMessage.value = t('login.errors.unknownError')
82+
}
83+
}
84+
85+
const onSubmit = form.handleSubmit(async (values) => {
5586
isLoading.value = true
87+
errorMessage.value = ''
88+
89+
try {
90+
// Create AbortController for timeout handling
91+
const controller = new AbortController()
92+
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
93+
94+
const response = await fetch(`${apiUrl}/auth/login`, {
95+
method: 'POST',
96+
headers: {
97+
'Content-Type': 'application/json',
98+
},
99+
body: JSON.stringify({
100+
email: values.email,
101+
password: values.password,
102+
}),
103+
signal: controller.signal,
104+
})
105+
106+
clearTimeout(timeoutId)
107+
108+
if (!response.ok) {
109+
const errorData = await response.json().catch(() => ({}))
110+
const error = new Error(errorData.message || 'Login failed') as Error & { status: number }
111+
error.status = response.status
112+
throw error
113+
}
56114
57-
// Simulate API call
58-
setTimeout(() => {
59-
console.log('Login submitted!', values)
115+
const data = await response.json()
116+
console.log('Login successful!', data)
117+
118+
// Handle successful login - redirect to dashboard or home
119+
router.push('/dashboard')
120+
121+
} catch (error) {
122+
console.error('Login error:', error)
123+
handleError(error)
124+
} finally {
60125
isLoading.value = false
61-
// In a real app, you would handle authentication here
62-
}, 1000)
126+
}
63127
})
64128
65129
import { getEnv, getAllEnv } from '@/utils/env';
@@ -87,6 +151,15 @@ const navigateToRegister = () => {
87151
</div>
88152

89153
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
154+
<!-- Error Alert -->
155+
<Alert v-if="errorMessage" variant="destructive" class="mb-6">
156+
<AlertTriangle class="h-4 w-4" />
157+
<AlertTitle>{{ $t('login.errors.title') }}</AlertTitle>
158+
<AlertDescription>
159+
{{ errorMessage }}
160+
</AlertDescription>
161+
</Alert>
162+
90163
<Card>
91164
<CardContent class="pt-6">
92165
<form @submit="onSubmit" class="space-y-6">
@@ -102,6 +175,7 @@ const navigateToRegister = () => {
102175
v-bind="componentField"
103176
class="pl-10"
104177
autocomplete="email"
178+
@input="clearError"
105179
/>
106180
</div>
107181
</FormControl>
@@ -128,6 +202,7 @@ const navigateToRegister = () => {
128202
v-bind="componentField"
129203
class="pl-10"
130204
autocomplete="current-password"
205+
@input="clearError"
131206
/>
132207
</div>
133208
</FormControl>

0 commit comments

Comments
 (0)