From 51668bae9dddaf28bec19ec0a230f21f2d41d3fe Mon Sep 17 00:00:00 2001 From: supalerk-ar66 Date: Wed, 14 Jan 2026 16:47:29 +0700 Subject: [PATCH] Add: Auth protection & error notifications --- Frontend-Learner/.nuxt/tailwind/postcss.mjs | 2 +- Frontend-Learner/composables/useAuth.ts | 5 +++ .../composables/useFormValidation.ts | 18 ++++---- Frontend-Learner/error.vue | 2 +- Frontend-Learner/pages/auth/login.vue | 42 ++++++++++++------- Frontend-Learner/pages/auth/register.vue | 21 +++++----- 6 files changed, 53 insertions(+), 37 deletions(-) diff --git a/Frontend-Learner/.nuxt/tailwind/postcss.mjs b/Frontend-Learner/.nuxt/tailwind/postcss.mjs index df8a4410..5a000f50 100644 --- a/Frontend-Learner/.nuxt/tailwind/postcss.mjs +++ b/Frontend-Learner/.nuxt/tailwind/postcss.mjs @@ -1,4 +1,4 @@ -// generated by the @nuxtjs/tailwindcss module at 14/1/2569 15:13:15 +// generated by the @nuxtjs/tailwindcss module at 14/1/2569 16:44:22 import "@nuxtjs/tailwindcss/config-ctx" import configMerger from "@nuxtjs/tailwindcss/merger"; diff --git a/Frontend-Learner/composables/useAuth.ts b/Frontend-Learner/composables/useAuth.ts index 7f65956d..634ee3b4 100644 --- a/Frontend-Learner/composables/useAuth.ts +++ b/Frontend-Learner/composables/useAuth.ts @@ -77,6 +77,11 @@ export const useAuth = () => { } if (data.value) { + // Validation: Only allow STUDENT role to login + if (data.value.user.role.code !== 'STUDENT') { + return { success: false, error: 'Email ไม่ถูกต้อง' } + } + token.value = data.value.token refreshToken.value = data.value.refreshToken // Save refresh token diff --git a/Frontend-Learner/composables/useFormValidation.ts b/Frontend-Learner/composables/useFormValidation.ts index 94583d99..ae637bd1 100644 --- a/Frontend-Learner/composables/useFormValidation.ts +++ b/Frontend-Learner/composables/useFormValidation.ts @@ -20,29 +20,29 @@ export function useFormValidation() { return re.test(email) } - const validateField = (value: string, rules: ValidationRule, fieldName: string, formData?: Record): string | null => { + const validateField = (value: string, rules: ValidationRule, fieldName: string, formData?: Record, messages?: Record): string | null => { if (rules.required && !value.trim()) { - return `กรุณากรอก${fieldName}` + return messages?.required || `กรุณากรอก${fieldName}` } if (rules.minLength && value.length < rules.minLength) { - return `${fieldName}ต้องมีอย่างน้อย ${rules.minLength} ตัวอักษร` + return messages?.minLength || `${fieldName}ต้องมีอย่างน้อย ${rules.minLength} ตัวอักษร` } if (rules.maxLength && value.length > rules.maxLength) { - return `${fieldName}ต้องไม่เกิน ${rules.maxLength} ตัวอักษร` + return messages?.maxLength || `${fieldName}ต้องไม่เกิน ${rules.maxLength} ตัวอักษร` } if (rules.email && value && !validateEmail(value)) { - return 'รูปแบบอีเมลไม่ถูกต้อง' + return messages?.email || 'รูปแบบอีเมลไม่ถูกต้อง' } if (rules.pattern && value && !rules.pattern.test(value)) { - return `${fieldName}รูปแบบไม่ถูกต้อง` + return messages?.pattern || `${fieldName}รูปแบบไม่ถูกต้อง` } if (rules.match && formData && value !== formData[rules.match]) { - return 'รหัสผ่านไม่ตรงกัน' + return messages?.match || 'รหัสผ่านไม่ตรงกัน' } if (rules.custom) { @@ -54,13 +54,13 @@ export function useFormValidation() { const validate = ( formData: Record, - validationRules: Record + validationRules: Record }> ): boolean => { const newErrors: FieldErrors = {} let isValid = true for (const [fieldKey, config] of Object.entries(validationRules)) { - const error = validateField(formData[fieldKey] || '', config.rules, config.label, formData) + const error = validateField(formData[fieldKey] || '', config.rules, config.label, formData, config.messages) if (error) { newErrors[fieldKey] = error isValid = false diff --git a/Frontend-Learner/error.vue b/Frontend-Learner/error.vue index dc84e80e..4d957a3b 100644 --- a/Frontend-Learner/error.vue +++ b/Frontend-Learner/error.vue @@ -11,7 +11,7 @@ useHead({ }) const handleError = () => { - clearError({ redirect: '/home' }) + clearError({ redirect: '/' }) } diff --git a/Frontend-Learner/pages/auth/login.vue b/Frontend-Learner/pages/auth/login.vue index 32739d56..dbac8b6f 100644 --- a/Frontend-Learner/pages/auth/login.vue +++ b/Frontend-Learner/pages/auth/login.vue @@ -29,8 +29,22 @@ const loginForm = reactive({ // Validation rules definition const loginRules = { - email: { rules: { required: true, email: true }, label: 'อีเมล' }, - password: { rules: { required: true, minLength: 6 }, label: 'รหัสผ่าน' } + email: { + rules: { required: true, email: true }, + label: 'อีเมล', + messages: { + required: 'กรุณากรอกอีเมลของคุณ', + email: 'กรุณากรอกอีเมลให้ถูกต้อง (you@example.com)' + } + }, + password: { + rules: { required: true, minLength: 8 }, + label: 'รหัสผ่าน', + messages: { + required: 'กรุณากรอกรหัสผ่าน', + minLength: 'กรุณากรอกรหัสผ่าน (อย่างน้อย 8 ตัวอักษร)' + } + } } /** @@ -50,19 +64,17 @@ const handleLogin = async () => { isLoading.value = false if (result.success) { - // Redirect based on user role - const role = user.value?.role?.code - - if (role === 'ADMIN') { - router.push('/admin') - } else if (role === 'INSTRUCTOR') { - router.push('/instructor') - } else { - router.push('/dashboard') - } + router.push('/dashboard') } else { - // Show error from API or fallback - alert(result.error || 'อีเมลหรือรหัสผ่านไม่ถูกต้อง') + // Show error on specific fields + if (result.error === 'ไม่พบอีเมลในระบบ') { + errors.value.email = 'กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง' + errors.value.password = 'กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง' + } else if (result.error === 'Email ไม่ถูกต้อง') { + errors.value.email = result.error + } else { + errors.value.password = 'กรอกรหัสผ่านไม่ถูกต้อง' + } } } @@ -84,7 +96,7 @@ const handleLogin = async () => { -
+ { + + { @update:model-value="clearFieldError('email')" /> - - -