"use client" import { useState } from "react" import useSWR from "swr" import { Clock, Calendar as CalendarIcon, DoorClosed, Users, Check, X, HelpCircle, Trash2, CheckCircle2, Ban, Loader2, } from "lucide-react" import { GlassModal } from "./glass-modal" import * as api from "@/lib/api" import { ApiError } from "@/lib/api" import type { CalendarEvent, Room, SignupStatus } from "@/lib/types" import { getRoomColor } from "@/lib/room-theme" import { parseDateTime, formatDayLabel, formatTime } from "@/lib/date-utils" interface EventDetailDialogProps { event: CalendarEvent room?: Room currentUserId: number onClose: () => void onChanged: () => void } const STATUS_STYLES: Record = { confirmed: "bg-emerald-500/30 text-emerald-100 border-emerald-400/40", proposed: "bg-amber-500/30 text-amber-100 border-amber-400/40", draft: "bg-white/20 text-white border-white/30", cancelled: "bg-red-500/30 text-red-100 border-red-400/40", } export function EventDetailDialog({ event, room, currentUserId, onClose, onChanged, }: EventDetailDialogProps) { const [busy, setBusy] = useState(null) const [error, setError] = useState(null) const [deleteConfirming, setDeleteConfirming] = useState(false) const { data: responses, mutate: mutateResponses } = useSWR( ["responses", event.id], () => api.getEventResponses(event.id), ) const start = parseDateTime(event.start_time) const end = parseDateTime(event.end_time) const color = getRoomColor(event.room_id) const canManage = event.creator_id === currentUserId || room?.role === "admin" || room?.role === "owner" const myResponse = responses?.find((r) => r.user_id === currentUserId)?.status const goingCount = responses?.filter((r) => r.status === "going").length ?? 0 const maybeCount = responses?.filter((r) => r.status === "maybe").length ?? 0 const declinedCount = responses?.filter((r) => r.status === "declined").length ?? 0 const run = async (key: string, fn: () => Promise, refetchResponses = false) => { setBusy(key) setError(null) try { await fn() if (refetchResponses) await mutateResponses() onChanged() } catch (err) { setError(err instanceof ApiError ? err.message : "Action failed.") } finally { setBusy(null) } } const respond = (status: SignupStatus) => run(`respond-${status}`, () => api.respondToEvent(event.id, status), true) const rsvpButtons: { status: SignupStatus; label: string; icon: typeof Check }[] = [ { status: "going", label: "Going", icon: Check }, { status: "maybe", label: "Maybe", icon: HelpCircle }, { status: "declined", label: "Can't go", icon: X }, ] return (
{room?.name ?? `Room #${event.room_id}`} {event.status}

{formatDayLabel(start)}

{formatTime(start)} – {formatTime(end)}

{event.type} · {event.visibility.replace("_", " ")}

{event.type === "proposal" && (

{goingCount} going · needs {event.min_people}

)}
{event.description && (

{event.description}

)} {/* RSVP */} {event.status !== "cancelled" && (

Your response

{rsvpButtons.map(({ status, label, icon: Icon }) => { const active = myResponse === status return ( ) })}

{goingCount} going · {maybeCount} maybe · {declinedCount} declined

)} {error && (
{error}
)} {/* Management actions */} {canManage && (
{event.status !== "confirmed" && event.status !== "cancelled" && ( )} {event.status !== "cancelled" && ( )}
{/* Delete lives in its own fixed spot, separate from Confirm/Cancel, so its position never shifts depending on which of those show. */}
{!deleteConfirming ? ( ) : (

Weet je zeker dat je dit evenement wilt verwijderen? Dit kan niet ongedaan worden gemaakt.

{/* Destructive action sits on top, off the "usual" spot. */} {/* Safe action sits below, in the spot people click fast out of habit. */}
)}
)}
) }