feat: 優化用戶體驗與界面設計

- 修復用戶名稱更新後導航欄不即時更新的問題
- 新增 AuthContext.updateUser 方法同步全域用戶狀態
- 隱藏導航欄通知鈴鐺按鈕
- 隱藏儀表板導航項目
- 隱藏個人資料頁面的學習設定分頁
- 調整登出按鈕顏色為較溫和的灰色

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
鄭沛軒 2025-10-08 00:18:10 +08:00
parent 6b66c56adc
commit b7c695bb4e
3 changed files with 28 additions and 29 deletions

View File

@ -2,6 +2,7 @@
import { useState, useEffect } from 'react'
import { Navigation } from '@/components/shared/Navigation'
import { useAuth } from '@/contexts/AuthContext'
interface UserProfile {
id: string
@ -31,6 +32,7 @@ interface LanguageLevel {
type TabType = 'profile' | 'settings' | 'level'
export default function ProfilePage() {
const { updateUser } = useAuth()
const [activeTab, setActiveTab] = useState<TabType>('profile')
const [profile, setProfile] = useState<UserProfile | null>(null)
const [settings, setSettings] = useState<UserSettings | null>(null)
@ -91,7 +93,7 @@ export default function ProfilePage() {
const tabs = [
{ id: 'profile' as TabType, label: '個人資料', icon: '👤' },
{ id: 'settings' as TabType, label: '學習設定', icon: '⚙️' },
// { id: 'settings' as TabType, label: '學習設定', icon: '⚙️' },
{ id: 'level' as TabType, label: '英語程度', icon: '🎯' }
]
@ -198,6 +200,10 @@ export default function ProfilePage() {
if (response.ok) {
await loadData() // 重新載入資料
// 同步更新全域 AuthContext 中的用戶資料
updateUser({ displayName: editForm.displayName })
console.log('✅ 個人資料更新成功')
} else {
setError('儲存失敗')
@ -442,7 +448,7 @@ export default function ProfilePage() {
<div className="border-t pt-6">
<button
onClick={handleLogout}
className="w-full px-4 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors font-medium"
className="w-full px-4 py-3 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors font-medium"
>
</button>
@ -670,29 +676,6 @@ export default function ProfilePage() {
</div>
)}
</div>
{/* 快速操作區 */}
<div className="mt-8 bg-white rounded-xl shadow-lg p-6">
<h3 className="font-semibold text-gray-900 mb-4"></h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{[
{ href: '/review', icon: '📚', label: '開始複習', desc: '複習詞卡' },
{ href: '/generate', icon: '', label: '新增詞卡', desc: '建立內容' },
{ href: '/flashcards', icon: '📋', label: '管理詞卡', desc: '編輯詞卡' },
{ href: '/stats', icon: '📊', label: '學習統計', desc: '查看進度' }
].map(action => (
<button
key={action.href}
onClick={() => window.location.href = action.href}
className="p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors text-center"
>
<div className="text-2xl mb-1">{action.icon}</div>
<div className="font-medium text-gray-900 text-sm">{action.label}</div>
<div className="text-xs text-gray-500">{action.desc}</div>
</button>
))}
</div>
</div>
</div>
</div>
</div>

View File

@ -16,10 +16,10 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
const navItems = [
{ href: '/dashboard', label: '儀表板' },
// { href: '/dashboard', label: '儀表板' },
{ href: '/flashcards', label: '詞卡' },
{ href: '/review', label: '複習' },
{ href: '/generate', label: 'AI 生成' }
{ href: '/generate', label: 'AI詞卡' }
]
return (
@ -74,11 +74,11 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat
) : (
<>
{/* 通知按鈕 - 桌面和手機都顯示 */}
<button className="p-2 text-gray-600 hover:text-gray-900">
{/* <button className="p-2 text-gray-600 hover:text-gray-900">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
</button>
</button> */}
{/* 用戶資訊 - 只在桌面版顯示 */}
<div className="hidden md:flex items-center space-x-3">

View File

@ -15,6 +15,7 @@ interface AuthContextType extends AuthState {
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)
@ -139,12 +140,27 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
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 (