103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
// components/TeamCard.tsx
|
|
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import Button from './Button'
|
|
import { Team, Player } from '../types/team'
|
|
import { useLiveTeam } from '../hooks/useLiveTeam'
|
|
|
|
type Props = {
|
|
team: Team
|
|
currentUserSteamId: string
|
|
invitationId?: string
|
|
onUpdateInvitation: (teamId: string, newValue: string | null) => void
|
|
}
|
|
|
|
export default function TeamCard({ team, currentUserSteamId, invitationId, onUpdateInvitation }: Props) {
|
|
const [joining, setJoining] = useState(false)
|
|
const data = useLiveTeam(team)
|
|
|
|
if (!data || !data.players) {
|
|
return <p className="text-sm text-gray-400">Lade Team …</p>
|
|
}
|
|
|
|
|
|
const handleClick = async () => {
|
|
if (joining) return
|
|
setJoining(true)
|
|
|
|
try {
|
|
if (invitationId) {
|
|
await fetch('/api/user/invitations/reject', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ invitationId }),
|
|
})
|
|
onUpdateInvitation(data.id, null)
|
|
} else {
|
|
const res = await fetch('/api/team/request-join', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ teamId: data.id }),
|
|
})
|
|
if (!res.ok) throw new Error()
|
|
onUpdateInvitation(data.id, 'dummy-id') // ← bei Bedarf mit realer ID aktualisieren
|
|
}
|
|
} catch (err) {
|
|
console.error('Fehler bei Join/Reject:', err)
|
|
} finally {
|
|
setJoining(false)
|
|
}
|
|
}
|
|
|
|
const isRequested = !!invitationId
|
|
const isDisabled = joining || currentUserSteamId === data.leader
|
|
|
|
return (
|
|
<div className="p-4 border rounded-lg bg-white dark:bg-neutral-800 dark:border-neutral-700 shadow-sm hover:shadow-md transition cursor-pointer">
|
|
<div className="flex items-center justify-between gap-3 mb-3">
|
|
<div className="flex items-center gap-3">
|
|
<img
|
|
src={data.logo ? `/assets/img/logos/${data.logo}` : '/assets/img/logos/placeholder.png'}
|
|
alt={data.teamname ?? 'Teamlogo'}
|
|
className="w-12 h-12 rounded-full object-cover border border-gray-200 dark:border-neutral-600"
|
|
/>
|
|
<span className="font-medium truncate text-gray-500 dark:text-neutral-400">
|
|
{data.teamname ?? 'Team'}
|
|
</span>
|
|
</div>
|
|
|
|
<Button
|
|
title={isRequested ? 'Angefragt (zurückziehen)' : 'Beitreten'}
|
|
size="sm"
|
|
color={isRequested ? 'gray' : 'blue'}
|
|
disabled={isDisabled}
|
|
onClick={(e: any) => {
|
|
e.stopPropagation()
|
|
handleClick()
|
|
}}
|
|
>
|
|
{joining ? '...' : isRequested ? 'Angefragt' : 'Beitreten'}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="flex -space-x-3">
|
|
{data.players.slice(0, 5).map((p) => (
|
|
<img
|
|
key={p.steamId}
|
|
src={p.avatar}
|
|
alt={p.name}
|
|
title={p.name}
|
|
className="w-8 h-8 rounded-full border-2 border-white dark:border-neutral-800 object-cover"
|
|
/>
|
|
))}
|
|
{data.players.length > 5 && (
|
|
<span className="w-8 h-8 flex items-center justify-center rounded-full bg-gray-200 text-xs">
|
|
+{data.players.length - 5}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|