feat: Scaffold new Nuxt.js application with initial pages, layouts, composables, and middleware.
This commit is contained in:
parent
ab3124628c
commit
9bfb852ad0
8 changed files with 113 additions and 48 deletions
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
// Interface สำหรับข้อมูลผู้ใช้งาน (User)
|
||||
interface User {
|
||||
id: number
|
||||
username: string
|
||||
|
|
@ -6,7 +7,7 @@ interface User {
|
|||
created_at?: string
|
||||
updated_at?: string
|
||||
role: {
|
||||
code: string
|
||||
code: string // เช่น 'STUDENT', 'INSTRUCTOR', 'ADMIN'
|
||||
name: { th: string; en: string }
|
||||
}
|
||||
profile?: {
|
||||
|
|
@ -18,6 +19,7 @@ interface User {
|
|||
}
|
||||
}
|
||||
|
||||
// Interface สำหรับข้อมูลตอบกลับตอน Login
|
||||
interface loginResponse {
|
||||
token: string
|
||||
refreshToken: string
|
||||
|
|
@ -25,6 +27,7 @@ interface loginResponse {
|
|||
profile: User['profile']
|
||||
}
|
||||
|
||||
// Interface สำหรับข้อมูลที่ใช้ลงทะเบียน
|
||||
interface RegisterPayload {
|
||||
username: string
|
||||
email: string
|
||||
|
|
@ -35,32 +38,44 @@ interface RegisterPayload {
|
|||
phone: string
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Composable: useAuth
|
||||
// หน้าที่: จัดการระบบ Authentication และ Authorization
|
||||
// - จัดการ Login/Logout/Register
|
||||
// - จัดการ Token (Access Token & Refresh Token)
|
||||
// - เก็บ State ของผู้ใช้ปัจจุบัน (User State)
|
||||
// ==========================================
|
||||
export const useAuth = () => {
|
||||
const config = useRuntimeConfig()
|
||||
const API_BASE_URL = config.public.apiBase as string
|
||||
|
||||
// Cookie สำหรับเก็บ Access Token (หมดอายุ 1 วัน)
|
||||
const token = useCookie('auth_token', {
|
||||
maxAge: 60 * 60 * 24, // 1 day
|
||||
sameSite: 'lax',
|
||||
secure: false // Set to true in production with HTTPS
|
||||
secure: false // ควรเป็น true ใน production (HTTPS)
|
||||
})
|
||||
|
||||
// Cookie สำหรับเก็บข้อมูล User (หมดอายุ 7 วัน)
|
||||
const user = useCookie<User | null>('auth_user_data', {
|
||||
maxAge: 60 * 60 * 24 * 7, // 1 week
|
||||
sameSite: 'lax',
|
||||
secure: false
|
||||
})
|
||||
|
||||
// Computed property เช็คว่า Login อยู่หรือไม่
|
||||
const isAuthenticated = computed(() => !!token.value)
|
||||
|
||||
// Refresh Token Logic
|
||||
// Cookie สำหรับเก็บ Refresh Token (หมดอายุ 7 วัน)
|
||||
const refreshToken = useCookie('auth_refresh_token', {
|
||||
maxAge: 60 * 60 * 24 * 7, // 7 days (matching API likely)
|
||||
maxAge: 60 * 60 * 24 * 7, // 7 days (ตรงกับ API)
|
||||
sameSite: 'lax',
|
||||
secure: false
|
||||
})
|
||||
|
||||
|
||||
|
||||
// ฟังก์ชันเข้าสู่ระบบ (Login)
|
||||
const login = async (credentials: { email: string; password: string }) => {
|
||||
try {
|
||||
const data = await $fetch<loginResponse>(`${API_BASE_URL}/auth/login`, {
|
||||
|
|
@ -69,15 +84,15 @@ export const useAuth = () => {
|
|||
})
|
||||
|
||||
if (data) {
|
||||
// Validation: Only allow STUDENT role to login
|
||||
// Validation: อนุญาตเฉพาะ Role 'STUDENT' เท่านั้น
|
||||
if (data.user.role.code !== 'STUDENT') {
|
||||
return { success: false, error: 'Email ไม่ถูกต้อง' }
|
||||
}
|
||||
|
||||
token.value = data.token
|
||||
refreshToken.value = data.refreshToken // Save refresh token
|
||||
refreshToken.value = data.refreshToken // บันทึก Refresh Token
|
||||
|
||||
// The API returns the profile nested inside the user object
|
||||
// API ส่งข้อมูล profile มาใน user object
|
||||
user.value = data.user
|
||||
|
||||
return { success: true }
|
||||
|
|
@ -92,6 +107,7 @@ export const useAuth = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// ฟังก์ชันลงทะเบียน (Register)
|
||||
const register = async (payload: RegisterPayload) => {
|
||||
try {
|
||||
const data = await $fetch(`${API_BASE_URL}/auth/register-learner`, {
|
||||
|
|
@ -110,6 +126,7 @@ export const useAuth = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// ฟังก์ชันดึงข้อมูลโปรไฟล์ผู้ใช้ล่าสุด
|
||||
const fetchUserProfile = async () => {
|
||||
if (!token.value) return
|
||||
|
||||
|
|
@ -124,11 +141,12 @@ export const useAuth = () => {
|
|||
user.value = data
|
||||
}
|
||||
} catch (error: any) {
|
||||
// กรณี Token หมดอายุ (401)
|
||||
if (error.statusCode === 401) {
|
||||
// Try to refresh token
|
||||
// พยายามขอ Token ใหม่ (Refresh Token)
|
||||
const refreshed = await refreshAccessToken()
|
||||
if (refreshed) {
|
||||
// Retry fetch with new token
|
||||
// ถ้าได้ Token ใหม่ ให้ลองดึงข้อมูลอีกครั้ง
|
||||
try {
|
||||
const retryData = await $fetch<User>(`${API_BASE_URL}/user/me`, {
|
||||
headers: {
|
||||
|
|
@ -144,6 +162,7 @@ export const useAuth = () => {
|
|||
console.error('Failed to fetch user profile after refresh:', retryErr)
|
||||
}
|
||||
} else {
|
||||
// ถ้า Refresh ไม่ผ่าน ให้ Logout
|
||||
logout()
|
||||
}
|
||||
} else {
|
||||
|
|
@ -152,6 +171,7 @@ export const useAuth = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// ฟังก์ชันอัปเดตข้อมูลโปรไฟล์
|
||||
const updateUserProfile = async (payload: {
|
||||
first_name: string
|
||||
last_name: string
|
||||
|
|
@ -169,7 +189,7 @@ export const useAuth = () => {
|
|||
body: payload
|
||||
})
|
||||
|
||||
// If successful, refresh the local user data
|
||||
// หากสำเร็จ ให้ดึงข้อมูลโปรไฟล์ล่าสุดมาอัปเดตใน State
|
||||
await fetchUserProfile()
|
||||
|
||||
return { success: true }
|
||||
|
|
@ -223,6 +243,7 @@ export const useAuth = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// ฟังก์ชันขอ Access Token ใหม่ด้วย Refresh Token
|
||||
const refreshAccessToken = async () => {
|
||||
if (!refreshToken.value) return false
|
||||
|
||||
|
|
@ -238,16 +259,17 @@ export const useAuth = () => {
|
|||
return true
|
||||
}
|
||||
} catch (err) {
|
||||
// Refresh failed, force logout
|
||||
// Refresh failed (เช่น Refresh Token หมดอายุ) ให้ Force Logout
|
||||
logout()
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ฟังก์ชันออกจากระบบ (Logout)
|
||||
const logout = () => {
|
||||
token.value = null
|
||||
refreshToken.value = null // Clear refresh token
|
||||
refreshToken.value = null // ลบ Refresh Token
|
||||
user.value = null
|
||||
const router = useRouter()
|
||||
router.push('/auth/login')
|
||||
|
|
@ -260,6 +282,7 @@ export const useAuth = () => {
|
|||
currentUser: computed(() => {
|
||||
if (!user.value) return null
|
||||
|
||||
// Helper ในการดึงข้อมูล user ที่อาจซ้อนกันอยู่หลายชั้น
|
||||
const prefix = user.value.profile?.prefix?.th || ''
|
||||
const firstName = user.value.profile?.first_name || user.value.username
|
||||
const lastName = user.value.profile?.last_name || ''
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue