"use client"; import React, { useState, useEffect } from "react"; import { useParams, useRouter } from "next/navigation"; import Link from "next/link"; import { Button } from "@/components/ui/Button"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/Card"; interface Activity { id: string; title: string; description: string | null; sportType: string; skillLevel: string; date: string; duration: number; maxParticipants: number; currentParticipants: number; status: string; location: string; locationName: string | null; latitude: number | null; longitude: number | null; gender: string; minAge: number; maxAge: number; price: number; isRecurring: boolean; recurrenceFrequency: string; recurrenceDays: number[]; recurrenceEndDate: string | null; parentActivityId: string | null; venue?: { id: string; name: string; city: string; address: string; latitude: number | null; longitude: number | null; } | null; organizer: { id: string; name: string; email: string; image: string | null; }; participations: { id: string; guestCount: number; user: { id: string; name: string; image: string | null; }; }[]; } const sportTypeLabels: Record = { FOOTBALL: "⚽ Futbal", BASKETBALL: "🏀 Basketbal", TENNIS: "🎾 Tenis", VOLLEYBALL: "🏐 Volejbal", BADMINTON: "🏸 Bedminton", TABLE_TENNIS: "🏓 Stolný tenis", RUNNING: "🏃 Beh", CYCLING: "🚴 Cyklistika", SWIMMING: "🏊 Plávanie", GYM: "💪 Posilňovňa", OTHER: "🎯 Iné", }; const skillLevelLabels: Record = { BEGINNER: "Začiatočník", INTERMEDIATE: "Mierne pokročilý", ADVANCED: "Pokročilý", EXPERT: "Expert", }; const genderLabels: Record = { MALE: "Muži", FEMALE: "Ženy", MIXED: "Zmiešané", }; const statusLabels: Record = { OPEN: { label: "Otvorená", color: "bg-green-500" }, FULL: { label: "Plná", color: "bg-orange-500" }, CANCELLED: { label: "Zrušená", color: "bg-red-500" }, COMPLETED: { label: "Ukončená", color: "bg-gray-500" }, }; export default function ActivityDetailPage() { const params = useParams(); const router = useRouter(); const [activity, setActivity] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [joining, setJoining] = useState(false); const [leaving, setLeaving] = useState(false); const [deleting, setDeleting] = useState(false); const [currentUserId, setCurrentUserId] = useState(null); const [guestCount, setGuestCount] = useState(1); const [addingGuests, setAddingGuests] = useState(false); const [upcomingInstances, setUpcomingInstances] = useState([]); const [loadingUpcoming, setLoadingUpcoming] = useState(false); const [showUpcoming, setShowUpcoming] = useState(false); const [returnUrl, setReturnUrl] = useState("/activities"); useEffect(() => { // Check if we came from my-activities page via referrer or sessionStorage if (typeof window !== "undefined") { const savedSource = sessionStorage.getItem("activityListSource"); if (savedSource === "/my-activities") { setReturnUrl("/my-activities"); } else if (document.referrer && document.referrer.includes("/my-activities")) { setReturnUrl("/my-activities"); } } }, []); useEffect(() => { fetchActivity(); fetchCurrentUser(); }, [params.id]); useEffect(() => { // Update guest count when activity changes if (activity && currentUserId) { const participation = activity.participations.find(p => p.user.id === currentUserId); if (participation) { setGuestCount(participation.guestCount || 0); } } // Fetch upcoming instances if recurring (including child activities) if (activity) { const isRecurringOrChild = (activity.isRecurring && activity.recurrenceFrequency !== "NONE") || activity.parentActivityId; if (isRecurringOrChild) { fetchUpcomingInstances(); } } }, [activity, currentUserId]); const fetchCurrentUser = async () => { try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/profile`, { credentials: "include", } ); if (response.ok) { const data = await response.json(); setCurrentUserId(data.id); } } catch (err) { console.error("Error fetching user:", err); } }; const fetchActivity = async () => { try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${params.id}` ); if (!response.ok) { throw new Error("Aktivita nenájdená"); } const data = await response.json(); setActivity(data); } catch (err: any) { setError(err.message); } finally { setLoading(false); } }; const fetchUpcomingInstances = async () => { setLoadingUpcoming(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${params.id}/upcoming` ); if (response.ok) { const data = await response.json(); setUpcomingInstances(data); // Don't auto-expand, keep collapsed by default } } catch (err) { console.error("Error fetching upcoming instances:", err); } finally { setLoadingUpcoming(false); } }; const handleJoin = async () => { if (!activity) return; setJoining(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${activity.id}/join`, { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ guestCount: 0 }), } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Chyba pri prihlásení"); } // Refresh activity data await fetchActivity(); } catch (err: any) { alert(err.message); } finally { setJoining(false); } }; const handleLeave = async () => { if (!activity) return; const confirmLeave = window.confirm( "Naozaj sa chcete odhlásiť z tejto aktivity?" ); if (!confirmLeave) return; setLeaving(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${activity.id}/join`, { method: "DELETE", credentials: "include", } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Chyba pri odhlásení"); } // Refresh activity data await fetchActivity(); } catch (err: any) { alert(err.message); } finally { setLeaving(false); } }; const handleAddGuests = async () => { if (!activity) return; const currentParticipation = activity.participations.find(p => p.user.id === currentUserId); const currentGuestCount = currentParticipation?.guestCount || 0; const totalNeeded = 1 + guestCount; // user + guests const currentTotal = 1 + currentGuestCount; // current user + current guests const availableSpots = activity.maxParticipants - activity.currentParticipants + currentTotal; if (totalNeeded > availableSpots) { alert(`K dispozícii je len ${availableSpots} voľných miest.`); return; } setAddingGuests(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${activity.id}/join`, { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ guestCount }), } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Chyba pri aktualizácii počtu hostí"); } // Refresh activity data await fetchActivity(); alert(`Počet hostí aktualizovaný na ${guestCount}!`); } catch (err: any) { alert(err.message); } finally { setAddingGuests(false); } }; const handleDelete = async () => { if (!activity) return; const confirmDelete = window.confirm( "Naozaj chcete zmazať túto aktivitu? Táto akcia je nevratná." ); if (!confirmDelete) return; setDeleting(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/activities/${activity.id}`, { method: "DELETE", credentials: "include", } ); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Chyba pri mazaní aktivity"); } alert("Aktivita bola úspešne zmazaná"); router.push(returnUrl); } catch (err: any) { alert(err.message); } finally { setDeleting(false); } }; if (loading) { return (

Načítavam...

); } if (error || !activity) { return (

{error || "Aktivita nenájdená"}

); } const date = new Date(activity.date); const formattedDate = date.toLocaleDateString("sk-SK", { day: "numeric", month: "long", year: "numeric", }); const formattedTime = date.toLocaleTimeString("sk-SK", { hour: "2-digit", minute: "2-digit", }); const isParticipating = activity.participations.some( (p) => p.user.id === currentUserId ); const isOrganizer = activity.organizer.id === currentUserId; const canJoin = !isParticipating && activity.status === "OPEN" && activity.currentParticipants < activity.maxParticipants; const fillPercentage = (activity.currentParticipants / activity.maxParticipants) * 100; const statusInfo = statusLabels[activity.status] || statusLabels.OPEN; return (
{/* Back button */} {/* Header */}

{activity.title}

{sportTypeLabels[activity.sportType] || activity.sportType}

{activity.isRecurring && activity.recurrenceFrequency !== "NONE" && ( Pravidelná aktivita )}
{statusInfo.label}
{/* Action buttons */}
{canJoin && ( )} {isParticipating && ( )} {isOrganizer && ( <> 👤 Organizátor )}
{/* Add guests section for participants */} {isParticipating && activity.status === "OPEN" && (
p.user.id === currentUserId)?.guestCount || 0)} value={guestCount} onChange={(e) => setGuestCount(Math.max(0, parseInt(e.target.value) || 0))} className="w-full px-4 py-2 border border-[color:var(--fluent-border)] rounded-lg bg-[color:var(--fluent-card-background)] text-[color:var(--fluent-text)] focus:outline-none focus:ring-2 focus:ring-blue-500" />

Celkom miest: Vy + {guestCount} {guestCount === 1 ? "hosť" : guestCount < 5 ? "hostia" : "hostí"} = {1 + guestCount}

)}
{/* Main info */}
{/* Details */} Informácie o aktivite

Dátum a čas

📅 {formattedDate} o {formattedTime}

Dĺžka trvania

🕐 {activity.duration} minút

Miesto konania

{activity.locationName && (

📍 {activity.locationName}

)}

{activity.location}

{(activity.locationName || activity.location || (activity.latitude && activity.longitude)) && ( Otvoriť v Mapách )}

Úroveň hráčov

{skillLevelLabels[activity.skillLevel] || activity.skillLevel}

Pohlavie

{genderLabels[activity.gender] || activity.gender}

Vekové rozpätie

{activity.minAge} - {activity.maxAge} rokov

{activity.price > 0 && (

Cena

{activity.price.toFixed(2)} €

)} {activity.description && (

Popis

{activity.description}

)}
{/* Upcoming instances for recurring activities */} {((activity.isRecurring && activity.recurrenceFrequency !== "NONE") || activity.parentActivityId) && ( setShowUpcoming(!showUpcoming)} >
Nadchádzajúce termíny {upcomingInstances.length > 0 && ( {upcomingInstances.length} )}
{showUpcoming && ( {loadingUpcoming ? (

Načítavam...

) : upcomingInstances.length === 0 ? (

Žiadne nadchádzajúce termíny

) : (
{upcomingInstances.map((instance) => { const instanceDate = new Date(instance.date); const formattedDate = instanceDate.toLocaleDateString("sk-SK", { day: "numeric", month: "short", year: "numeric", }); const formattedTime = instanceDate.toLocaleTimeString("sk-SK", { hour: "2-digit", minute: "2-digit", }); const isCurrentActivity = instance.id === activity.id; const isParticipatingInInstance = instance.participations.some( (p) => p.user.id === currentUserId ); return (
{instanceDate.getDate()}
{instanceDate.toLocaleDateString("sk-SK", { month: "short" })}

{formattedDate} o {formattedTime}

{instance.currentParticipants}/{instance.maxParticipants} účastníkov

{isCurrentActivity && ( Aktuálny termín )}
{!isCurrentActivity && ( )} {!isParticipatingInInstance && instance.currentParticipants < instance.maxParticipants && ( )} {isParticipatingInInstance && ( Prihlásený )}
); })}
)}
)}
)} {/* Map */} {activity.latitude && activity.longitude && ( Mapa
)}
{/* Sidebar */}
{/* Participants progress */} Obsadenosť
Účastníci {activity.currentParticipants}/{activity.maxParticipants}

{activity.maxParticipants - activity.currentParticipants}{" "} voľných miest

{/* Organizer */} Organizátor
{activity.organizer.name.charAt(0).toUpperCase()}

{activity.organizer.name}

{activity.organizer.email}

{/* Participants list */} Prihlásení účastníci
{activity.participations.map((participation) => (
{participation.user.name.charAt(0).toUpperCase()}

{participation.user.name} {participation.guestCount > 0 && ( +{participation.guestCount} )} {participation.user.id === activity.organizer.id && ( (Organizátor) )}

))}
); }