Add: Auth protection & error notifications
This commit is contained in:
parent
5d508c4731
commit
51668bae9d
6 changed files with 53 additions and 37 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 14/1/2569 15:13:15
|
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 14/1/2569 16:44:22
|
||||||
import "@nuxtjs/tailwindcss/config-ctx"
|
import "@nuxtjs/tailwindcss/config-ctx"
|
||||||
import configMerger from "@nuxtjs/tailwindcss/merger";
|
import configMerger from "@nuxtjs/tailwindcss/merger";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,11 @@ export const useAuth = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.value) {
|
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
|
token.value = data.value.token
|
||||||
refreshToken.value = data.value.refreshToken // Save refresh token
|
refreshToken.value = data.value.refreshToken // Save refresh token
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,29 +20,29 @@ export function useFormValidation() {
|
||||||
return re.test(email)
|
return re.test(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateField = (value: string, rules: ValidationRule, fieldName: string, formData?: Record<string, string>): string | null => {
|
const validateField = (value: string, rules: ValidationRule, fieldName: string, formData?: Record<string, string>, messages?: Record<string, string>): string | null => {
|
||||||
if (rules.required && !value.trim()) {
|
if (rules.required && !value.trim()) {
|
||||||
return `กรุณากรอก${fieldName}`
|
return messages?.required || `กรุณากรอก${fieldName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.minLength && value.length < rules.minLength) {
|
if (rules.minLength && value.length < rules.minLength) {
|
||||||
return `${fieldName}ต้องมีอย่างน้อย ${rules.minLength} ตัวอักษร`
|
return messages?.minLength || `${fieldName}ต้องมีอย่างน้อย ${rules.minLength} ตัวอักษร`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.maxLength && value.length > rules.maxLength) {
|
if (rules.maxLength && value.length > rules.maxLength) {
|
||||||
return `${fieldName}ต้องไม่เกิน ${rules.maxLength} ตัวอักษร`
|
return messages?.maxLength || `${fieldName}ต้องไม่เกิน ${rules.maxLength} ตัวอักษร`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.email && value && !validateEmail(value)) {
|
if (rules.email && value && !validateEmail(value)) {
|
||||||
return 'รูปแบบอีเมลไม่ถูกต้อง'
|
return messages?.email || 'รูปแบบอีเมลไม่ถูกต้อง'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.pattern && value && !rules.pattern.test(value)) {
|
if (rules.pattern && value && !rules.pattern.test(value)) {
|
||||||
return `${fieldName}รูปแบบไม่ถูกต้อง`
|
return messages?.pattern || `${fieldName}รูปแบบไม่ถูกต้อง`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.match && formData && value !== formData[rules.match]) {
|
if (rules.match && formData && value !== formData[rules.match]) {
|
||||||
return 'รหัสผ่านไม่ตรงกัน'
|
return messages?.match || 'รหัสผ่านไม่ตรงกัน'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.custom) {
|
if (rules.custom) {
|
||||||
|
|
@ -54,13 +54,13 @@ export function useFormValidation() {
|
||||||
|
|
||||||
const validate = (
|
const validate = (
|
||||||
formData: Record<string, string>,
|
formData: Record<string, string>,
|
||||||
validationRules: Record<string, { rules: ValidationRule; label: string }>
|
validationRules: Record<string, { rules: ValidationRule; label: string; messages?: Record<string, string> }>
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const newErrors: FieldErrors = {}
|
const newErrors: FieldErrors = {}
|
||||||
let isValid = true
|
let isValid = true
|
||||||
|
|
||||||
for (const [fieldKey, config] of Object.entries(validationRules)) {
|
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) {
|
if (error) {
|
||||||
newErrors[fieldKey] = error
|
newErrors[fieldKey] = error
|
||||||
isValid = false
|
isValid = false
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ useHead({
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleError = () => {
|
const handleError = () => {
|
||||||
clearError({ redirect: '/home' })
|
clearError({ redirect: '/' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,22 @@ const loginForm = reactive({
|
||||||
|
|
||||||
// Validation rules definition
|
// Validation rules definition
|
||||||
const loginRules = {
|
const loginRules = {
|
||||||
email: { rules: { required: true, email: true }, label: 'อีเมล' },
|
email: {
|
||||||
password: { rules: { required: true, minLength: 6 }, label: 'รหัสผ่าน' }
|
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
|
isLoading.value = false
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Redirect based on user role
|
router.push('/dashboard')
|
||||||
const role = user.value?.role?.code
|
|
||||||
|
|
||||||
if (role === 'ADMIN') {
|
|
||||||
router.push('/admin')
|
|
||||||
} else if (role === 'INSTRUCTOR') {
|
|
||||||
router.push('/instructor')
|
|
||||||
} else {
|
|
||||||
router.push('/dashboard')
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Show error from API or fallback
|
// Show error on specific fields
|
||||||
alert(result.error || 'อีเมลหรือรหัสผ่านไม่ถูกต้อง')
|
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 = 'กรอกรหัสผ่านไม่ถูกต้อง'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -84,7 +96,7 @@ const handleLogin = async () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Login Form -->
|
<!-- Login Form -->
|
||||||
<form @submit.prevent="handleLogin">
|
<form @submit.prevent="handleLogin" novalidate>
|
||||||
<!-- Email Input -->
|
<!-- Email Input -->
|
||||||
<FormInput
|
<FormInput
|
||||||
v-model="loginForm.email"
|
v-model="loginForm.email"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,16 @@ const handleRegister = async () => {
|
||||||
|
|
||||||
<!-- REGISTER FORM -->
|
<!-- REGISTER FORM -->
|
||||||
<form @submit.prevent="handleRegister">
|
<form @submit.prevent="handleRegister">
|
||||||
|
<!-- Username -->
|
||||||
|
<FormInput
|
||||||
|
v-model="registerForm.username"
|
||||||
|
label="ชื่อผู้ใช้"
|
||||||
|
placeholder="username"
|
||||||
|
:error="errors.username"
|
||||||
|
required
|
||||||
|
class="dark-form-input"
|
||||||
|
@update:model-value="clearFieldError('username')"
|
||||||
|
/>
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<FormInput
|
<FormInput
|
||||||
v-model="registerForm.email"
|
v-model="registerForm.email"
|
||||||
|
|
@ -116,17 +126,6 @@ const handleRegister = async () => {
|
||||||
@update:model-value="clearFieldError('email')"
|
@update:model-value="clearFieldError('email')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Username -->
|
|
||||||
<FormInput
|
|
||||||
v-model="registerForm.username"
|
|
||||||
label="ชื่อผู้ใช้"
|
|
||||||
placeholder="username"
|
|
||||||
:error="errors.username"
|
|
||||||
required
|
|
||||||
class="dark-form-input"
|
|
||||||
@update:model-value="clearFieldError('username')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Password Fields -->
|
<!-- Password Fields -->
|
||||||
<FormInput
|
<FormInput
|
||||||
v-model="registerForm.password"
|
v-model="registerForm.password"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue