ironie-nextjs/src/app/admin/teams/[teamId]/TeamAdminClient.tsx
2025-09-20 21:28:10 +02:00

101 lines
3.2 KiB
TypeScript

// /src/app/(admin)/admin/teams/[teamId]/TeamAdminClient.tsx
'use client'
import { useCallback, useEffect, useState, useRef } from 'react'
import { useSession } from 'next-auth/react'
import LoadingSpinner from '@/app/components/LoadingSpinner'
import TeamMemberView from '@/app/components/TeamMemberView'
import { useTeamStore } from '@/app/lib/stores'
import { reloadTeam } from '@/app/lib/sse-actions'
import type { Player } from '@/app/types/team'
type Props = { teamId: string }
export default function TeamAdminClient({ teamId }: Props) {
const { team, setTeam } = useTeamStore()
const { data: session } = useSession()
const currentUserSteamId = session?.user?.steamId || ''
const [loading, setLoading] = useState(true)
const [activeDragItem, setActiveDragItem] = useState<Player | null>(null)
const [isDragging, setIsDragging] = useState(false)
const [showLeaveModal, setShowLeaveModal] = useState(false)
const [showInviteModal, setShowInviteModal] = useState(false)
const fetchTeam = useCallback(async () => {
const result = await reloadTeam(teamId)
if (result) setTeam(result)
setLoading(false)
}, [teamId, setTeam])
useEffect(() => {
if (teamId) fetchTeam()
}, [teamId, fetchTeam])
// 👇 WICHTIG: subscribe by steamId (passt zu deinem SSE-Server)
useEffect(() => {
const steamId = session?.user?.steamId
if (!steamId) return
// ggf. .env nutzen: z. B. NEXT_PUBLIC_SSE_URL=http://localhost:3001
const base = process.env.NEXT_PUBLIC_SSE_URL ?? 'http://localhost:3001'
const url = `${base}/events?steamId=${encodeURIComponent(steamId)}`
let es: EventSource | null = new EventSource(url, { withCredentials: false })
const onTeamUpdated = (ev: MessageEvent) => {
try {
const msg = JSON.parse(ev.data)
if (msg.teamId === teamId) {
fetchTeam()
}
} catch (e) {
console.error('[SSE] parse error:', e)
}
}
es.addEventListener('team-updated', onTeamUpdated)
es.onerror = () => {
// sanftes Reconnect
es?.close()
es = null
setTimeout(() => {
// neuer EventSource
const next = new EventSource(url, { withCredentials: false })
next.addEventListener('team-updated', onTeamUpdated)
next.onerror = () => { next.close() }
es = next
}, 2000)
}
return () => {
es?.removeEventListener('team-updated', onTeamUpdated as any)
es?.close()
}
}, [session?.user?.steamId, teamId, fetchTeam])
if (loading || !team) return <LoadingSpinner />
return (
<div className="mx-auto">
<TeamMemberView
key={
team
? `${team.id}|A:${team.activePlayers.map(p=>p.steamId).join(',')}|I:${team.inactivePlayers.map(p=>p.steamId).join(',')}|V:${team.invitedPlayers.map(p=>p.steamId).join(',')}`
: 'no-team'
}
currentUserSteamId={currentUserSteamId}
adminMode
activeDragItem={activeDragItem}
isDragging={isDragging}
showLeaveModal={showLeaveModal}
showInviteModal={showInviteModal}
setShowLeaveModal={setShowLeaveModal}
setShowInviteModal={setShowInviteModal}
setActiveDragItem={setActiveDragItem}
setIsDragging={setIsDragging}
/>
</div>
)
}