139 lines
4.2 KiB
TypeScript
139 lines
4.2 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import Button from './Button'
|
|
import TeamPremierRankBadge from './TeamPremierRankBadge'
|
|
import type { Team } from '../types/team'
|
|
|
|
type Props = {
|
|
team: Team
|
|
currentUserSteamId: string
|
|
invitationId?: string
|
|
onUpdateInvitation: (teamId: string, newValue: string | null | 'pending') => void
|
|
adminMode?: boolean
|
|
}
|
|
|
|
export default function TeamCard({
|
|
team,
|
|
currentUserSteamId,
|
|
invitationId,
|
|
onUpdateInvitation,
|
|
adminMode = false,
|
|
}: Props) {
|
|
const router = useRouter()
|
|
const [joining, setJoining] = useState(false)
|
|
|
|
const isRequested = Boolean(invitationId)
|
|
const isDisabled = joining || currentUserSteamId === team.leader?.steamId
|
|
|
|
const handleClick = async () => {
|
|
if (joining) return
|
|
setJoining(true)
|
|
try {
|
|
if (isRequested) {
|
|
await fetch('/api/user/invitations/reject', {
|
|
method : 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body : JSON.stringify({ invitationId }),
|
|
})
|
|
onUpdateInvitation(team.id, null)
|
|
} else {
|
|
await fetch('/api/team/request-join', {
|
|
method : 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body : JSON.stringify({ teamId: team.id }),
|
|
})
|
|
onUpdateInvitation(team.id, 'pending')
|
|
}
|
|
} catch (err) {
|
|
console.error('[TeamCard] Join/Reject-Fehler:', err)
|
|
} finally {
|
|
setJoining(false)
|
|
}
|
|
}
|
|
|
|
const targetHref = adminMode ? `/admin/teams/${team.id}` : `/team/${team.id}`
|
|
|
|
return (
|
|
<div
|
|
role="button"
|
|
tabIndex={0}
|
|
onClick={() => router.push(targetHref)}
|
|
onKeyDown={e => (e.key === 'Enter') && router.push(targetHref)}
|
|
className="p-4 border rounded-lg bg-white dark:bg-neutral-800
|
|
dark:border-neutral-700 shadow-sm hover:shadow-md
|
|
transition cursor-pointer focus:outline-none
|
|
hover:scale-105 hover:bg-neutral-200 hover:dark:bg-neutral-700"
|
|
>
|
|
<div className="flex items-center justify-between gap-3 mb-3">
|
|
<div className="flex items-center gap-3">
|
|
<img
|
|
src={team.logo ? `/assets/img/logos/${team.logo}` : `/assets/img/logos/cs2.webp`}
|
|
alt={team.name ?? 'Teamlogo'}
|
|
className="w-12 h-12 rounded-full object-cover border
|
|
border-gray-200 dark:border-neutral-600"
|
|
/>
|
|
<div className="flex items-center gap-2">
|
|
<span className="font-medium truncate text-gray-800 dark:text-neutral-200">
|
|
{team.name ?? 'Team'}
|
|
</span>
|
|
<TeamPremierRankBadge players={team.activePlayers} />
|
|
</div>
|
|
</div>
|
|
|
|
{adminMode ? (
|
|
<Button
|
|
title="Verwalten"
|
|
size="md"
|
|
color="blue"
|
|
variant="solid"
|
|
onClick={e => {
|
|
e.stopPropagation()
|
|
router.push(`/admin/teams/${team.id}`)
|
|
}}
|
|
>
|
|
Verwalten
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
title={isRequested ? 'Angefragt (zurückziehen)' : 'Beitritt anfragen'}
|
|
size="sm"
|
|
color={isRequested ? 'gray' : 'blue'}
|
|
disabled={isDisabled}
|
|
onClick={e => { e.stopPropagation(); handleClick() }}
|
|
>
|
|
{joining ? (
|
|
<>
|
|
<span
|
|
className="animate-spin inline-block size-4 border-[3px] border-current border-t-transparent rounded-full mr-1"
|
|
role="status"
|
|
aria-label="loading"
|
|
/>
|
|
Lädt
|
|
</>
|
|
) : isRequested ? (
|
|
'Angefragt'
|
|
) : (
|
|
'Beitritt anfragen'
|
|
)}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex -space-x-3">
|
|
{[...team.activePlayers, ...team.inactivePlayers].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"
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|