dramaling-vocab-learning/frontend/contexts/AuthContext.tsx

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>
)
}