Files
hr-assessment-system/app/home/page.tsx
2025-10-12 00:07:45 +08:00

431 lines
20 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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