171 lines
4.3 KiB
TypeScript
171 lines
4.3 KiB
TypeScript
'use client'
|
|
|
|
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react'
|
|
import { authService, User } from '@/lib/services/auth'
|
|
|
|
interface AuthState {
|
|
user: User | null
|
|
token: string | null
|
|
isAuthenticated: boolean
|
|
isLoading: boolean
|
|
}
|
|
|
|
interface AuthContextType extends AuthState {
|
|
login: (email: string, password: string) => Promise<{ success: boolean; error?: string }>
|
|
register: (username: string, email: string, password: string) => Promise<{ success: boolean; error?: string }>
|
|
logout: () => void
|
|
checkAuth: () => Promise<boolean>
|
|
updateUser: (updatedUser: Partial<User>) => void
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
|
|
|
export const useAuth = () => {
|
|
const context = useContext(AuthContext)
|
|
if (context === undefined) {
|
|
throw new Error('useAuth must be used within an AuthProvider')
|
|
}
|
|
return context
|
|
}
|
|
|
|
interface AuthProviderProps {
|
|
children: ReactNode
|
|
}
|
|
|
|
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
|
const [state, setState] = useState<AuthState>({
|
|
user: null,
|
|
token: null,
|
|
isAuthenticated: false,
|
|
isLoading: true,
|
|
})
|
|
|
|
// 初始化時檢查認證狀態
|
|
useEffect(() => {
|
|
const initAuth = async () => {
|
|
const token = authService.getToken()
|
|
const user = authService.getUser()
|
|
|
|
if (token && user) {
|
|
// 驗證 token 是否仍然有效
|
|
const isValid = await authService.checkAuthStatus()
|
|
if (isValid) {
|
|
setState({
|
|
user,
|
|
token,
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
})
|
|
} else {
|
|
// Token 無效,清除本地存儲
|
|
authService.logout()
|
|
setState({
|
|
user: null,
|
|
token: null,
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
})
|
|
}
|
|
} else {
|
|
setState({
|
|
user: null,
|
|
token: null,
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
})
|
|
}
|
|
}
|
|
|
|
initAuth()
|
|
}, [])
|
|
|
|
const login = async (email: string, password: string) => {
|
|
try {
|
|
const response = await authService.login({ email, password })
|
|
|
|
if (response.success && response.data) {
|
|
setState({
|
|
user: response.data.user,
|
|
token: response.data.token,
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
})
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: response.error || '登入失敗' }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: '網路錯誤,請稍後再試' }
|
|
}
|
|
}
|
|
|
|
const register = async (username: string, email: string, password: string) => {
|
|
try {
|
|
const response = await authService.register({ username, email, password })
|
|
|
|
if (response.success && response.data) {
|
|
setState({
|
|
user: response.data.user,
|
|
token: response.data.token,
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
})
|
|
return { success: true }
|
|
} else {
|
|
return { success: false, error: response.error || '註冊失敗' }
|
|
}
|
|
} catch (error) {
|
|
return { success: false, error: '網路錯誤,請稍後再試' }
|
|
}
|
|
}
|
|
|
|
const logout = () => {
|
|
authService.logout()
|
|
setState({
|
|
user: null,
|
|
token: null,
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
})
|
|
}
|
|
|
|
const checkAuth = async (): Promise<boolean> => {
|
|
if (!state.token) return false
|
|
|
|
const isValid = await authService.checkAuthStatus()
|
|
if (!isValid) {
|
|
logout()
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
const updateUser = (updatedUser: Partial<User>) => {
|
|
if (!state.user) return
|
|
|
|
const newUser = { ...state.user, ...updatedUser }
|
|
|
|
setState(prev => ({
|
|
...prev,
|
|
user: newUser
|
|
}))
|
|
|
|
// 同時更新 localStorage 中的用戶資料
|
|
localStorage.setItem('user_data', JSON.stringify(newUser))
|
|
}
|
|
|
|
const contextValue: AuthContextType = {
|
|
...state,
|
|
login,
|
|
register,
|
|
logout,
|
|
checkAuth,
|
|
updateUser,
|
|
}
|
|
|
|
return (
|
|
<AuthContext.Provider value={contextValue}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
)
|
|
} |