整合資料庫、完成登入註冊忘記密碼功能

This commit is contained in:
2025-09-09 12:00:22 +08:00
parent af88c0f037
commit 32b19e9a0f
85 changed files with 11672 additions and 2350 deletions

View File

@@ -77,17 +77,27 @@ const mockNotifications: Notification[] = []
const mockSearchData: SearchResult[] = []
export function AdminLayout({ children, currentPage, onPageChange }: AdminLayoutProps) {
const { user, logout, isLoading } = useAuth()
// Move ALL hooks to the top, before any conditional logic
const { user, logout, isLoading, isInitialized } = useAuth()
const [sidebarOpen, setSidebarOpen] = useState(true)
const [isClient, setIsClient] = useState(false)
// Search state
const [searchQuery, setSearchQuery] = useState("")
const [searchResults, setSearchResults] = useState<SearchResult[]>([])
const [showSearchResults, setShowSearchResults] = useState(false)
// Notification state
const [notifications, setNotifications] = useState<Notification[]>(mockNotifications)
const [showNotifications, setShowNotifications] = useState(false)
// Logout confirmation state
const [showLogoutDialog, setShowLogoutDialog] = useState(false)
// Set client state after hydration
useEffect(() => {
setIsClient(true)
}, [])
// Handle search
useEffect(() => {
if (searchQuery.trim()) {
@@ -104,46 +114,6 @@ export function AdminLayout({ children, currentPage, onPageChange }: AdminLayout
}
}, [searchQuery])
// 認證檢查 - moved after all hooks
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="flex items-center space-x-2">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600"></div>
<span className="text-gray-600">...</span>
</div>
</div>
)
}
if (!user) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold text-gray-900 mb-4"></h1>
<p className="text-gray-600 mb-6"></p>
<Button onClick={() => window.location.href = '/'}>
</Button>
</div>
</div>
)
}
if (user.role !== 'admin') {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold text-gray-900 mb-4"></h1>
<p className="text-gray-600 mb-6"></p>
<Button onClick={() => window.location.href = '/'}>
</Button>
</div>
</div>
)
}
// Get unread notification count
const unreadCount = notifications.filter((n) => !n.read).length
@@ -207,13 +177,15 @@ export function AdminLayout({ children, currentPage, onPageChange }: AdminLayout
setShowLogoutDialog(false)
// Check if this is a popup/new tab opened from main site
if (typeof window !== 'undefined' && window.opener && !window.opener.closed) {
// If opened from another window, close this tab and focus parent
window.opener.focus()
window.close()
} else {
// If this is the main window or standalone, redirect to homepage
window.location.href = "/"
if (isClient) {
if (window.opener && !window.opener.closed) {
// If opened from another window, close this tab and focus parent
window.opener.focus()
window.close()
} else {
// If this is the main window or standalone, redirect to homepage
window.location.href = "/"
}
}
}
@@ -236,6 +208,19 @@ export function AdminLayout({ children, currentPage, onPageChange }: AdminLayout
}
}
// 如果還在載入中,顯示載入畫面
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="text-center space-y-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
<p className="text-gray-600">...</p>
</div>
</div>
)
}
// 檢查用戶權限
if (!user || user.role !== "admin") {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
@@ -246,11 +231,20 @@ export function AdminLayout({ children, currentPage, onPageChange }: AdminLayout
<div>
<h2 className="text-2xl font-bold text-gray-900 mb-2"></h2>
<p className="text-gray-600 mb-4"></p>
{process.env.NODE_ENV === 'development' && (
<div className="text-xs text-gray-500 mb-4">
調試信息: 用戶={user ? '已登入' : '未登入'}, ={user?.role || '無'}
</div>
)}
<div className="space-x-3">
<Button onClick={() => (window.location.href = "/")} variant="outline">
<Button onClick={() => {
if (isClient) {
window.location.href = "/"
}
}} variant="outline">
</Button>
{typeof window !== 'undefined' && window.opener && !window.opener.closed && (
{isClient && window.opener && !window.opener.closed && (
<Button
onClick={() => {
window.opener.focus()