interface User { id: number username: string email: string created_at?: string updated_at?: string role: { code: string name: { th: string; en: string } } profile?: { prefix: { th: string; en: string } first_name: string last_name: string phone: string | null avatar_url: string | null } } interface loginResponse { token: string refreshToken: string user: User profile: User['profile'] } interface RegisterPayload { username: string email: string password: string first_name: string last_name: string prefix: { th: string; en: string } phone: string } export const useAuth = () => { const config = useRuntimeConfig() const API_BASE_URL = config.public.apiBase as string const token = useCookie('auth_token', { maxAge: 60 * 60 * 24, // 1 day sameSite: 'lax', secure: false // Set to true in production with HTTPS }) const user = useCookie('auth_user_data', { maxAge: 60 * 60 * 24 * 7, // 1 week sameSite: 'lax', secure: false }) const isAuthenticated = computed(() => !!token.value) // Refresh Token Logic const refreshToken = useCookie('auth_refresh_token', { maxAge: 60 * 60 * 24 * 7, // 7 days (matching API likely) sameSite: 'lax', secure: false }) const login = async (credentials: { email: string; password: string }) => { try { const data = await $fetch(`${API_BASE_URL}/auth/login`, { method: 'POST', body: credentials }) if (data) { // Validation: Only allow STUDENT role to login if (data.user.role.code !== 'STUDENT') { return { success: false, error: 'Email ไม่ถูกต้อง' } } token.value = data.token refreshToken.value = data.refreshToken // Save refresh token // The API returns the profile nested inside the user object user.value = data.user return { success: true } } return { success: false, error: 'No data returned' } } catch (err: any) { console.error('Login failed:', err) return { success: false, error: err.data?.message || err.message || 'เข้าสู่ระบบไม่สำเร็จ' } } } const register = async (payload: RegisterPayload) => { try { const data = await $fetch(`${API_BASE_URL}/auth/register-learner`, { method: 'POST', body: payload }) return { success: true, data } } catch (err: any) { console.error('Register failed:', err) return { success: false, error: err.data?.error?.message || err.data?.message || err.message || 'ลงทะเบียนไม่สำเร็จ' } } } const fetchUserProfile = async () => { if (!token.value) return try { const data = await $fetch(`${API_BASE_URL}/user/me`, { headers: { Authorization: `Bearer ${token.value}` } }) if (data) { user.value = data } } catch (error: any) { if (error.statusCode === 401) { // Try to refresh token const refreshed = await refreshAccessToken() if (refreshed) { // Retry fetch with new token try { const retryData = await $fetch(`${API_BASE_URL}/user/me`, { headers: { Authorization: `Bearer ${token.value}` } }) if (retryData) { user.value = retryData return } } catch (retryErr) { console.error('Failed to fetch user profile after refresh:', retryErr) } } else { logout() } } else { console.error('Failed to fetch user profile:', error) } } } const updateUserProfile = async (payload: { first_name: string last_name: string phone: string prefix: { th: string; en: string } }) => { if (!token.value) return try { await $fetch(`${API_BASE_URL}/user/me`, { method: 'PUT', headers: { Authorization: `Bearer ${token.value}` }, body: payload }) // If successful, refresh the local user data await fetchUserProfile() return { success: true } } catch (err: any) { console.error('Failed to update profile:', err) return { success: false, error: err.data?.message || err.message || 'บันทึกข้อมูลไม่สำเร็จ' } } } const requestPasswordReset = async (email: string) => { try { await $fetch(`${API_BASE_URL}/auth/reset-request`, { method: 'POST', body: { email } }) return { success: true } } catch (err: any) { return { success: false, error: err.data?.message || 'ส่งคำขอไม่สำเร็จ' } } } const confirmResetPassword = async (payload: { token: string; password: string }) => { try { await $fetch(`${API_BASE_URL}/auth/reset-password`, { method: 'POST', body: payload }) return { success: true } } catch (err: any) { return { success: false, error: err.data?.message || 'รีเซ็ตรหัสผ่านไม่สำเร็จ' } } } const changePassword = async (payload: { oldPassword: string, newPassword: string }) => { if (!token.value) return { success: false, error: 'ไม่พบ Token การใช้งาน' } try { await $fetch(`${API_BASE_URL}/user/change-password`, { method: 'POST', headers: { Authorization: `Bearer ${token.value}` }, body: payload }) return { success: true } } catch (err: any) { return { success: false, error: err.data?.message || 'เปลี่ยนรหัสผ่านไม่สำเร็จ' } } } const refreshAccessToken = async () => { if (!refreshToken.value) return false try { const data = await $fetch<{ token: string; refreshToken: string }>(`${API_BASE_URL}/auth/refresh`, { method: 'POST', body: { refreshToken: refreshToken.value } }) if (data) { token.value = data.token refreshToken.value = data.refreshToken return true } } catch (err) { // Refresh failed, force logout logout() return false } return false } const logout = () => { token.value = null refreshToken.value = null // Clear refresh token user.value = null const router = useRouter() router.push('/auth/login') } return { isAuthenticated, token, user, currentUser: computed(() => { if (!user.value) return null const prefix = user.value.profile?.prefix?.th || '' const firstName = user.value.profile?.first_name || user.value.username const lastName = user.value.profile?.last_name || '' return { prefix: user.value.profile?.prefix || { th: '', en: '' }, firstName, lastName, email: user.value.email, phone: user.value.profile?.phone || '', photoURL: user.value.profile?.avatar_url || '', role: user.value.role, createdAt: user.value.created_at || new Date().toISOString() } }), login, register, fetchUserProfile, updateUserProfile, requestPasswordReset, confirmResetPassword, changePassword, refreshAccessToken, logout } }