import { useState, useCallback } from 'react'; import { MOCK_EVENTS, MOCK_POLLS } from '../../data/mockData'; import { useAuth } from '../../contexts/AuthContext'; import { formatDateTime } from '../../utils/format'; import type { EventPost, EventType, Poll, UserRole } from '../../types'; const EVENT_TYPE_COLORS: Record = { announcement: 'var(--color-yellow)', update: 'var(--color-blue)', milestone: 'var(--color-green)', poll: 'var(--color-amber)', }; const EVENT_TYPE_LABELS: Record = { announcement: 'ANNOUNCEMENT', update: 'DEV UPDATE', milestone: 'MILESTONE', poll: 'COMMUNITY POLL', }; const ROLE_COLORS: Record = { dev: 'var(--color-green)', com: 'var(--color-amber)', user: 'var(--color-text-muted)', }; // ── Poll Component ───────────────────────────────────────────────────────────── function PollCard({ poll, onVote }: { poll: Poll; onVote: (pollId: string, optionId: string) => void }) { const { user } = useAuth(); const totalVotes = poll.options.reduce((sum, opt) => sum + opt.votes, 0); const isEnded = poll.endsAt ? new Date(poll.endsAt) < new Date() : false; return (
{poll.question}
{poll.options.map((option) => { const percentage = totalVotes > 0 ? Math.round((option.votes / totalVotes) * 100) : 0; const userVoted = option.votedUserIds.includes(user?.id || ''); return (
{ if (!isEnded && poll.isActive && user) { onVote(poll.id, option.id); } }} > {/* Progress bar */}
{userVoted && '✓ '} {option.text} {option.votes} ({percentage}%)
); })}
{totalVotes} total vote{totalVotes !== 1 ? 's' : ''} {poll.allowMultipleVotes && ' • Multiple votes allowed'} {poll.endsAt && ( {isEnded ? 'Poll Ended' : `Ends ${formatDateTime(poll.endsAt)}`} )}
{!user && !isEnded && poll.isActive && (
Please log in to vote
)}
); } // ── Event Card Component ─────────────────────────────────────────────────────── function EventCard({ event, poll, onVote, }: { event: EventPost; poll?: Poll; onVote: (pollId: string, optionId: string) => void; }) { return (
{/* Header */}
{EVENT_TYPE_LABELS[event.type]}

{event.title}

{event.authorName} {formatDateTime(event.createdAt)}
{/* Content */}
{event.content}
{/* Poll if exists */} {poll && }
); } // ── Main Component ───────────────────────────────────────────────────────────── export default function EventsPage() { const { user } = useAuth(); // Filter to show only public events const publicEvents = MOCK_EVENTS.filter((event) => event.isPublic); const [events] = useState(publicEvents); const [polls, setPolls] = useState(MOCK_POLLS); const handleVote = useCallback( (pollId: string, optionId: string) => { if (!user) return; setPolls((prevPolls) => prevPolls.map((poll) => { if (poll.id !== pollId) return poll; const hasVotedForOption = poll.options.some((opt) => opt.votedUserIds.includes(user.id) ); return { ...poll, options: poll.options.map((opt) => { if (opt.id === optionId) { // Add vote to this option return { ...opt, votes: opt.votedUserIds.includes(user.id) ? opt.votes : opt.votes + 1, votedUserIds: opt.votedUserIds.includes(user.id) ? opt.votedUserIds : [...opt.votedUserIds, user.id], }; } else if (!poll.allowMultipleVotes && hasVotedForOption) { // Remove vote from other options if single vote return { ...opt, votes: opt.votedUserIds.includes(user.id) ? opt.votes - 1 : opt.votes, votedUserIds: opt.votedUserIds.filter((id) => id !== user.id), }; } return opt; }), }; }) ); }, [user] ); return (
{/* Header */}
DEVELOPMENT UPDATES

COMMUNITY EVENTS

Stay up to date with the latest game development news, announcements, and participate in community polls to help shape the future of Headless Hazard.

{/* Events Grid */}
{events.length === 0 ? (
No events available at the moment. Check back soon!
) : ( events.map((event) => { const poll = event.pollId ? polls.find((p) => p.id === event.pollId) : undefined; return ; }) )}
); }