Add:api-login
This commit is contained in:
parent
a6cddc6318
commit
c411f2a8a4
20 changed files with 434 additions and 185 deletions
|
|
@ -1,37 +1,239 @@
|
|||
// Shared global state for current user
|
||||
const currentUser = ref({
|
||||
prefix: 'นาย',
|
||||
firstName: 'สมชาย',
|
||||
lastName: 'ใจดี',
|
||||
email: 'student@example.com',
|
||||
photoURL: '' // Set to URL if available
|
||||
})
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
|
||||
|
||||
// Types based on API responses
|
||||
interface User {
|
||||
id: number
|
||||
username: string
|
||||
email: 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<User | null>('auth_user_data', {
|
||||
maxAge: 60 * 60 * 24 * 7, // 1 week
|
||||
sameSite: 'lax',
|
||||
secure: process.env.NODE_ENV === 'production'
|
||||
secure: false
|
||||
})
|
||||
|
||||
const isAuthenticated = computed(() => !!token.value)
|
||||
|
||||
const login = (mockToken: string = 'demo-token') => {
|
||||
token.value = mockToken
|
||||
// Refresh Token Logic
|
||||
const refreshToken = useCookie('auth_refresh_token', {
|
||||
maxAge: 60 * 60 * 24 * 7, // 7 days (matching API likely)
|
||||
sameSite: 'lax',
|
||||
secure: false
|
||||
})
|
||||
|
||||
// ... (previous code)
|
||||
|
||||
// Login
|
||||
const login = async (credentials: { email: string; password: string }) => {
|
||||
try {
|
||||
const { data, error } = await useFetch<loginResponse>(`${API_BASE_URL}/auth/login`, {
|
||||
method: 'POST',
|
||||
body: credentials
|
||||
})
|
||||
|
||||
if (error.value) {
|
||||
throw error.value
|
||||
}
|
||||
|
||||
if (data.value) {
|
||||
token.value = data.value.token
|
||||
refreshToken.value = data.value.refreshToken // Save refresh token
|
||||
|
||||
// The API returns the profile nested inside the user object
|
||||
user.value = data.value.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 || 'เข้าสู่ระบบไม่สำเร็จ'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
const register = async (payload: RegisterPayload) => {
|
||||
try {
|
||||
const { data, error } = await useFetch(`${API_BASE_URL}/auth/register`, {
|
||||
method: 'POST',
|
||||
body: payload
|
||||
})
|
||||
|
||||
if (error.value) {
|
||||
throw error.value
|
||||
}
|
||||
|
||||
return { success: true, data: data.value }
|
||||
|
||||
} catch (err: any) {
|
||||
console.error('Register failed:', err)
|
||||
return {
|
||||
success: false,
|
||||
error: err.data?.message || err.data?.error || 'ลงทะเบียนไม่สำเร็จ'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch User Profile (/api/user/me)
|
||||
const fetchUserProfile = async () => {
|
||||
if (!token.value) return
|
||||
|
||||
try {
|
||||
const { data, error } = await useFetch<User>(`${API_BASE_URL}/user/me`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token.value}`
|
||||
}
|
||||
})
|
||||
|
||||
if (error.value) {
|
||||
if (error.value.statusCode === 401) {
|
||||
logout()
|
||||
}
|
||||
throw error.value
|
||||
}
|
||||
|
||||
if (data.value) {
|
||||
user.value = data.value
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch user profile:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Request Password Reset
|
||||
const requestPasswordReset = async (email: string) => {
|
||||
try {
|
||||
const { error } = await useFetch(`${API_BASE_URL}/auth/reset-request`, {
|
||||
method: 'POST',
|
||||
body: { email }
|
||||
})
|
||||
|
||||
if (error.value) throw error.value
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.data?.message || 'ส่งคำขอไม่สำเร็จ' }
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm Reset Password
|
||||
const confirmResetPassword = async (payload: { id: number; token: string; password: string }) => {
|
||||
try {
|
||||
const { error } = await useFetch(`${API_BASE_URL}/auth/reset-password`, {
|
||||
method: 'POST',
|
||||
body: payload
|
||||
})
|
||||
|
||||
if (error.value) throw error.value
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.data?.message || 'รีเซ็ตรหัสผ่านไม่สำเร็จ' }
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh Access Token
|
||||
const refreshAccessToken = async () => {
|
||||
if (!refreshToken.value) return false
|
||||
|
||||
try {
|
||||
const { data, error } = await useFetch<{ token: string; refreshToken: string }>(`${API_BASE_URL}/auth/refresh`, {
|
||||
method: 'POST',
|
||||
body: { refreshToken: refreshToken.value }
|
||||
})
|
||||
|
||||
if (error.value) throw error.value
|
||||
|
||||
if (data.value) {
|
||||
token.value = data.value.token
|
||||
refreshToken.value = data.value.refreshToken
|
||||
return true
|
||||
}
|
||||
} catch (err) {
|
||||
// Refresh failed, force logout
|
||||
logout()
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Logout
|
||||
const logout = () => {
|
||||
token.value = null
|
||||
// Reset user photo if needed on logout
|
||||
// currentUser.value.photoURL = ''
|
||||
return navigateTo('/auth/login', { replace: true })
|
||||
refreshToken.value = null // Clear refresh token
|
||||
user.value = null
|
||||
const router = useRouter()
|
||||
router.push('/auth/login')
|
||||
}
|
||||
|
||||
return {
|
||||
isAuthenticated,
|
||||
token,
|
||||
currentUser,
|
||||
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,
|
||||
firstName,
|
||||
lastName,
|
||||
email: user.value.email,
|
||||
phone: user.value.profile?.phone || '',
|
||||
photoURL: user.value.profile?.avatar_url || '',
|
||||
role: user.value.role
|
||||
}
|
||||
}),
|
||||
login,
|
||||
register,
|
||||
fetchUserProfile,
|
||||
requestPasswordReset,
|
||||
confirmResetPassword,
|
||||
logout
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue