431 lines
20 KiB
TypeScript
431 lines
20 KiB
TypeScript
"use client"
|
||
|
||
import { useState, useEffect, useRef } from "react"
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Brain, Lightbulb, BarChart3, Users, Settings, Menu, ChevronDown, Link as LinkIcon, CheckCircle } from "lucide-react"
|
||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"
|
||
import Link from "next/link"
|
||
import Image from "next/image"
|
||
import { useAuth } from "@/lib/hooks/use-auth"
|
||
import { useRouter } from "next/navigation"
|
||
import { ProtectedRoute } from "@/components/protected-route"
|
||
|
||
export default function HomePage() {
|
||
const { user, logout } = useAuth()
|
||
const router = useRouter()
|
||
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
|
||
const [testCompletionStatus, setTestCompletionStatus] = useState({
|
||
logic: false,
|
||
creative: false,
|
||
combined: false
|
||
})
|
||
const [isLoadingTests, setIsLoadingTests] = useState(true)
|
||
const [questionCounts, setQuestionCounts] = useState({
|
||
logic: 0,
|
||
creative: 0,
|
||
total: 0
|
||
})
|
||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||
|
||
const handleLogout = () => {
|
||
logout()
|
||
router.push("/")
|
||
}
|
||
|
||
// 獲取題目數量
|
||
const fetchQuestionCounts = async () => {
|
||
try {
|
||
// 獲取邏輯題目數量
|
||
const logicResponse = await fetch('/api/logic-questions')
|
||
const logicData = await logicResponse.json()
|
||
const logicCount = logicData.success ? logicData.count || logicData.questions?.length || 0 : 0
|
||
|
||
// 獲取創意題目數量
|
||
const creativeResponse = await fetch('/api/creative-questions')
|
||
const creativeData = await creativeResponse.json()
|
||
const creativeCount = creativeData.success ? creativeData.questions?.length || 0 : 0
|
||
|
||
setQuestionCounts({
|
||
logic: logicCount,
|
||
creative: creativeCount,
|
||
total: logicCount + creativeCount
|
||
})
|
||
} catch (error) {
|
||
console.error('Error fetching question counts:', error)
|
||
}
|
||
}
|
||
|
||
// 檢查用戶測驗完成狀態
|
||
const checkTestCompletionStatus = async () => {
|
||
if (!user) return
|
||
|
||
try {
|
||
setIsLoadingTests(true)
|
||
|
||
// 檢查邏輯測試
|
||
const logicResponse = await fetch(`/api/test-results/logic?userId=${user.id}`)
|
||
const logicData = await logicResponse.json()
|
||
const hasLogicTest = logicData.success && logicData.data && logicData.data.length > 0
|
||
|
||
// 檢查創意測試
|
||
const creativeResponse = await fetch(`/api/test-results/creative?userId=${user.id}`)
|
||
const creativeData = await creativeResponse.json()
|
||
const hasCreativeTest = creativeData.success && creativeData.data && creativeData.data.length > 0
|
||
|
||
// 檢查綜合測試
|
||
const combinedResponse = await fetch(`/api/test-results/combined?userId=${user.id}`)
|
||
const combinedData = await combinedResponse.json()
|
||
const hasCombinedTest = combinedData.success && combinedData.data && combinedData.data.length > 0
|
||
|
||
setTestCompletionStatus({
|
||
logic: hasLogicTest,
|
||
creative: hasCreativeTest,
|
||
combined: hasCombinedTest
|
||
})
|
||
} catch (error) {
|
||
console.error('Error checking test completion status:', error)
|
||
} finally {
|
||
setIsLoadingTests(false)
|
||
}
|
||
}
|
||
|
||
// 獲取題目數量和檢查測驗完成狀態
|
||
useEffect(() => {
|
||
fetchQuestionCounts()
|
||
if (user) {
|
||
checkTestCompletionStatus()
|
||
}
|
||
}, [user])
|
||
|
||
// 點擊外部關閉下拉選單
|
||
useEffect(() => {
|
||
const handleClickOutside = (event: MouseEvent) => {
|
||
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
||
setIsDropdownOpen(false)
|
||
}
|
||
}
|
||
|
||
if (isDropdownOpen) {
|
||
document.addEventListener('mousedown', handleClickOutside)
|
||
}
|
||
|
||
return () => {
|
||
document.removeEventListener('mousedown', handleClickOutside)
|
||
}
|
||
}, [isDropdownOpen])
|
||
|
||
// 調試信息
|
||
console.log("Current user:", user)
|
||
|
||
return (
|
||
<ProtectedRoute>
|
||
<div className="min-h-screen bg-background">
|
||
{/* Header */}
|
||
<header className="border-b bg-card/50 backdrop-blur-sm sticky top-0 z-50">
|
||
<div className="container mx-auto px-4 py-4">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-primary rounded-lg flex items-center justify-center">
|
||
<Users className="w-6 h-6 text-primary-foreground" />
|
||
</div>
|
||
<div>
|
||
<h1 className="text-xl font-bold text-foreground">HR 評估系統</h1>
|
||
<p className="text-sm text-muted-foreground">員工能力測評平台</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Desktop Navigation */}
|
||
<div className="hidden md:flex items-center gap-6">
|
||
{/* Navigation Links */}
|
||
<div className="flex items-center gap-12">
|
||
{user?.role === "admin" && (
|
||
<>
|
||
<Link
|
||
href="/admin/results"
|
||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||
>
|
||
所有測試結果
|
||
</Link>
|
||
<Link
|
||
href="/admin/analytics"
|
||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||
>
|
||
部門分析
|
||
</Link>
|
||
</>
|
||
)}
|
||
</div>
|
||
|
||
{/* 自定義下拉選單 */}
|
||
<div className="relative" ref={dropdownRef}>
|
||
<Button
|
||
variant="ghost"
|
||
className="flex items-center gap-3 hover:bg-accent px-6 py-6 text-foreground rounded-lg group"
|
||
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
||
>
|
||
<div className="text-right">
|
||
<p className="text-sm font-medium text-foreground group-hover:text-white">{user?.name || '系統管理員'}</p>
|
||
<p className="text-xs text-muted-foreground group-hover:text-white/80">{user?.department || '人力資源部'}</p>
|
||
</div>
|
||
<ChevronDown className={`w-4 h-4 transition-transform group-hover:text-white ${isDropdownOpen ? 'rotate-180' : ''}`} />
|
||
</Button>
|
||
|
||
{isDropdownOpen && (
|
||
<div className="absolute right-0 top-full mt-1 w-56 bg-background border border-border rounded-md shadow-lg z-50">
|
||
<div className="py-1">
|
||
{user?.role === "admin" && (
|
||
<>
|
||
<Link
|
||
href="/settings"
|
||
className="flex items-center gap-2 px-4 py-2 text-sm text-foreground hover:bg-accent hover:text-accent-foreground"
|
||
onClick={() => setIsDropdownOpen(false)}
|
||
>
|
||
<Settings className="w-4 h-4" />
|
||
帳戶設定
|
||
</Link>
|
||
<Link
|
||
href="/admin/users"
|
||
className="flex items-center gap-2 px-4 py-2 text-sm text-foreground hover:bg-accent hover:text-accent-foreground"
|
||
onClick={() => setIsDropdownOpen(false)}
|
||
>
|
||
<Users className="w-4 h-4" />
|
||
用戶管理
|
||
</Link>
|
||
<Link
|
||
href="/admin/questions"
|
||
className="flex items-center gap-2 px-4 py-2 text-sm text-foreground hover:bg-accent hover:text-accent-foreground"
|
||
onClick={() => setIsDropdownOpen(false)}
|
||
>
|
||
<Brain className="w-4 h-4" />
|
||
題目管理
|
||
</Link>
|
||
<Link
|
||
href="/admin/test-links"
|
||
className="flex items-center gap-2 px-4 py-2 text-sm text-foreground hover:bg-accent hover:text-accent-foreground"
|
||
onClick={() => setIsDropdownOpen(false)}
|
||
>
|
||
<LinkIcon className="w-4 h-4" />
|
||
測驗連結
|
||
</Link>
|
||
<div className="border-t border-border my-1"></div>
|
||
</>
|
||
)}
|
||
<button
|
||
onClick={() => {
|
||
handleLogout()
|
||
setIsDropdownOpen(false)
|
||
}}
|
||
className="flex items-center gap-2 px-4 py-2 text-sm text-red-600 hover:bg-red-50 hover:text-red-700 w-full text-left"
|
||
>
|
||
登出
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="md:hidden">
|
||
<Sheet>
|
||
<SheetTrigger asChild>
|
||
<Button variant="ghost" size="sm">
|
||
<Menu className="w-5 h-5" />
|
||
</Button>
|
||
</SheetTrigger>
|
||
<SheetContent>
|
||
<SheetHeader>
|
||
<SheetTitle className="text-left">選單</SheetTitle>
|
||
</SheetHeader>
|
||
<div className="mt-6 space-y-4 px-4">
|
||
<div className="pb-4 border-b">
|
||
<p className="font-medium">{user?.name}</p>
|
||
<p className="text-sm text-muted-foreground">{user?.department}</p>
|
||
</div>
|
||
|
||
{/* Navigation Links */}
|
||
{user?.role === "admin" && (
|
||
<>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/admin/results" className="flex items-center gap-2">
|
||
<BarChart3 className="w-4 h-4" />
|
||
所有測試結果
|
||
</Link>
|
||
</Button>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/admin/analytics" className="flex items-center gap-2">
|
||
<BarChart3 className="w-4 h-4" />
|
||
部門分析
|
||
</Link>
|
||
</Button>
|
||
</>
|
||
)}
|
||
|
||
{user?.role === "admin" && (
|
||
<>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/settings" className="flex items-center gap-2">
|
||
<Settings className="w-4 h-4" />
|
||
帳戶設定
|
||
</Link>
|
||
</Button>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/admin/users" className="flex items-center gap-2">
|
||
<Users className="w-4 h-4" />
|
||
用戶管理
|
||
</Link>
|
||
</Button>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/admin/questions" className="flex items-center gap-2">
|
||
<Brain className="w-4 h-4" />
|
||
題目管理
|
||
</Link>
|
||
</Button>
|
||
<Button asChild variant="ghost" className="w-full justify-start px-4">
|
||
<Link href="/admin/test-links" className="flex items-center gap-2">
|
||
<LinkIcon className="w-4 h-4" />
|
||
測驗連結
|
||
</Link>
|
||
</Button>
|
||
</>
|
||
)}
|
||
<Button onClick={handleLogout} variant="ghost" className="w-full justify-start text-red-600 px-4">
|
||
登出
|
||
</Button>
|
||
</div>
|
||
</SheetContent>
|
||
</Sheet>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
{/* Hero Section */}
|
||
<section className="py-8 md:py-16 px-4 flex items-center">
|
||
<div className="container mx-auto text-center">
|
||
<div className="max-w-2xl mx-auto">
|
||
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4 md:mb-6 text-balance">
|
||
歡迎回來,{user?.name}
|
||
</h2>
|
||
<p className="text-lg md:text-xl text-muted-foreground text-pretty leading-relaxed">
|
||
透過科學的邏輯思維測試和創意能力評估,全面了解您的綜合素質
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Test Cards / Admin Info Cards */}
|
||
<section className="py-8 md:py-16 px-4">
|
||
<div className="container mx-auto">
|
||
{user?.role === "admin" ? (
|
||
// 管理者看到的介紹卡片
|
||
<div className="flex justify-center mb-8">
|
||
<div className="w-full max-w-2xl">
|
||
{/* 綜合測試介紹 */}
|
||
<Card className="group hover:shadow-lg transition-all duration-300 border-2 border-primary/20 bg-gradient-to-br from-primary/5 to-accent/5">
|
||
<CardHeader className="text-center pb-4">
|
||
<div className="w-12 h-12 bg-gradient-to-br from-primary to-accent rounded-full flex items-center justify-center mx-auto mb-3 group-hover:scale-110 transition-transform shadow-lg">
|
||
<BarChart3 className="w-6 h-6 text-white" />
|
||
</div>
|
||
<CardTitle className="text-xl mb-2">綜合測試</CardTitle>
|
||
<CardDescription className="text-sm mb-3">
|
||
綜合測試包含邏輯思維和創意能力,附有完整分析報告,<br />
|
||
全卷設定作答時間 30 分鐘。
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="text-center">
|
||
<div className="flex justify-center gap-6">
|
||
<div className="flex flex-col items-center">
|
||
<span className="text-xs text-muted-foreground mb-1">總題目數</span>
|
||
<span className="text-lg font-bold text-primary">{questionCounts.total}題</span>
|
||
</div>
|
||
<div className="flex flex-col items-center">
|
||
<span className="text-xs text-muted-foreground mb-1">預計時間</span>
|
||
<span className="text-lg font-bold text-accent">30分鐘</span>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
) : (
|
||
// 一般用戶看到的測試功能
|
||
<div className="flex justify-center mb-8">
|
||
<div className="w-full max-w-2xl">
|
||
{/* Combined Test */}
|
||
<Card className="group hover:shadow-lg transition-all duration-300 border-2 border-primary/20 bg-gradient-to-br from-primary/5 to-accent/5">
|
||
<CardHeader className="text-center pb-4">
|
||
<div className="w-12 h-12 bg-gradient-to-br from-primary to-accent rounded-full flex items-center justify-center mx-auto mb-3 group-hover:scale-110 transition-transform shadow-lg">
|
||
<BarChart3 className="w-6 h-6 text-white" />
|
||
</div>
|
||
<CardTitle className="text-xl mb-2">綜合測試</CardTitle>
|
||
<CardDescription className="text-sm mb-3">
|
||
全卷設定作答時間 30 分鐘,<br />
|
||
請誠實反映您平常的思考方式與感受,不需刻意迎合特定答案。
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="text-center">
|
||
<div className="flex justify-center gap-6">
|
||
<div className="flex flex-col items-center">
|
||
<span className="text-xs text-muted-foreground mb-1">總題目數</span>
|
||
<span className="text-lg font-bold text-primary">{questionCounts.total}題</span>
|
||
</div>
|
||
<div className="flex flex-col items-center">
|
||
<span className="text-xs text-muted-foreground mb-1">預計時間</span>
|
||
<span className="text-lg font-bold text-accent">30分鐘</span>
|
||
</div>
|
||
</div>
|
||
<div className="mt-6">
|
||
{isLoadingTests ? (
|
||
<Button disabled size="lg" className="w-full">
|
||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2"></div>
|
||
載入中...
|
||
</Button>
|
||
) : testCompletionStatus.combined ? (
|
||
<Button asChild variant="outline" size="lg" className="w-full border-green-500 text-green-600 hover:bg-green-50 hover:text-green-700 hover:border-green-600">
|
||
<Link href="/tests/combined">
|
||
<CheckCircle className="w-4 h-4 mr-2" />
|
||
已完成測驗
|
||
</Link>
|
||
</Button>
|
||
) : (
|
||
<Button asChild size="lg" className="w-full">
|
||
<Link href="/tests/combined">開始測試</Link>
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</section>
|
||
|
||
{/* Footer */}
|
||
<footer className="border-t bg-muted/30 py-12 px-4 mt-16">
|
||
<div className="container mx-auto">
|
||
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||
{/* 左側內容 */}
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-primary rounded-lg flex items-center justify-center">
|
||
<Users className="w-6 h-6 text-primary-foreground" />
|
||
</div>
|
||
<div>
|
||
<span className="text-lg font-semibold">HR 評估系統</span>
|
||
<p className="text-muted-foreground text-sm">專業的員工能力測評解決方案,助力企業人才發展</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 右側內容 */}
|
||
<div className="text-sm text-muted-foreground">
|
||
© 2025 HR 評估系統. All rights reserved.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
</ProtectedRoute>
|
||
)
|
||
}
|