"use client" import { createContext, useContext, useState, useEffect, type ReactNode } from "react" import type { Judge, JudgeScore, Competition, Award, Team, Proposal, ProposalJudgeScore } from "@/types/competition" interface CompetitionContextType { // Judges judges: Judge[] addJudge: (judge: Omit) => void updateJudge: (id: string, updates: Partial) => void deleteJudge: (id: string) => void // Competitions competitions: Competition[] currentCompetition: Competition | null setCurrentCompetition: (competition: Competition | null) => void addCompetition: (competition: Omit) => void updateCompetition: (id: string, updates: Partial) => void deleteCompetition: (id: string) => void // Teams teams: Team[] addTeam: (team: Omit) => void updateTeam: (id: string, updates: Partial) => void getTeamById: (id: string) => Team | undefined // Proposals proposals: Proposal[] addProposal: (proposal: Omit) => void updateProposal: (id: string, updates: Partial) => void getProposalById: (id: string) => Proposal | undefined // Judge Scores judgeScores: JudgeScore[] proposalJudgeScores: ProposalJudgeScore[] addJudgeScore: (score: Omit) => void addProposalJudgeScore: (score: Omit) => void submitJudgeScore: (score: Omit) => void submitProposalJudgeScore: (score: Omit) => void getAppJudgeScores: (appId: string) => JudgeScore[] getProposalJudgeScores: (proposalId: string) => ProposalJudgeScore[] getAppAverageScore: (appId: string) => number getProposalAverageScore: (proposalId: string) => number getAppDetailedScores: (appId: string) => { innovation: number technical: number usability: number presentation: number impact: number total: number judgeCount: number } getProposalDetailedScores: (proposalId: string) => { problemIdentification: number solutionFeasibility: number innovation: number impact: number presentation: number total: number judgeCount: number } // Awards awards: Award[] addAward: (award: Omit) => void getAwardsByYear: (year: number) => Award[] getAwardsByMonth: (year: number, month: number) => Award[] // Rankings getCompetitionRankings: (competitionId?: string) => Array<{ appId?: string proposalId?: string teamId?: string appName?: string proposalTitle?: string teamName?: string creator: string totalScore: number rank: number scores: any competitionType: "individual" | "team" | "proposal" }> // Add new filtering functions getAwardsByCompetitionType: (competitionType?: string) => Award[] getAwardsByCategory: (category?: string) => Award[] getTopRankingAwards: () => Award[] getPopularityAwards: () => Award[] getPopularityRankings: (competitionId?: string) => Array<{ id: string name: string creator: string department: string type: string likes: number rank: number }> } const CompetitionContext = createContext(undefined) // Mock data const mockJudges: Judge[] = [] // Mock teams data const mockTeams: Team[] = [] // Mock proposals data const mockProposals: Proposal[] = [] // 競賽資料 const mockCompetitions: Competition[] = [] // Mock app likes counter const appLikesCounter: Record = {} export function CompetitionProvider({ children }: { children: ReactNode }) { const [judges, setJudges] = useState(mockJudges) const [competitions, setCompetitions] = useState(mockCompetitions) const [currentCompetition, setCurrentCompetition] = useState(null) const [teams, setTeams] = useState(mockTeams) const [proposals, setProposals] = useState(mockProposals) // 載入所有競賽和當前競賽 useEffect(() => { const loadCompetitions = async () => { try { // 載入所有競賽 const competitionsResponse = await fetch('/api/competitions') const competitionsData = await competitionsResponse.json() if (competitionsData.success && competitionsData.data) { setCompetitions(competitionsData.data) } // 載入當前競賽 const currentResponse = await fetch('/api/competitions/current') const currentData = await currentResponse.json() if (currentData.success && currentData.data) { setCurrentCompetition(currentData.data) } } catch (error) { console.error('載入競賽數據失敗:', error) } } loadCompetitions() }, []) // Load judge scores from localStorage const [judgeScores, setJudgeScores] = useState(() => { if (typeof window !== "undefined") { const saved = localStorage.getItem("judgeScores") if (saved) { return JSON.parse(saved) } } // 評分資料 const mockScores: JudgeScore[] = [] return mockScores }) // Load proposal judge scores from localStorage const [proposalJudgeScores, setProposalJudgeScores] = useState(() => { if (typeof window !== "undefined") { const saved = localStorage.getItem("proposalJudgeScores") if (saved) { return JSON.parse(saved) } } // 提案評分資料 const mockProposalScores: ProposalJudgeScore[] = [] return mockProposalScores }) // Load awards from localStorage const [awards, setAwards] = useState(() => { if (typeof window !== "undefined") { const saved = localStorage.getItem("competitionAwards") if (saved) { return JSON.parse(saved) } } // 獎項資料 const mockAwards = [] return mockAwards }) // Save to localStorage when data changes useEffect(() => { if (typeof window !== "undefined") { localStorage.setItem("judgeScores", JSON.stringify(judgeScores)) } }, [judgeScores]) useEffect(() => { if (typeof window !== "undefined") { localStorage.setItem("proposalJudgeScores", JSON.stringify(proposalJudgeScores)) } }, [proposalJudgeScores]) useEffect(() => { if (typeof window !== "undefined") { localStorage.setItem("competitionAwards", JSON.stringify(awards)) } }, [awards]) const addJudge = (judge: Omit) => { const newJudge: Judge = { ...judge, id: `j${Date.now()}`, } setJudges((prev) => [...prev, newJudge]) } const updateJudge = (id: string, updates: Partial) => { setJudges((prev) => prev.map((judge) => (judge.id === id ? { ...judge, ...updates } : judge))) } const deleteJudge = (id: string) => { console.log('🗑️ Context deleteJudge 被調用,ID:', id) console.log('🗑️ 刪除前的 judges 狀態:', judges.map(j => ({ id: j.id, name: j.name, is_active: j.is_active }))) setJudges((prev) => { const filtered = prev.filter((judge) => judge.id !== id) console.log('🗑️ 刪除後的 judges 狀態:', filtered.map(j => ({ id: j.id, name: j.name, is_active: j.is_active }))) return filtered }) setCompetitions((prev) => prev.map((comp) => ({ ...comp, judges: comp.judges.filter((judgeId) => judgeId !== id), })), ) setJudgeScores((prev) => prev.filter((score) => score.judgeId !== id)) setProposalJudgeScores((prev) => prev.filter((score) => score.judgeId !== id)) } const addCompetition = (competition: Omit) => { const newCompetition: Competition = { ...competition, id: `c${Date.now()}`, } setCompetitions((prev) => [...prev, newCompetition]) } const updateCompetition = (id: string, updates: Partial) => { setCompetitions((prev) => prev.map((comp) => (comp.id === id ? { ...comp, ...updates } : comp))) if (currentCompetition?.id === id) { setCurrentCompetition((prev) => (prev ? { ...prev, ...updates } : null)) } } const deleteCompetition = (id: string) => { setCompetitions((prev) => prev.filter((comp) => comp.id !== id)) if (currentCompetition?.id === id) { setCurrentCompetition(null) } } const addTeam = (team: Omit) => { const newTeam: Team = { ...team, id: `t${Date.now()}`, } setTeams((prev) => [...prev, newTeam]) } const updateTeam = (id: string, updates: Partial) => { setTeams((prev) => prev.map((team) => (team.id === id ? { ...team, ...updates } : team))) } const getTeamById = (id: string): Team | undefined => { return teams.find((team) => team.id === id) } const addProposal = (proposal: Omit) => { const newProposal: Proposal = { ...proposal, id: `p${Date.now()}`, } setProposals((prev) => [...prev, newProposal]) } const updateProposal = (id: string, updates: Partial) => { setProposals((prev) => prev.map((proposal) => (proposal.id === id ? { ...proposal, ...updates } : proposal))) } const getProposalById = (id: string): Proposal | undefined => { return proposals.find((proposal) => proposal.id === id) } const addJudgeScore = (score: Omit) => { const newScore: JudgeScore = { ...score, submittedAt: new Date().toISOString(), } const filteredScores = judgeScores.filter((s) => !(s.judgeId === score.judgeId && s.appId === score.appId)) setJudgeScores([...filteredScores, newScore]) } const addProposalJudgeScore = (score: Omit) => { const newScore: ProposalJudgeScore = { ...score, submittedAt: new Date().toISOString(), } const filteredScores = proposalJudgeScores.filter( (s) => !(s.judgeId === score.judgeId && s.proposalId === score.proposalId), ) setProposalJudgeScores([...filteredScores, newScore]) } const submitJudgeScore = (score: Omit) => { addJudgeScore(score) } const submitProposalJudgeScore = (score: Omit) => { addProposalJudgeScore(score) } const getAppJudgeScores = (appId: string): JudgeScore[] => { return judgeScores.filter((score) => score.appId === appId) } const getProposalJudgeScores = (proposalId: string): ProposalJudgeScore[] => { return proposalJudgeScores.filter((score) => score.proposalId === proposalId) } const getAppAverageScore = (appId: string): number => { const scores = getAppJudgeScores(appId) if (scores.length === 0) return 0 const totalScore = scores.reduce((sum, score) => { const scoreSum = Object.values(score.scores).reduce((a, b) => a + b, 0) return sum + scoreSum }, 0) return Number((totalScore / (scores.length * 5)).toFixed(1)) } const getProposalAverageScore = (proposalId: string): number => { const scores = getProposalJudgeScores(proposalId) if (scores.length === 0) return 0 const totalScore = scores.reduce((sum, score) => { const scoreSum = Object.values(score.scores).reduce((a, b) => a + b, 0) return sum + scoreSum }, 0) return Number((totalScore / (scores.length * 5)).toFixed(1)) } const getAppDetailedScores = (appId: string) => { const scores = getAppJudgeScores(appId) if (scores.length === 0) { return { innovation: 0, technical: 0, usability: 0, presentation: 0, impact: 0, total: 0, judgeCount: 0, } } const totals = scores.reduce( (acc, score) => ({ innovation: acc.innovation + score.scores.innovation, technical: acc.technical + score.scores.technical, usability: acc.usability + score.scores.usability, presentation: acc.presentation + score.scores.presentation, impact: acc.impact + score.scores.impact, }), { innovation: 0, technical: 0, usability: 0, presentation: 0, impact: 0 }, ) const judgeCount = scores.length const averages = { innovation: Number((totals.innovation / judgeCount).toFixed(1)), technical: Number((totals.technical / judgeCount).toFixed(1)), usability: Number((totals.usability / judgeCount).toFixed(1)), presentation: Number((totals.presentation / judgeCount).toFixed(1)), impact: Number((totals.impact / judgeCount).toFixed(1)), } const total = Number( ( (totals.innovation + totals.technical + totals.usability + totals.presentation + totals.impact) / (judgeCount * 5) ).toFixed(1), ) return { ...averages, total, judgeCount, } } const getProposalDetailedScores = (proposalId: string) => { const scores = getProposalJudgeScores(proposalId) if (scores.length === 0) { return { problemIdentification: 0, solutionFeasibility: 0, innovation: 0, impact: 0, presentation: 0, total: 0, judgeCount: 0, } } const totals = scores.reduce( (acc, score) => ({ problemIdentification: acc.problemIdentification + score.scores.problemIdentification, solutionFeasibility: acc.solutionFeasibility + score.scores.solutionFeasibility, innovation: acc.innovation + score.scores.innovation, impact: acc.impact + score.scores.impact, presentation: acc.presentation + score.scores.presentation, }), { problemIdentification: 0, solutionFeasibility: 0, innovation: 0, impact: 0, presentation: 0 }, ) const judgeCount = scores.length const averages = { problemIdentification: Number((totals.problemIdentification / judgeCount).toFixed(1)), solutionFeasibility: Number((totals.solutionFeasibility / judgeCount).toFixed(1)), innovation: Number((totals.innovation / judgeCount).toFixed(1)), impact: Number((totals.impact / judgeCount).toFixed(1)), presentation: Number((totals.presentation / judgeCount).toFixed(1)), } const total = Number( ( (totals.problemIdentification + totals.solutionFeasibility + totals.innovation + totals.impact + totals.presentation) / (judgeCount * 5) ).toFixed(1), ) return { ...averages, total, judgeCount, } } const addAward = (award: Omit) => { const newAward: Award = { ...award, id: `a${Date.now()}`, } setAwards((prev) => [...prev, newAward]) } const getAwardsByYear = (year: number): Award[] => { return awards.filter((award) => award.year === year) } const getAwardsByMonth = (year: number, month: number): Award[] => { return awards.filter((award) => award.year === year && award.month === month) } const getCompetitionRankings = (competitionId?: string) => { const targetCompetition = competitionId ? competitions.find((c) => c.id === competitionId) : currentCompetition if (!targetCompetition) return [] const rankings: any[] = [] // Handle individual competitions if (targetCompetition.type === "individual" || targetCompetition.type === "mixed") { targetCompetition.participatingApps.forEach((appId) => { const detailedScores = getAppDetailedScores(appId) const appNames: Record = { "1": "智能對話助手", "2": "圖像生成工具", "3": "語音識別系統", "4": "智能推薦引擎", "5": "文本分析器", "6": "AI創意寫作", } const creators: Record = { "1": "張小明", "2": "李美華", "3": "王大偉", "4": "陳小芳", "5": "劉志強", "6": "黃小玲", } rankings.push({ appId, appName: appNames[appId] || `應用 ${appId}`, creator: creators[appId] || "未知", totalScore: detailedScores.total, scores: { innovation: detailedScores.innovation, technical: detailedScores.technical, usability: detailedScores.usability, presentation: detailedScores.presentation, impact: detailedScores.impact, }, rank: 0, competitionType: "individual" as const, }) }) } // Handle team competitions if (targetCompetition.type === "team" || targetCompetition.type === "mixed") { targetCompetition.participatingTeams.forEach((teamId) => { const team = getTeamById(teamId) if (team) { // Calculate team score based on their apps let totalScore = 0 let appCount = 0 team.apps.forEach((appId) => { const appScore = getAppDetailedScores(appId) totalScore += appScore.total appCount++ }) const averageScore = appCount > 0 ? totalScore / appCount : 0 rankings.push({ teamId, teamName: team.name, creator: `${team.members.find((m) => m.id === team.leader)?.name}團隊`, totalScore: averageScore, scores: { teamwork: averageScore * 0.25, technical: averageScore * 0.25, innovation: averageScore * 0.25, practical: averageScore * 0.25, }, rank: 0, competitionType: "team" as const, appCount: team.apps.length, totalLikes: team.totalLikes, members: team.members, }) } }) } // Handle proposal competitions if (targetCompetition.type === "proposal" || targetCompetition.type === "mixed") { targetCompetition.participatingProposals.forEach((proposalId) => { const proposal = getProposalById(proposalId) const detailedScores = getProposalDetailedScores(proposalId) if (proposal) { const team = getTeamById(proposal.teamId) rankings.push({ proposalId, proposalTitle: proposal.title, creator: team?.name || "未知團隊", totalScore: detailedScores.total, scores: { problemIdentification: detailedScores.problemIdentification, solutionFeasibility: detailedScores.solutionFeasibility, innovation: detailedScores.innovation, impact: detailedScores.impact, presentation: detailedScores.presentation, }, rank: 0, competitionType: "proposal" as const, proposal, team, }) } }) } // Sort by total score and assign ranks within each competition type const individualRankings = rankings .filter((r) => r.competitionType === "individual") .sort((a, b) => b.totalScore - a.totalScore) .map((item, index) => ({ ...item, rank: index + 1 })) const teamRankings = rankings .filter((r) => r.competitionType === "team") .sort((a, b) => b.totalScore - a.totalScore) .map((item, index) => ({ ...item, rank: index + 1 })) const proposalRankings = rankings .filter((r) => r.competitionType === "proposal") .sort((a, b) => b.totalScore - a.totalScore) .map((item, index) => ({ ...item, rank: index + 1 })) // Combine all rankings return [...individualRankings, ...teamRankings, ...proposalRankings] } // Add new filtering functions const getAwardsByCompetitionType = (competitionType?: string) => { if (!competitionType || competitionType === "all") return awards return awards.filter((award) => award.competitionType === competitionType) } const getAwardsByCategory = (category?: string) => { if (!category || category === "all") return awards return awards.filter((award) => award.category === category) } const getTopRankingAwards = () => { return awards.filter((award) => award.rank > 0 && award.rank <= 3) } const getPopularityAwards = () => { return awards.filter((award) => award.awardType === "popular") } const getPopularityRankings = (competitionId?: string) => { const targetCompetition = competitionId ? competitions.find((c) => c.id === competitionId) : currentCompetition if (!targetCompetition) return [] const rankings: any[] = [] // Get participants based on competition type const participants = targetCompetition.type === "individual" ? targetCompetition.participatingApps : targetCompetition.type === "team" ? targetCompetition.participatingTeams : targetCompetition.participatingProposals // For each participant, calculate popularity based on likes participants.forEach((participantId) => { const appNames: Record = { "1": "智能對話助手", "2": "圖像生成工具", "3": "語音識別系統", "4": "智能推薦引擎", "5": "文本分析器", "6": "AI創意寫作", } const creators: Record = { "1": "張小明", "2": "李美華", "3": "王大偉", "4": "陳小芳", "5": "劉志強", "6": "黃小玲", } const departments: Record = { "1": "HQBU", "2": "ITBU", "3": "MBU1", "4": "SBU", "5": "HQBU", "6": "ITBU", } const types: Record = { "1": "文字處理", "2": "圖像生成", "3": "語音辨識", "4": "推薦系統", "5": "文字處理", "6": "文字處理", } // Get likes from appLikesCounter const likes = appLikesCounter[participantId] || 0 rankings.push({ id: participantId, name: appNames[participantId] || `應用 ${participantId}`, creator: creators[participantId] || "未知", department: departments[participantId] || "未知", type: types[participantId] || "未知", likes: likes, rank: 0, // Will be calculated after sorting }) }) // Sort by likes and assign ranks return rankings.sort((a, b) => b.likes - a.likes).map((item, index) => ({ ...item, rank: index + 1 })) } // Add these functions to the context value return ( {children} ) } export function useCompetition() { const context = useContext(CompetitionContext) if (context === undefined) { throw new Error("useCompetition must be used within a CompetitionProvider") } return context }