update
This commit is contained in:
parent
237be94ebe
commit
6543210eba
@ -159,6 +159,9 @@
|
|||||||
schedule Schedule?
|
schedule Schedule?
|
||||||
|
|
||||||
readyAcceptances MatchReady[] @relation("MatchReadyMatch")
|
readyAcceptances MatchReady[] @relation("MatchReadyMatch")
|
||||||
|
|
||||||
|
cs2MatchId Int? // die in die JSON geschriebene matchid
|
||||||
|
exportedAt DateTime? // wann die JSON exportiert wurde
|
||||||
}
|
}
|
||||||
|
|
||||||
model MatchPlayer {
|
model MatchPlayer {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/admin/page.tsx
|
// /src/app/admin/page.tsx
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
export default function AdminRedirectPage() {
|
export default function AdminRedirectPage() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/(admin)/admin/teams/[teamId]/TeamAdminClient.tsx
|
// /src/app/(admin)/admin/teams/[teamId]/TeamAdminClient.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useEffect, useState, useRef } from 'react'
|
import { useCallback, useEffect, useState, useRef } from 'react'
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// /src/app/admin/teams/page.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import Card from '@/app/components/Card'
|
import Card from '@/app/components/Card'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/[id]/_builders.ts
|
// /src/app/api/matches/[id]/_builders.ts
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
|
|
||||||
/** Klein, konsistent, Frontend-freundlich */
|
/** Klein, konsistent, Frontend-freundlich */
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/[matchId]/mapvote/admin-edit/route.ts
|
// /src/app/api/matches/[matchId]/mapvote/admin-edit/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/[id]/mapvote/reset/route.ts
|
// /src/app/api/matches/[id]/mapvote/reset/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/[matchId]/mapvote/route.ts
|
// /src/app/api/matches/[matchId]/mapvote/route.ts
|
||||||
|
|
||||||
import { NextResponse, NextRequest } from 'next/server'
|
import { NextResponse, NextRequest } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
@ -22,6 +22,15 @@ const ACTION_MAP: Record<MapVoteAction, 'ban'|'pick'|'decider'> = {
|
|||||||
|
|
||||||
const sleep = (ms: number) => new Promise<void>(res => setTimeout(res, ms));
|
const sleep = (ms: number) => new Promise<void>(res => setTimeout(res, ms));
|
||||||
|
|
||||||
|
async function unloadCurrentMatch() {
|
||||||
|
// einige MatchZy Builds nutzen "matchzy_unloadmatch",
|
||||||
|
// andere trennen zwischen cancel/end. Der Unload reicht meist.
|
||||||
|
await sendServerCommand('matchzy_unloadmatch')
|
||||||
|
// optional „end/cancel“ hinterher, falls dein Build es erfordert:
|
||||||
|
// await sendServerCommand('matchzy_cancelmatch')
|
||||||
|
await sleep(500) // Server eine halbe Sekunde Luft lassen
|
||||||
|
}
|
||||||
|
|
||||||
function makeRandomMatchId() {
|
function makeRandomMatchId() {
|
||||||
try {
|
try {
|
||||||
// 9–10-stellige ID (>= 100_000_000) – Obergrenze exklusiv
|
// 9–10-stellige ID (>= 100_000_000) – Obergrenze exklusiv
|
||||||
@ -361,6 +370,34 @@ function collectParticipants(match: any): string[] {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function persistMatchPlayers(match: any) {
|
||||||
|
// Teilnehmer ermitteln (du hast schon collectParticipants)
|
||||||
|
const participants = collectParticipants(match); // string[] der steamIds
|
||||||
|
|
||||||
|
// teamId pro Spieler bestimmen (A oder B), sonst null
|
||||||
|
const aIds = new Set((match.teamAUsers ?? []).map((u: any) => String(u?.steamId)).filter(Boolean));
|
||||||
|
const bIds = new Set((match.teamBUsers ?? []).map((u: any) => String(u?.steamId)).filter(Boolean));
|
||||||
|
|
||||||
|
const ops = participants.map((steamId) => {
|
||||||
|
const onTeamA = aIds.has(String(steamId));
|
||||||
|
const onTeamB = bIds.has(String(steamId));
|
||||||
|
const teamId =
|
||||||
|
onTeamA ? match.teamA?.id
|
||||||
|
: onTeamB ? match.teamB?.id
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Upsert je Spieler fürs Match
|
||||||
|
return prisma.matchPlayer.upsert({
|
||||||
|
where: { matchId_steamId: { matchId: match.id, steamId } },
|
||||||
|
update: { teamId }, // falls sich die Team-Zuordnung ändert
|
||||||
|
create: { matchId: match.id, steamId, teamId },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await prisma.$transaction(ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Export-Helfer ---------- */
|
/* ---------- Export-Helfer ---------- */
|
||||||
|
|
||||||
@ -452,10 +489,12 @@ async function exportMatchToSftpDirect(match: any, vote: any) {
|
|||||||
const chosen = (sLike.steps ?? []).filter(s => (s.action === 'pick' || s.action === 'decider') && s.map)
|
const chosen = (sLike.steps ?? []).filter(s => (s.action === 'pick' || s.action === 'decider') && s.map)
|
||||||
if (chosen.length < bestOf) return
|
if (chosen.length < bestOf) return
|
||||||
|
|
||||||
|
// ⬇️ JSON bauen (enthält cs2MatchId/rndId)
|
||||||
const json = buildMatchJson(mLike, sLike)
|
const json = buildMatchJson(mLike, sLike)
|
||||||
const jsonStr = JSON.stringify(json, null, 2)
|
const jsonStr = JSON.stringify(json, null, 2)
|
||||||
const filename = `${match.id}.json`
|
const filename = `${match.id}.json`
|
||||||
|
|
||||||
|
// --- SFTP Upload wie gehabt ---
|
||||||
const url = process.env.PTERO_SERVER_SFTP_URL || ''
|
const url = process.env.PTERO_SERVER_SFTP_URL || ''
|
||||||
const user = process.env.PTERO_SERVER_SFTP_USER
|
const user = process.env.PTERO_SERVER_SFTP_USER
|
||||||
const pass = process.env.PTERO_SERVER_SFTP_PASSWORD
|
const pass = process.env.PTERO_SERVER_SFTP_PASSWORD
|
||||||
@ -484,16 +523,46 @@ async function exportMatchToSftpDirect(match: any, vote: any) {
|
|||||||
|
|
||||||
console.log(`[mapvote] Export OK → ${remotePath}`)
|
console.log(`[mapvote] Export OK → ${remotePath}`)
|
||||||
|
|
||||||
// 👇 NACH ERFOLGREICHEM UPLOAD: Match in CS2-Plugin laden
|
// erst aktuelles Match beenden/entladen …
|
||||||
// Laut Vorgabe nur die JSON-Datei als Argument übergeben:
|
await unloadCurrentMatch()
|
||||||
|
|
||||||
|
// … dann das neue laden
|
||||||
await sendServerCommand(`matchzy_loadmatch ${filename}`)
|
await sendServerCommand(`matchzy_loadmatch ${filename}`)
|
||||||
// (Falls dein Plugin den absoluten Pfad erwartet, nimm stattdessen: `matchzy_loadmatch ${remotePath}`)
|
|
||||||
|
// Spieler persistieren + cs2MatchId speichern wie gehabt
|
||||||
|
await persistMatchPlayers(match)
|
||||||
|
if (typeof json.matchid === 'number') {
|
||||||
|
await prisma.match.update({
|
||||||
|
where: { id: match.id },
|
||||||
|
data: { cs2MatchId: json.matchid, exportedAt: new Date() },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await prisma.match.update({
|
||||||
|
where: { id: match.id },
|
||||||
|
data: { exportedAt: new Date() },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⬇️ OPTIONAL: cs2MatchId + exportedAt im Match speichern
|
||||||
|
if (typeof json.matchid === 'number') {
|
||||||
|
await prisma.match.update({
|
||||||
|
where: { id: match.id },
|
||||||
|
data: { cs2MatchId: json.matchid, exportedAt: new Date() },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await prisma.match.update({
|
||||||
|
where: { id: match.id },
|
||||||
|
data: { exportedAt: new Date() },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[mapvote] Export fehlgeschlagen:', err)
|
console.error('[mapvote] Export fehlgeschlagen:', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- kleine Helfer für match-ready Payload ---------- */
|
/* ---------- kleine Helfer für match-ready Payload ---------- */
|
||||||
|
|
||||||
function deriveChosenSteps(vote: any) {
|
function deriveChosenSteps(vote: any) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/[id]/route.ts
|
// /src/app/api/matches/[id]/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/matches/create/route.ts
|
// /src/app/api/matches/create/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { prisma } from '@/app/lib/prisma'
|
// /api/notifications/route.ts
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
|
||||||
export async function GET(req: NextRequest) {
|
export async function GET(req: NextRequest) {
|
||||||
const session = await getServerSession(authOptions(req))
|
const session = await getServerSession(authOptions(req))
|
||||||
@ -11,9 +12,19 @@ export async function GET(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const notifications = await prisma.notification.findMany({
|
const notifications = await prisma.notification.findMany({
|
||||||
where: { steamId: session.user.steamId },
|
where: {
|
||||||
|
steamId: session.user.steamId,
|
||||||
|
},
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
take: 10,
|
select: {
|
||||||
|
id: true,
|
||||||
|
title: true,
|
||||||
|
message: true,
|
||||||
|
read: true,
|
||||||
|
actionType: true,
|
||||||
|
actionData: true,
|
||||||
|
createdAt: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return NextResponse.json({ notifications })
|
return NextResponse.json({ notifications })
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
// /api/notifications/user/route.ts
|
|
||||||
import { getServerSession } from 'next-auth'
|
|
||||||
import { authOptions } from '@/app/lib/auth'
|
|
||||||
import { prisma } from '@/app/lib/prisma'
|
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
|
||||||
|
|
||||||
export async function GET(req: NextRequest) {
|
|
||||||
const session = await getServerSession(authOptions(req))
|
|
||||||
|
|
||||||
if (!session?.user?.steamId) {
|
|
||||||
return NextResponse.json({ message: 'Nicht eingeloggt' }, { status: 401 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifications = await prisma.notification.findMany({
|
|
||||||
where: {
|
|
||||||
steamId: session.user.steamId,
|
|
||||||
},
|
|
||||||
orderBy: { createdAt: 'desc' },
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
message: true,
|
|
||||||
read: true,
|
|
||||||
actionType: true,
|
|
||||||
actionData: true,
|
|
||||||
createdAt: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return NextResponse.json({ notifications })
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/schedule/route.ts
|
// /src/app/api/schedule/route.ts
|
||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/team/add-players/route.ts
|
// /src/app/api/team/add-players/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/team/delete/route.ts
|
// /src/app/api/team/delete/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/team/kick/route.ts
|
// /src/app/api/team/kick/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/team/leave/route.ts
|
// /src/app/api/team/leave/route.ts
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { removePlayerFromMatches } from '@/app/lib/removePlayerFromMatches'
|
import { removePlayerFromMatches } from '@/app/lib/removePlayerFromMatches'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/team/rename/route.ts
|
// /src/app/api/team/rename/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/team/request-join/route.ts
|
// /src/app/api/team/request-join/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/team/transfer-leader/route.ts
|
// /src/app/api/team/transfer-leader/route.ts
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
import { sendServerSSEMessage } from '@/app/lib/sse-server-client'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/teams/route.ts
|
// /src/app/api/teams/route.ts
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
import type { Player } from '@/app/types/team'
|
import type { Player } from '@/app/types/team'
|
||||||
@ -41,14 +41,16 @@ export async function GET() {
|
|||||||
id: t.id,
|
id: t.id,
|
||||||
name: t.name,
|
name: t.name,
|
||||||
logo: t.logo,
|
logo: t.logo,
|
||||||
leader: t.leaderId,
|
leaderId: t.leaderId,
|
||||||
createdAt: t.createdAt,
|
createdAt: t.createdAt,
|
||||||
activePlayers: t.activePlayers .map(id => byId[id]).filter(Boolean) as Player[],
|
activePlayers: t.activePlayers .map(id => byId[id]).filter(Boolean) as Player[],
|
||||||
inactivePlayers:t.inactivePlayers.map(id => byId[id]).filter(Boolean) as Player[],
|
inactivePlayers:t.inactivePlayers.map(id => byId[id]).filter(Boolean) as Player[],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// HIER: direkt das Array zurückgeben
|
return NextResponse.json(
|
||||||
return NextResponse.json(result, { headers: { 'Cache-Control': 'no-store' } })
|
{ items: result, hasMore: false },
|
||||||
|
{ headers: { 'Cache-Control': 'no-store' } }
|
||||||
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('GET /api/teams failed:', err)
|
console.error('GET /api/teams failed:', err)
|
||||||
return NextResponse.json({ message: 'Interner Serverfehler' }, { status: 500 })
|
return NextResponse.json({ message: 'Interner Serverfehler' }, { status: 500 })
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/api/user/[steamId]/matches/route.ts
|
// /src/app/api/user/[steamId]/matches/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/user/invitations/route.ts
|
// /src/app/api/user/invitations/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/api/user/route.ts
|
// /src/app/api/user/route.ts
|
||||||
import { NextResponse, type NextRequest } from 'next/server'
|
import { NextResponse, type NextRequest } from 'next/server'
|
||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/app/lib/auth'
|
import { authOptions } from '@/app/lib/auth'
|
||||||
|
|||||||
@ -10,7 +10,10 @@ type ButtonProps = {
|
|||||||
modalId?: string
|
modalId?: string
|
||||||
color?: 'blue' | 'red' | 'gray' | 'green' | 'teal' | 'transparent'
|
color?: 'blue' | 'red' | 'gray' | 'green' | 'teal' | 'transparent'
|
||||||
variant?: 'solid' | 'outline' | 'ghost' | 'soft' | 'white' | 'link'
|
variant?: 'solid' | 'outline' | 'ghost' | 'soft' | 'white' | 'link'
|
||||||
|
/** Steuert NUR Höhe/Abstände */
|
||||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'
|
||||||
|
/** Optionale Schriftgröße */
|
||||||
|
textSize?: 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl'
|
||||||
className?: string
|
className?: string
|
||||||
dropDirection?: 'up' | 'down' | 'auto'
|
dropDirection?: 'up' | 'down' | 'auto'
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
@ -27,6 +30,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
color = 'blue',
|
color = 'blue',
|
||||||
variant = 'solid',
|
variant = 'solid',
|
||||||
size = 'md',
|
size = 'md',
|
||||||
|
textSize = 'sm',
|
||||||
className,
|
className,
|
||||||
dropDirection = 'down',
|
dropDirection = 'down',
|
||||||
disabled = false,
|
disabled = false,
|
||||||
@ -49,18 +53,31 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
|
|
||||||
const sizeClasses: Record<string, string> = {
|
// Feste Höhen sorgen für vertikale Zentrierung
|
||||||
xs: 'py-1 px-2',
|
const sizeClasses: Record<NonNullable<ButtonProps['size']>, string> = {
|
||||||
sm: 'py-2 px-3',
|
xs: 'h-7 px-2',
|
||||||
md: 'py-3 px-4',
|
sm: 'h-8 px-3',
|
||||||
lg: 'p-4 sm:p-5',
|
md: 'h-9 px-4',
|
||||||
xl: 'py-6 px-8 text-lg',
|
lg: 'h-10 px-5',
|
||||||
full: 'py-6 px-8 text-lg w-full',
|
xl: 'h-12 px-6',
|
||||||
|
full: 'h-12 px-6 w-full',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur Textgröße
|
||||||
|
const textSizeClasses: Record<NonNullable<ButtonProps['textSize']>, string> = {
|
||||||
|
xs: 'text-xs',
|
||||||
|
sm: 'text-sm',
|
||||||
|
base: 'text-base',
|
||||||
|
lg: 'text-lg',
|
||||||
|
xl: 'text-xl',
|
||||||
|
'2xl': 'text-2xl',
|
||||||
|
'3xl': 'text-3xl',
|
||||||
}
|
}
|
||||||
|
|
||||||
const base = `
|
const base = `
|
||||||
${sizeClasses[size] || sizeClasses['md']}
|
${sizeClasses[size] || sizeClasses['md']}
|
||||||
inline-flex items-center gap-x-2 text-sm font-medium rounded-lg
|
inline-flex items-center gap-x-2 ${textSizeClasses[textSize] || 'text-sm'}
|
||||||
|
font-medium rounded-lg leading-none
|
||||||
focus:outline-hidden disabled:opacity-50 disabled:cursor-not-allowed
|
focus:outline-hidden disabled:opacity-50 disabled:cursor-not-allowed
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -79,15 +96,15 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
gray: 'border border-gray-200 text-gray-500 hover:border-gray-600 hover:text-gray-600 focus:border-gray-600 focus:text-gray-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
gray: 'border border-gray-200 text-gray-500 hover:border-gray-600 hover:text-gray-600 focus:border-gray-600 focus:text-gray-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
||||||
teal: 'border border-teal-200 text-teal-500 hover:border-teal-600 hover:text-teal-600 focus:border-teal-600 focus:text-teal-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
teal: 'border border-teal-200 text-teal-500 hover:border-teal-600 hover:text-teal-600 focus:border-teal-600 focus:text-teal-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
||||||
green: 'border border-green-200 text-green-500 hover:border-green-600 hover:text-green-600 focus:border-green-600 focus:text-green-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
green: 'border border-green-200 text-green-500 hover:border-green-600 hover:text-green-600 focus:border-green-600 focus:text-green-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
||||||
transparent: 'border border-transparent-200 text-transparent-500 hover:border-transparent-600 hover:text-transparent-600 focus:border-transparent-600 focus:text-transparent-600 dark:border-neutral-700 dark:text-neutral-400 dark:hover:text-white dark:hover:border-neutral-600 dark:focus:text-white dark:focus:border-neutral-600',
|
transparent: 'border border-white/20 bg-transparent text-white shadow-2xs hover:bg-white/15 focus:bg-white/15 dark:bg-transparent dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700/50 dark:focus:bg-neutral-700/50',
|
||||||
},
|
},
|
||||||
ghost: {
|
ghost: {
|
||||||
blue: 'border border-transparent text-blue-600 hover:bg-blue-100 hover:text-blue-800 focus:bg-blue-100 focus:text-blue-800 dark:text-blue-500 dark:hover:bg-blue-800/30 dark:hover:text-blue-400 dark:focus:bg-blue-800/30 dark:focus:text-blue-400',
|
blue: 'border border-transparent text-blue-600 hover:bg-blue-100 hover:text-blue-800 focus:bg-blue-100 focus:text-blue-800 dark:text-blue-500 dark:hover:bg-blue-800/30 dark:hover:text-blue-400 dark:focus:bg-blue-800/30 dark:focus:text-blue-400',
|
||||||
red: 'border border-transparent text-red-600 hover:bg-red-100 hover:text-red-800 focus:bg-red-100 focus:text-red-800 dark:text-red-500 dark:hover:bg-red-800/30 dark:hover:text-red-400 dark:focus:bg-red-800/30 dark:focus:text-red-400',
|
red: 'border border-transparent text-red-600 hover:bg-red-100 hover:text-red-800 focus:bg-red-100 focus:text-red-800 dark:text-red-500 dark:hover:bg-red-800/30 dark:hover:text-red-400 dark:focus:bg-red-800/30 dark:focus:text-red-400',
|
||||||
gray: 'border border-transparent text-gray-600 hover:bg-gray-100 hover:text-gray-800 focus:bg-gray-100 focus:text-gray-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
gray: 'border border-transparent text-gray-600 hover:bg-gray-100 hover:text-gray-800 focus:bg-gray-100 focus:text-gray-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
||||||
teal: 'border border-transparent text-teal-600 hover:bg-teal-100 hover:text-teal-800 focus:bg-teal-100 focus:text-teal-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
teal: 'border border-transparent text-teal-600 hover:bg-teal-100 hover:text-teal-800 focus:bg-teal-100 focus:text-teal-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
||||||
green: 'border border-transparent text-green-600 hover:bg-green-100 hover:text-green-800 focus:bg-green-100 focus:text-green-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
green: 'border border-transparent text-green-600 hover:bg-green-100 hover:text-green-800 focus:bg-green-100 focus:text-green-800 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:focus:bg-neutral-700 dark:focus:text-white',
|
||||||
transparent: 'border border-transparent text-transparent-600 hover:bg-transparent-100 focus:bg-transparent-100 dark:text-neutral-400 dark:hover:bg-neutral-700 dark:hover:text-white dark:focus:bg-neutral-700 dark:focus:text-white',
|
transparent: 'border border-transparent text-white hover:bg-white/10 focus:bg-white/10 dark:text-white',
|
||||||
},
|
},
|
||||||
soft: {
|
soft: {
|
||||||
blue: 'bg-blue-100 text-blue-800 hover:bg-blue-200 focus:bg-blue-200 dark:text-blue-400 dark:hover:bg-blue-900 dark:focus:bg-blue-900',
|
blue: 'bg-blue-100 text-blue-800 hover:bg-blue-200 focus:bg-blue-200 dark:text-blue-400 dark:hover:bg-blue-900 dark:focus:bg-blue-900',
|
||||||
@ -103,7 +120,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
gray: 'border border-gray-200 bg-white text-gray-800 shadow-2xs hover:bg-gray-50 focus:bg-gray-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
gray: 'border border-gray-200 bg-white text-gray-800 shadow-2xs hover:bg-gray-50 focus:bg-gray-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
||||||
teal: 'border border-teal-200 bg-white text-teal-800 shadow-2xs hover:bg-teal-50 focus:bg-teal-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
teal: 'border border-teal-200 bg-white text-teal-800 shadow-2xs hover:bg-teal-50 focus:bg-teal-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
||||||
green: 'border border-green-200 bg-white text-green-800 shadow-2xs hover:bg-green-50 focus:bg-green-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
green: 'border border-green-200 bg-white text-green-800 shadow-2xs hover:bg-green-50 focus:bg-green-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
||||||
transparent: 'border border-transparent-200 bg-white text-transparent-800 shadow-2xs hover:bg-transparent-50 focus:bg-transparent-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700',
|
transparent: 'border border-white/20 bg-transparent text-white shadow-2xs hover:bg-white/15 focus:bg-white/15 dark:bg-transparent dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700/50 dark:focus:bg-neutral-700/50',
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
blue: 'border border-transparent text-blue-600 hover:text-blue-800 focus:text-blue-800 dark:text-blue-500 dark:hover:text-blue-400 dark:focus:text-blue-400',
|
blue: 'border border-transparent text-blue-600 hover:text-blue-800 focus:text-blue-800 dark:text-blue-500 dark:hover:text-blue-400 dark:focus:text-blue-400',
|
||||||
@ -139,12 +156,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
const dropdownHeight = 200
|
const dropdownHeight = 200
|
||||||
const spaceBelow = window.innerHeight - rect.bottom
|
const spaceBelow = window.innerHeight - rect.bottom
|
||||||
const spaceAbove = rect.top
|
const spaceAbove = rect.top
|
||||||
|
setDirection(spaceBelow < dropdownHeight && spaceAbove > dropdownHeight ? 'up' : 'down')
|
||||||
if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {
|
|
||||||
setDirection('up')
|
|
||||||
} else {
|
|
||||||
setDirection('down')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [open, dropDirection])
|
}, [open, dropDirection])
|
||||||
@ -171,7 +183,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|||||||
className="animate-spin inline-block size-4 border-[3px] border-current border-t-transparent rounded-full mr-2"
|
className="animate-spin inline-block size-4 border-[3px] border-current border-t-transparent rounded-full mr-2"
|
||||||
role="status"
|
role="status"
|
||||||
aria-label="loading"
|
aria-label="loading"
|
||||||
></span>
|
/>
|
||||||
)}
|
)}
|
||||||
{children ?? title}
|
{children ?? title}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/components/LoadingSpinner.tsx
|
// /src/app/components/LoadingSpinner.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/components/MapVoteBanner.tsx
|
// /src/app/components/MapVoteBanner.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
@ -24,7 +24,6 @@ function formatCountdown(ms: number) {
|
|||||||
const pad = (n:number)=>String(n).padStart(2,'0')
|
const pad = (n:number)=>String(n).padStart(2,'0')
|
||||||
return `${h}:${pad(m)}:${pad(s)}`
|
return `${h}:${pad(m)}:${pad(s)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatLead(minutes: number) {
|
function formatLead(minutes: number) {
|
||||||
if (!Number.isFinite(minutes) || minutes <= 0) return 'zum Matchbeginn'
|
if (!Number.isFinite(minutes) || minutes <= 0) return 'zum Matchbeginn'
|
||||||
const h = Math.floor(minutes / 60)
|
const h = Math.floor(minutes / 60)
|
||||||
@ -35,11 +34,7 @@ function formatLead(minutes: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function MapVoteBanner({
|
export default function MapVoteBanner({
|
||||||
match,
|
match, initialNow, matchBaseTs, sseOpensAtTs, sseLeadMinutes,
|
||||||
initialNow,
|
|
||||||
matchBaseTs,
|
|
||||||
sseOpensAtTs,
|
|
||||||
sseLeadMinutes,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
@ -50,16 +45,11 @@ export default function MapVoteBanner({
|
|||||||
const [leadOverride, setLeadOverride] = useState<number | null>(null)
|
const [leadOverride, setLeadOverride] = useState<number | null>(null)
|
||||||
const [opensAtOverride, setOpensAtOverride] = useState<number | null>(null)
|
const [opensAtOverride, setOpensAtOverride] = useState<number | null>(null)
|
||||||
|
|
||||||
// ⚠️ Hydration-sicher: auf dem Server rendern wir ein statisches Placeholder
|
|
||||||
const [mounted, setMounted] = useState(false)
|
const [mounted, setMounted] = useState(false)
|
||||||
useEffect(() => { setMounted(true) }, [])
|
useEffect(() => { setMounted(true) }, [])
|
||||||
|
|
||||||
// clientseitiger Ticker
|
|
||||||
const [now, setNow] = useState(initialNow)
|
const [now, setNow] = useState(initialNow)
|
||||||
useEffect(() => {
|
useEffect(() => { const id = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(id) }, [])
|
||||||
const id = setInterval(() => setNow(Date.now()), 1000)
|
|
||||||
return () => clearInterval(id)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -78,16 +68,11 @@ export default function MapVoteBanner({
|
|||||||
}
|
}
|
||||||
}, [match.id])
|
}, [match.id])
|
||||||
|
|
||||||
// initial + bei Meta-Änderungen
|
|
||||||
useEffect(() => { load() }, [load])
|
useEffect(() => { load() }, [load])
|
||||||
useEffect(() => { load() }, [match.matchDate, match.demoDate, match.bestOf, load])
|
useEffect(() => { load() }, [match.matchDate, match.demoDate, match.bestOf, load])
|
||||||
|
|
||||||
const matchDateTs = useMemo(
|
const matchDateTs = useMemo(() => (typeof matchBaseTs === 'number' ? matchBaseTs : null), [matchBaseTs])
|
||||||
() => (typeof matchBaseTs === 'number' ? matchBaseTs : null),
|
|
||||||
[matchBaseTs]
|
|
||||||
)
|
|
||||||
|
|
||||||
// SSE: nur map-vote-updated & Co. beachten
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!lastEvent) return
|
if (!lastEvent) return
|
||||||
const { type } = lastEvent as any
|
const { type } = lastEvent as any
|
||||||
@ -107,7 +92,6 @@ export default function MapVoteBanner({
|
|||||||
? (typeof evt.opensAt === 'string' ? evt.opensAt : new Date(evt.opensAt).toISOString())
|
? (typeof evt.opensAt === 'string' ? evt.opensAt : new Date(evt.opensAt).toISOString())
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
// Sofort lokale Overrides setzen
|
|
||||||
if (nextOpensAtISO) {
|
if (nextOpensAtISO) {
|
||||||
setOpensAtOverride(new Date(nextOpensAtISO).getTime())
|
setOpensAtOverride(new Date(nextOpensAtISO).getTime())
|
||||||
} else if (Number.isFinite(parsedLead) && matchDateTs != null) {
|
} else if (Number.isFinite(parsedLead) && matchDateTs != null) {
|
||||||
@ -115,7 +99,6 @@ export default function MapVoteBanner({
|
|||||||
}
|
}
|
||||||
if (Number.isFinite(parsedLead)) setLeadOverride(parsedLead as number)
|
if (Number.isFinite(parsedLead)) setLeadOverride(parsedLead as number)
|
||||||
|
|
||||||
// sichtbares Mergen (für UI-Texte)
|
|
||||||
if (nextOpensAtISO !== undefined || Number.isFinite(parsedLead)) {
|
if (nextOpensAtISO !== undefined || Number.isFinite(parsedLead)) {
|
||||||
setState(prev => ({
|
setState(prev => ({
|
||||||
...(prev ?? {} as any),
|
...(prev ?? {} as any),
|
||||||
@ -127,7 +110,6 @@ export default function MapVoteBanner({
|
|||||||
}
|
}
|
||||||
}, [lastEvent, match.id, matchDateTs, load])
|
}, [lastEvent, match.id, matchDateTs, load])
|
||||||
|
|
||||||
// Öffnet wann? (Priorität: Parent-SSE → lokale SSE → Server → Fallback)
|
|
||||||
const opensAt = useMemo(() => {
|
const opensAt = useMemo(() => {
|
||||||
if (typeof sseOpensAtTs === 'number') return sseOpensAtTs
|
if (typeof sseOpensAtTs === 'number') return sseOpensAtTs
|
||||||
if (opensAtOverride != null) return opensAtOverride
|
if (opensAtOverride != null) return opensAtOverride
|
||||||
@ -139,11 +121,8 @@ export default function MapVoteBanner({
|
|||||||
return matchDateTs - lead * 60_000
|
return matchDateTs - lead * 60_000
|
||||||
}, [sseOpensAtTs, opensAtOverride, state?.opensAt, matchDateTs, initialNow, sseLeadMinutes, leadOverride, state?.leadMinutes])
|
}, [sseOpensAtTs, opensAtOverride, state?.opensAt, matchDateTs, initialNow, sseLeadMinutes, leadOverride, state?.leadMinutes])
|
||||||
|
|
||||||
// „startet X vor Matchbeginn“
|
|
||||||
const leadMinutes = useMemo(() => {
|
const leadMinutes = useMemo(() => {
|
||||||
if (matchDateTs != null && opensAt != null) {
|
if (matchDateTs != null && opensAt != null) return Math.max(0, Math.round((matchDateTs - opensAt) / 60_000))
|
||||||
return Math.max(0, Math.round((matchDateTs - opensAt) / 60_000))
|
|
||||||
}
|
|
||||||
if (typeof sseLeadMinutes === 'number') return sseLeadMinutes
|
if (typeof sseLeadMinutes === 'number') return sseLeadMinutes
|
||||||
if (leadOverride != null) return leadOverride
|
if (leadOverride != null) return leadOverride
|
||||||
if (Number.isFinite(state?.leadMinutes)) return state!.leadMinutes as number
|
if (Number.isFinite(state?.leadMinutes)) return state!.leadMinutes as number
|
||||||
@ -152,6 +131,8 @@ export default function MapVoteBanner({
|
|||||||
|
|
||||||
const isOpen = mounted && now >= opensAt
|
const isOpen = mounted && now >= opensAt
|
||||||
const msToOpen = Math.max(opensAt - now, 0)
|
const msToOpen = Math.max(opensAt - now, 0)
|
||||||
|
const isLocked = !!state?.locked
|
||||||
|
const isVotingOpen = isOpen && !isLocked
|
||||||
|
|
||||||
const current = state?.steps?.[state?.currentIndex ?? 0]
|
const current = state?.steps?.[state?.currentIndex ?? 0]
|
||||||
const whoIsUp = current?.teamId
|
const whoIsUp = current?.teamId
|
||||||
@ -162,8 +143,7 @@ export default function MapVoteBanner({
|
|||||||
const isLeaderB = !!session?.user?.steamId && match.teamB?.leader?.steamId === session?.user?.steamId
|
const isLeaderB = !!session?.user?.steamId && match.teamB?.leader?.steamId === session?.user?.steamId
|
||||||
const isAdmin = !!session?.user?.isAdmin
|
const isAdmin = !!session?.user?.isAdmin
|
||||||
const iCanAct = Boolean(
|
const iCanAct = Boolean(
|
||||||
isOpen &&
|
isVotingOpen &&
|
||||||
!state?.locked &&
|
|
||||||
current?.teamId &&
|
current?.teamId &&
|
||||||
(isAdmin ||
|
(isAdmin ||
|
||||||
(current.teamId === match.teamA?.id && isLeaderA) ||
|
(current.teamId === match.teamA?.id && isLeaderA) ||
|
||||||
@ -172,12 +152,24 @@ export default function MapVoteBanner({
|
|||||||
|
|
||||||
const gotoFullPage = () => router.push(`/match-details/${match.id}/vote`)
|
const gotoFullPage = () => router.push(`/match-details/${match.id}/vote`)
|
||||||
|
|
||||||
const cardClasses =
|
// Farblogik: locked → grün, offen → gelb, noch geschlossen → neutral
|
||||||
'group relative overflow-hidden rounded-xl border bg-white/90 dark:bg-neutral-800/90 ' +
|
const ringClass = isLocked
|
||||||
'dark:border-neutral-700 shadow-sm cursor-pointer focus:outline-none transition ' +
|
? 'ring-1 ring-green-500/15 hover:ring-green-500/30 hover:shadow-lg'
|
||||||
(isOpen
|
: isVotingOpen
|
||||||
? 'ring-1 ring-green-500/15 hover:ring-green-500/30 hover:shadow-lg'
|
? 'ring-1 ring-yellow-500/20 hover:ring-yellow-500/35 hover:shadow-lg'
|
||||||
: 'ring-1 ring-neutral-500/10 hover:ring-neutral-500/20 hover:shadow-md')
|
: 'ring-1 ring-neutral-500/10 hover:ring-neutral-500/20 hover:shadow-md'
|
||||||
|
|
||||||
|
const bubbleClass = isLocked
|
||||||
|
? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-200'
|
||||||
|
: isVotingOpen
|
||||||
|
? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-100'
|
||||||
|
: 'bg-neutral-100 text-neutral-700 dark:bg-neutral-700/40 dark:text-neutral-200'
|
||||||
|
|
||||||
|
const gradientClass = isLocked
|
||||||
|
? 'mapVoteGradient--green'
|
||||||
|
: isVotingOpen
|
||||||
|
? 'mapVoteGradient--yellow'
|
||||||
|
: 'mapVoteGradient--none'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -185,41 +177,35 @@ export default function MapVoteBanner({
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={gotoFullPage}
|
onClick={gotoFullPage}
|
||||||
onKeyDown={(e) => e.key === 'Enter' && gotoFullPage()}
|
onKeyDown={(e) => e.key === 'Enter' && gotoFullPage()}
|
||||||
className={cardClasses}
|
className={`group relative overflow-hidden rounded-xl border bg-white/90 dark:bg-neutral-800/90 dark:border-neutral-700 shadow-sm cursor-pointer focus:outline-none transition ${ringClass}`}
|
||||||
aria-label="Map-Vote öffnen"
|
aria-label="Map-Vote öffnen"
|
||||||
>
|
>
|
||||||
{isOpen && (
|
{(isVotingOpen || isLocked) && (
|
||||||
<>
|
<>
|
||||||
<div aria-hidden className="absolute inset-0 z-0 pointer-events-none mapVoteGradient" />
|
<div aria-hidden className={`absolute inset-0 z-0 pointer-events-none ${gradientClass}`} />
|
||||||
<span aria-hidden className="shine pointer-events-none" />
|
<span aria-hidden className="shine pointer-events-none" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="relative z-[1] px-4 py-3 flex items-center justify-between gap-3">
|
<div className="relative z-[1] px-4 py-3 flex items-center justify-between gap-3">
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<div className="shrink-0 w-9 h-9 rounded-full grid place-items-center bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-200 transition-transform group-hover:scale-[1.03] group-hover:translate-x-[1px]">
|
<div className={`shrink-0 w-9 h-9 rounded-full grid place-items-center transition-transform group-hover:scale-[1.03] group-hover:translate-x-[1px] ${bubbleClass}`}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" className="w-5 h-5" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" className="w-5 h-5" fill="currentColor">
|
||||||
<path d="M15 4.5 9 7.5l-6-3v15l6 3 6-3 6 3v-15l-6-3Zm-6 16.5-4-2V6l4 2v13Zm2-13 4-2v13l-4 2V8Z"/>
|
<path d="M15 4.5 9 7.5l-6-3v15l6 3 6-3 6 3v-15l-6-3Zm-6 16.5-4-2V6l4 2v13Zm2-13 4-2v13l-4 2V8Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="font-medium text-gray-900 dark:text-neutral-100">
|
<div className="font-medium text-gray-900 dark:text-neutral-100">Map-Vote</div>
|
||||||
Map-Vote
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-gray-600 dark:text-neutral-400 truncate">
|
<div className="text-xs text-gray-600 dark:text-neutral-400 truncate">
|
||||||
Modus: BO{match.bestOf ?? state?.bestOf ?? 3}
|
Modus: BO{match.bestOf ?? state?.bestOf ?? 3}
|
||||||
{state?.locked
|
{state?.locked
|
||||||
? ' • Auswahl fixiert'
|
? ' • Auswahl fixiert'
|
||||||
: isOpen
|
: isVotingOpen
|
||||||
? (whoIsUp ? ` • am Zug: ${whoIsUp}` : ' • läuft')
|
? (whoIsUp ? ` • am Zug: ${whoIsUp}` : ' • läuft')
|
||||||
: ` • startet ${formatLead(leadMinutes)} vor Matchbeginn`}
|
: ` • startet ${formatLead(leadMinutes)} vor Matchbeginn`}
|
||||||
</div>
|
</div>
|
||||||
{error && (
|
{error && <div className="text-xs text-red-600 dark:text-red-400 mt-0.5">{error}</div>}
|
||||||
<div className="text-xs text-red-600 dark:text-red-400 mt-0.5">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -228,12 +214,11 @@ export default function MapVoteBanner({
|
|||||||
<span className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200">
|
<span className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200">
|
||||||
Voting abgeschlossen
|
Voting abgeschlossen
|
||||||
</span>
|
</span>
|
||||||
) : isOpen ? (
|
) : isVotingOpen ? (
|
||||||
<span className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200">
|
<span className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-100">
|
||||||
{iCanAct ? 'Jetzt wählen' : 'Map-Vote offen'}
|
{iCanAct ? 'Jetzt wählen' : 'Map-Vote offen'}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
// 🔑 Hydration-safe: vor dem Mount nur ein Placeholder rendern
|
|
||||||
<span
|
<span
|
||||||
className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-100"
|
className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-100"
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
@ -245,63 +230,43 @@ export default function MapVoteBanner({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
/* Hintergrund-Schimmer (läuft permanent) */
|
@keyframes slide-x { from { background-position-x: 0% } to { background-position-x: 200% } }
|
||||||
@keyframes slide-x {
|
|
||||||
from { background-position-x: 0%; }
|
.mapVoteGradient--green {
|
||||||
to { background-position-x: 200%; }
|
background-image: repeating-linear-gradient(90deg, rgba(16,168,54,0.20) 0%, rgba(16,168,54,0.04) 50%, rgba(16,168,54,0.20) 100%);
|
||||||
|
background-size: 200% 100%; background-repeat: repeat-x; animation: slide-x 6s linear infinite;
|
||||||
}
|
}
|
||||||
.mapVoteGradient {
|
:global(.dark) .mapVoteGradient--green {
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(90deg, rgba(16,168,54,0.28) 0%, rgba(16,168,54,0.08) 50%, rgba(16,168,54,0.28) 100%);
|
||||||
90deg,
|
|
||||||
rgba(16,168,54,0.20) 0%,
|
|
||||||
rgba(16,168,54,0.04) 50%,
|
|
||||||
rgba(16,168,54,0.20) 100%
|
|
||||||
);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
animation: slide-x 6s linear infinite;
|
|
||||||
}
|
|
||||||
:global(.dark) .mapVoteGradient {
|
|
||||||
background-image: repeating-linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(16,168,54,0.28) 0%,
|
|
||||||
rgba(16,168,54,0.08) 50%,
|
|
||||||
rgba(16,168,54,0.28) 100%
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shine-Sweep nur auf Hover */
|
.mapVoteGradient--yellow {
|
||||||
|
background-image: repeating-linear-gradient(90deg, rgba(234,179,8,0.24) 0%, rgba(234,179,8,0.08) 50%, rgba(234,179,8,0.24) 100%);
|
||||||
|
background-size: 200% 100%; background-repeat: repeat-x; animation: slide-x 6s linear infinite;
|
||||||
|
}
|
||||||
|
:global(.dark) .mapVoteGradient--yellow {
|
||||||
|
background-image: repeating-linear-gradient(90deg, rgba(234,179,8,0.35) 0%, rgba(234,179,8,0.12) 50%, rgba(234,179,8,0.35) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapVoteGradient--none { background: transparent }
|
||||||
|
|
||||||
@keyframes shine {
|
@keyframes shine {
|
||||||
0% { transform: translateX(-120%) skewX(-20deg); opacity: 0; }
|
0% { transform: translateX(-120%) skewX(-20deg); opacity: 0 }
|
||||||
10% { opacity: .7; }
|
10% { opacity: .7 }
|
||||||
27% { transform: translateX(120%) skewX(-20deg); opacity: 0; }
|
27% { transform: translateX(120%) skewX(-20deg); opacity: 0 }
|
||||||
100% { transform: translateX(120%) skewX(-20deg); opacity: 0; }
|
100% { transform: translateX(120%) skewX(-20deg); opacity: 0 }
|
||||||
}
|
|
||||||
.shine {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
}
|
}
|
||||||
|
.shine { position: absolute; inset: 0 }
|
||||||
.shine::before {
|
.shine::before {
|
||||||
content: "";
|
content: ""; position: absolute; top: -25%; bottom: -25%; left: -20%; width: 35%;
|
||||||
position: absolute;
|
pointer-events: none; background: linear-gradient(90deg, transparent, rgba(255,255,255,.35), transparent);
|
||||||
top: -25%;
|
filter: blur(2px); opacity: 0; transform: translateX(-120%) skewX(-20deg); transition: opacity .2s;
|
||||||
bottom: -25%;
|
|
||||||
left: -20%;
|
|
||||||
width: 35%;
|
|
||||||
pointer-events: none;
|
|
||||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,.35), transparent);
|
|
||||||
filter: blur(2px);
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-120%) skewX(-20deg);
|
|
||||||
transition: opacity .2s;
|
|
||||||
}
|
|
||||||
:global(.group:hover) .shine::before {
|
|
||||||
animation: shine 3.8s ease-out infinite;
|
|
||||||
}
|
}
|
||||||
|
:global(.group:hover) .shine::before { animation: shine 3.8s ease-out infinite }
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.mapVoteGradient { animation: none; }
|
.mapVoteGradient--green, .mapVoteGradient--yellow { animation: none }
|
||||||
.shine::before { animation: none !important; transform: none !important; opacity: 0 !important; }
|
.shine::before { animation: none !important; transform: none !important; opacity: 0 !important }
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/components/MapVoteProfileCard.tsx
|
// /src/app/components/MapVoteProfileCard.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import PremierRankBadge from './PremierRankBadge'
|
import PremierRankBadge from './PremierRankBadge'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/components/MatchDetails.tsx
|
// /src/app/components/MatchDetails.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, useEffect, useMemo, useRef } from 'react'
|
import { useState, useEffect, useMemo, useRef } from 'react'
|
||||||
@ -431,13 +431,15 @@ export function MatchDetails({ match, initialNow }: { match: Match; initialNow:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* MapVote-Banner erhält die aktuell berechneten (SSE-konformen) Werte */}
|
{/* MapVote-Banner erhält die aktuell berechneten (SSE-konformen) Werte */}
|
||||||
<MapVoteBanner
|
{(match.matchType === 'community' &&
|
||||||
match={match}
|
<MapVoteBanner
|
||||||
initialNow={initialNow}
|
match={match}
|
||||||
matchBaseTs={matchBaseTs}
|
initialNow={initialNow}
|
||||||
sseOpensAtTs={sseOpensAtTs}
|
matchBaseTs={matchBaseTs}
|
||||||
sseLeadMinutes={sseLeadMinutes}
|
sseOpensAtTs={sseOpensAtTs}
|
||||||
/>
|
sseLeadMinutes={sseLeadMinutes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* ───────── Team-Blöcke ───────── */}
|
{/* ───────── Team-Blöcke ───────── */}
|
||||||
<div className="border-t pt-4 mt-4 space-y-10">
|
<div className="border-t pt-4 mt-4 space-y-10">
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { useSession } from 'next-auth/react'
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useSSEStore } from '@/app/lib/useSSEStore'
|
import { useSSEStore } from '@/app/lib/useSSEStore'
|
||||||
import { NOTIFICATION_EVENTS, isSseEventType } from '../lib/sseEvents'
|
import { NOTIFICATION_EVENTS, isSseEventType } from '../lib/sseEvents'
|
||||||
|
import { useUiChromeStore } from '@/app/lib/useUiChromeStore'
|
||||||
|
|
||||||
type Notification = {
|
type Notification = {
|
||||||
id: string
|
id: string
|
||||||
@ -36,6 +37,7 @@ export default function NotificationBell() {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { lastEvent } = useSSEStore() // nur konsumieren, nicht connecten
|
const { lastEvent } = useSSEStore() // nur konsumieren, nicht connecten
|
||||||
const bellRef = useRef<HTMLButtonElement | null>(null);
|
const bellRef = useRef<HTMLButtonElement | null>(null);
|
||||||
|
const telemetryBannerPx = useUiChromeStore(s => s.telemetryBannerPx)
|
||||||
|
|
||||||
const [notifications, setNotifications] = useState<Notification[]>([])
|
const [notifications, setNotifications] = useState<Notification[]>([])
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
@ -43,6 +45,9 @@ export default function NotificationBell() {
|
|||||||
const [showPreview, setShowPreview] = useState(false)
|
const [showPreview, setShowPreview] = useState(false)
|
||||||
const [animateBell, setAnimateBell] = useState(false)
|
const [animateBell, setAnimateBell] = useState(false)
|
||||||
|
|
||||||
|
const baseBottom = 24 // px, entspricht bottom-6
|
||||||
|
const bottomPx = baseBottom + (telemetryBannerPx || 0)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!lastEvent) return
|
if (!lastEvent) return
|
||||||
if (!isSseEventType(lastEvent.type)) return
|
if (!isSseEventType(lastEvent.type)) return
|
||||||
@ -79,7 +84,7 @@ export default function NotificationBell() {
|
|||||||
if (!steamId) return
|
if (!steamId) return
|
||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/notifications/user')
|
const res = await fetch('/api/notifications')
|
||||||
if (!res.ok) throw new Error('Fehler beim Laden')
|
if (!res.ok) throw new Error('Fehler beim Laden')
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const loaded: Notification[] = data.notifications.map((n: any) => ({
|
const loaded: Notification[] = data.notifications.map((n: any) => ({
|
||||||
@ -257,7 +262,10 @@ export default function NotificationBell() {
|
|||||||
|
|
||||||
// 4) Render
|
// 4) Render
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-6 right-6 z-50">
|
<div
|
||||||
|
className="fixed right-6 z-50"
|
||||||
|
style={{ bottom: bottomPx }}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
ref={bellRef}
|
ref={bellRef}
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -85,18 +85,18 @@ export default function ReadyOverlayHost() {
|
|||||||
// Events: 'match-ready' & 'map-vote-updated'
|
// Events: 'match-ready' & 'map-vote-updated'
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!lastEvent || !mySteamId) return
|
if (!lastEvent || !mySteamId) return
|
||||||
|
const evt = (lastEvent as any).payload ?? lastEvent // ⬅️ robust gegen beide Formen
|
||||||
|
|
||||||
if (lastEvent.type === 'match-ready') {
|
if (lastEvent.type === 'match-ready') {
|
||||||
(async () => {
|
(async () => {
|
||||||
const m: string | undefined = lastEvent.payload?.matchId
|
const m: string | undefined = evt?.matchId
|
||||||
const participants: string[] = lastEvent.payload?.participants ?? []
|
const participants: string[] = evt?.participants ?? []
|
||||||
if (!m || !participants.includes(mySteamId) || isAccepted(m)) return
|
if (!m || !participants.includes(mySteamId) || isAccepted(m)) return
|
||||||
|
|
||||||
// ⬇️ Roster persistent speichern (für Reconnect-Banner)
|
setRoster(participants) // ✅ wird jetzt sicher gesetzt
|
||||||
setRoster(participants)
|
|
||||||
|
|
||||||
const label = lastEvent.payload?.firstMap?.label ?? '?'
|
const label = evt?.firstMap?.label ?? '?'
|
||||||
const bg = lastEvent.payload?.firstMap?.bg ?? '/assets/img/maps/cs2.webp'
|
const bg = evt?.firstMap?.bg ?? '/assets/img/maps/cs2.webp'
|
||||||
|
|
||||||
const connectHref =
|
const connectHref =
|
||||||
(await getConnectHref(m)) ||
|
(await getConnectHref(m)) ||
|
||||||
@ -119,12 +119,11 @@ export default function ReadyOverlayHost() {
|
|||||||
|
|
||||||
if (lastEvent.type === 'map-vote-updated') {
|
if (lastEvent.type === 'map-vote-updated') {
|
||||||
(async () => {
|
(async () => {
|
||||||
const summary = deriveReadySummary(lastEvent.payload)
|
const summary = deriveReadySummary(evt) // evt statt lastEvent.payload
|
||||||
if (!summary) return
|
if (!summary) return
|
||||||
const { matchId: m, firstMap, participants } = summary
|
const { matchId: m, firstMap, participants } = summary
|
||||||
if (!participants.includes(mySteamId) || isAccepted(m)) return
|
if (!participants.includes(mySteamId) || isAccepted(m)) return
|
||||||
|
|
||||||
// ⬇️ Roster persistent speichern
|
|
||||||
setRoster(participants)
|
setRoster(participants)
|
||||||
|
|
||||||
const connectHref =
|
const connectHref =
|
||||||
|
|||||||
@ -182,35 +182,6 @@ export default function Sidebar() {
|
|||||||
Spielplan
|
Spielplan
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{/* Radar */}
|
|
||||||
<li>
|
|
||||||
<Button
|
|
||||||
onClick={() => { router.push('/radar'); setIsOpen(false) }}
|
|
||||||
size="sm"
|
|
||||||
variant="link"
|
|
||||||
className={`${navBtnBase} ${isActive('/radar') ? activeClasses : idleClasses}`}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
className="size-4"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
{/* äußerer Kreis */}
|
|
||||||
<circle cx="12" cy="12" r="10" />
|
|
||||||
{/* Sweep-Linie */}
|
|
||||||
<line x1="12" y1="12" x2="21" y2="12" />
|
|
||||||
{/* Zusatz-Ringe */}
|
|
||||||
<circle cx="12" cy="12" r="6" strokeDasharray="4 4" />
|
|
||||||
<circle cx="12" cy="12" r="3" />
|
|
||||||
</svg>
|
|
||||||
Radar
|
|
||||||
</Button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@ -68,11 +68,11 @@ export default function SidebarFooter() {
|
|||||||
}`
|
}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="relative w-full min-h-[65px]">
|
||||||
{/* Kopf / Toggle */}
|
{/* Kopf / Toggle */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsOpen(v => !v)}
|
onClick={() => setIsOpen(v => !v)}
|
||||||
className={`w-full inline-flex items-center gap-x-2 px-4 py-3 text-sm text-left text-gray-800 transition-all duration-100
|
className={`w-full min-h-[65px] inline-flex items-center gap-x-2 px-4 py-3 text-sm text-left text-gray-800 transition-all duration-100
|
||||||
${isOpen ? 'bg-gray-100 dark:bg-neutral-700' : 'hover:bg-gray-100 dark:hover:bg-neutral-700'}
|
${isOpen ? 'bg-gray-100 dark:bg-neutral-700' : 'hover:bg-gray-100 dark:hover:bg-neutral-700'}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
// /src/app/components/TeamCard.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState, useMemo } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import Button from './Button'
|
import Button from './Button'
|
||||||
import TeamPremierRankBadge from './TeamPremierRankBadge'
|
import TeamPremierRankBadge from './TeamPremierRankBadge'
|
||||||
@ -12,6 +13,9 @@ type Props = {
|
|||||||
invitationId?: string
|
invitationId?: string
|
||||||
onUpdateInvitation: (teamId: string, newValue: string | null | 'pending') => void
|
onUpdateInvitation: (teamId: string, newValue: string | null | 'pending') => void
|
||||||
adminMode?: boolean
|
adminMode?: boolean
|
||||||
|
/** Vom Page-Container gesetzt: ob der Nutzer grundsätzlich Beitritte anfragen darf
|
||||||
|
* (false, wenn /api/user ein team liefert). Default: true (abwärtskompatibel). */
|
||||||
|
canRequestJoin?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TeamCard({
|
export default function TeamCard({
|
||||||
@ -20,15 +24,29 @@ export default function TeamCard({
|
|||||||
invitationId,
|
invitationId,
|
||||||
onUpdateInvitation,
|
onUpdateInvitation,
|
||||||
adminMode = false,
|
adminMode = false,
|
||||||
|
canRequestJoin = true,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [joining, setJoining] = useState(false)
|
const [joining, setJoining] = useState(false)
|
||||||
|
|
||||||
const isRequested = Boolean(invitationId)
|
const isRequested = Boolean(invitationId)
|
||||||
const isDisabled = joining || currentUserSteamId === team.leader?.steamId
|
|
||||||
|
// Bin ich bereits in DIESEM Team (Leader, aktiv oder inaktiv)?
|
||||||
|
const isMemberOfThisTeam = useMemo(() => {
|
||||||
|
const inActive = (team.activePlayers ?? []).some(p => String(p.steamId) === String(currentUserSteamId))
|
||||||
|
const inInactive = (team.inactivePlayers ?? []).some(p => String(p.steamId) === String(currentUserSteamId))
|
||||||
|
const isLeader = team.leader?.steamId && String(team.leader.steamId) === String(currentUserSteamId)
|
||||||
|
return Boolean(inActive || inInactive || isLeader)
|
||||||
|
}, [team, currentUserSteamId])
|
||||||
|
|
||||||
|
// Button sperren, wenn:
|
||||||
|
// - gerade Request läuft
|
||||||
|
// - bereits Mitglied dieses Teams
|
||||||
|
// - global keine Join-Anfragen erlaubt (User hat bereits ein Team)
|
||||||
|
const isDisabled = joining || isMemberOfThisTeam || !canRequestJoin
|
||||||
|
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
if (joining) return
|
if (joining || isDisabled) return
|
||||||
setJoining(true)
|
setJoining(true)
|
||||||
try {
|
try {
|
||||||
if (isRequested) {
|
if (isRequested) {
|
||||||
@ -55,6 +73,27 @@ export default function TeamCard({
|
|||||||
|
|
||||||
const targetHref = adminMode ? `/admin/teams/${team.id}` : `/team/${team.id}`
|
const targetHref = adminMode ? `/admin/teams/${team.id}` : `/team/${team.id}`
|
||||||
|
|
||||||
|
// Label & Farbe abhängig vom Status
|
||||||
|
const buttonLabel = 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
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
: (!canRequestJoin || isMemberOfThisTeam)
|
||||||
|
? 'Beitritt nicht möglich'
|
||||||
|
: isRequested
|
||||||
|
? 'Angefragt (zurückziehen)'
|
||||||
|
: 'Beitritt anfragen'
|
||||||
|
|
||||||
|
const buttonColor =
|
||||||
|
isDisabled ? 'gray' : (isRequested ? 'gray' : 'blue')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
@ -96,27 +135,16 @@ export default function TeamCard({
|
|||||||
Verwalten
|
Verwalten
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
|
// 👉 Button immer zeigen – falls nicht möglich: disabled + anderes Label
|
||||||
<Button
|
<Button
|
||||||
title={isRequested ? 'Angefragt (zurückziehen)' : 'Beitritt anfragen'}
|
title={typeof buttonLabel === 'string' ? buttonLabel : undefined}
|
||||||
size="sm"
|
size="sm"
|
||||||
color={isRequested ? 'gray' : 'blue'}
|
color={buttonColor as any}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
onClick={e => { e.stopPropagation(); handleClick() }}
|
onClick={e => { e.stopPropagation(); handleClick() }}
|
||||||
|
aria-disabled={isDisabled ? 'true' : undefined}
|
||||||
>
|
>
|
||||||
{joining ? (
|
{buttonLabel}
|
||||||
<>
|
|
||||||
<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>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/components/TeamCardComponent.tsx
|
// /src/app/components/TeamCardComponent.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
|||||||
279
src/app/components/TelemetryBanner.tsx
Normal file
279
src/app/components/TelemetryBanner.tsx
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
// src/app/components/TelemetryBanner.tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import React, { useEffect, useRef } from 'react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Button from '@/app/components/Button'
|
||||||
|
import { useUiChromeStore } from '@/app/lib/useUiChromeStore'
|
||||||
|
import { MAP_OPTIONS } from '@/app/lib/mapOptions'
|
||||||
|
|
||||||
|
export type TelemetryBannerVariant = 'connected' | 'disconnected'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
variant: TelemetryBannerVariant
|
||||||
|
visible: boolean
|
||||||
|
zIndex?: number
|
||||||
|
// gemeinsam
|
||||||
|
connectedCount: number
|
||||||
|
totalExpected: number
|
||||||
|
connectUri: string
|
||||||
|
onReconnect: () => void
|
||||||
|
// neu: zum harten Trennen (X-Button)
|
||||||
|
onDisconnect?: () => void
|
||||||
|
// nur für "connected"
|
||||||
|
serverLabel?: string
|
||||||
|
mapKey?: string
|
||||||
|
mapLabel?: string
|
||||||
|
phase?: string
|
||||||
|
score?: string
|
||||||
|
// nur für "disconnected"
|
||||||
|
missingCount?: number
|
||||||
|
// optional: wenn im Dock unter Main gerendert
|
||||||
|
inline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- helpers ---------- */
|
||||||
|
function hashStr(s: string): number {
|
||||||
|
let h = 5381
|
||||||
|
for (let i = 0; i < s.length; i++) h = ((h << 5) + h) + s.charCodeAt(i)
|
||||||
|
return h | 0
|
||||||
|
}
|
||||||
|
function pickMapImageFromOptions(mapKey?: string): string | null {
|
||||||
|
if (!mapKey) return null
|
||||||
|
const opt = MAP_OPTIONS.find(o => o.key.toLowerCase() === mapKey.toLowerCase())
|
||||||
|
if (!opt || !opt.images?.length) return null
|
||||||
|
const idx = Math.abs(hashStr(mapKey)) % opt.images.length
|
||||||
|
return opt.images[idx] ?? null
|
||||||
|
}
|
||||||
|
function pickMapIcon(mapKey?: string): string | null {
|
||||||
|
if (!mapKey) return null
|
||||||
|
const opt = MAP_OPTIONS.find(o => o.key.toLowerCase() === mapKey.toLowerCase())
|
||||||
|
return opt?.icon ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- component ---------- */
|
||||||
|
export default function TelemetryBanner({
|
||||||
|
variant,
|
||||||
|
visible,
|
||||||
|
zIndex = 9999,
|
||||||
|
connectedCount,
|
||||||
|
totalExpected,
|
||||||
|
connectUri,
|
||||||
|
onReconnect,
|
||||||
|
onDisconnect,
|
||||||
|
serverLabel,
|
||||||
|
mapKey,
|
||||||
|
mapLabel,
|
||||||
|
phase,
|
||||||
|
score,
|
||||||
|
missingCount,
|
||||||
|
inline = false,
|
||||||
|
}: Props) {
|
||||||
|
const ref = useRef<HTMLDivElement | null>(null)
|
||||||
|
const setBannerPx = useUiChromeStore(s => s.setTelemetryBannerPx)
|
||||||
|
|
||||||
|
// ▼ Phase normalisieren und Sichtbarkeit nur erlauben, wenn nicht "unknown"
|
||||||
|
const phaseStr = String(phase ?? 'unknown').toLowerCase()
|
||||||
|
const show = visible && phaseStr !== 'unknown'
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!show) { setBannerPx(0); return }
|
||||||
|
const el = ref.current
|
||||||
|
if (!el) return
|
||||||
|
const report = () => setBannerPx(el.getBoundingClientRect().height)
|
||||||
|
report()
|
||||||
|
const ro = new ResizeObserver(report)
|
||||||
|
ro.observe(el)
|
||||||
|
return () => { ro.disconnect(); setBannerPx(0) }
|
||||||
|
}, [show, setBannerPx])
|
||||||
|
|
||||||
|
// Ableitungen vor dem Guard
|
||||||
|
const outerBase = inline ? '' : 'fixed inset-x-0 bottom-0'
|
||||||
|
const outerStyle = inline ? {} : { zIndex }
|
||||||
|
|
||||||
|
const wrapperClass =
|
||||||
|
variant === 'connected'
|
||||||
|
? 'bg-emerald-700/95 text-white ring-1 ring-black/10'
|
||||||
|
: 'bg-amber-700/95 text-white ring-1 ring-black/10'
|
||||||
|
|
||||||
|
const bgUrl = pickMapImageFromOptions(mapKey)
|
||||||
|
const mapIconConnected = pickMapIcon(mapKey)
|
||||||
|
const iconUrl = variant === 'connected' ? (mapIconConnected ?? '') : '/assets/img/icons/ui/disconnect.svg'
|
||||||
|
|
||||||
|
const prettyMap = mapLabel ?? mapKey ?? '—'
|
||||||
|
const prettyPhase = phaseStr || 'unknown' // nutzt die normalisierte Phase
|
||||||
|
const prettyScore = score ?? '– : –'
|
||||||
|
|
||||||
|
const handleFocusGame = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
try { window.location.href = 'steam://rungameid/730' } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ▼ nichts rendern, wenn Phase unbekannt oder sichtbar=false
|
||||||
|
if (!show) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${outerBase} h-full w-full`} style={outerStyle} ref={ref}>
|
||||||
|
<div className={`relative overflow-hidden h-full shadow-lg ${wrapperClass} transition duration-300 ease-in-out`}>
|
||||||
|
{/* Subtiler Map-Hintergrund */}
|
||||||
|
{bgUrl && (
|
||||||
|
<div
|
||||||
|
aria-hidden
|
||||||
|
className="pointer-events-none absolute inset-0"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${bgUrl})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
opacity: 0.5,
|
||||||
|
filter: 'blur(2px)',
|
||||||
|
transform: 'scale(1.02)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Lesbarkeits-Gradient */}
|
||||||
|
<div
|
||||||
|
aria-hidden
|
||||||
|
className="pointer-events-none absolute inset-0"
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(180deg, rgba(0,0,0,0.20) 0%, rgba(0,0,0,0.10) 40%, rgba(0,0,0,0.25) 100%)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Inhalt */}
|
||||||
|
<div className="relative h-full p-3 flex items-center gap-3">
|
||||||
|
{/* Icon links */}
|
||||||
|
{iconUrl ? (
|
||||||
|
<div className="shrink-0 relative z-[1]">
|
||||||
|
<div className="h-9 w-9 rounded-md bg-black/15 flex items-center justify-center ring-1 ring-black/20">
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={iconUrl}
|
||||||
|
alt={variant === 'connected' ? (prettyMap || 'Map') : 'Disconnected'}
|
||||||
|
className="h-6 w-6 object-contain"
|
||||||
|
loading="eager"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
{variant === 'connected' ? (
|
||||||
|
<>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
Verbunden mit {serverLabel ?? 'CS2-Server'}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs opacity-90 mt-0.5 flex flex-wrap gap-x-3 gap-y-1">
|
||||||
|
<span>Map: <span className="font-semibold">{prettyMap}</span></span>
|
||||||
|
<span>Phase: <span className="font-semibold">{prettyPhase}</span></span>
|
||||||
|
<span>Score: <span className="font-semibold">{prettyScore}</span></span>
|
||||||
|
<span>Spieler verbunden: <span className="font-semibold">{connectedCount}</span> / {totalExpected}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="text-sm font-semibold">Verbindung getrennt</div>
|
||||||
|
<div className="text-xs opacity-90 mt-0.5 flex flex-wrap gap-x-3 gap-y-1">
|
||||||
|
<span>Map: <span className="font-semibold">{prettyMap}</span></span>
|
||||||
|
<span>Phase: <span className="font-semibold">{prettyPhase}</span></span>
|
||||||
|
<span>Score: <span className="font-semibold">{prettyScore}</span></span>
|
||||||
|
<span>Spieler verbunden: <span className="font-semibold">{connectedCount}</span> / {totalExpected}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Buttons rechts */}
|
||||||
|
<div className="relative z-[1] flex items-center gap-2">
|
||||||
|
{/* Radar */}
|
||||||
|
<Link href="/radar" className="inline-flex">
|
||||||
|
<Button
|
||||||
|
variant="white"
|
||||||
|
color="transparent"
|
||||||
|
size="md"
|
||||||
|
className="bg-white/10 dark:bg-white/10 border border-white/20 hover:bg-white/15 dark:hover:bg-white/15"
|
||||||
|
title={undefined}
|
||||||
|
>
|
||||||
|
<span className="relative mr-2 h-4 w-4 rounded-full overflow-hidden ring-1 ring-black/20 bg-black/20">
|
||||||
|
{/* zentraler Punkt */}
|
||||||
|
<span className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<span className="h-1.5 w-1.5 rounded-full bg-white/90 shadow-[0_0_6px_rgba(255,255,255,0.8)]" />
|
||||||
|
</span>
|
||||||
|
{/* expandierende Ringe */}
|
||||||
|
<span className="absolute inset-0 rounded-full border border-white/50 opacity-70 animate-ping-slow" />
|
||||||
|
<span className="absolute inset-0 rounded-full border border-white/30 opacity-50 animate-ping-slower" />
|
||||||
|
<span className="absolute inset-0 rounded-full border border-white/20 opacity-30 animate-ping-slowest" />
|
||||||
|
{/* rotierender Sweep */}
|
||||||
|
<span className="absolute inset-0 rounded-full overflow-hidden">
|
||||||
|
<span className="absolute left-1/2 top-1/2 origin-left -translate-y-1/2 h-[1.2px] w-full bg-gradient-to-r from-white/70 via-white/30 to-transparent animate-sweep" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
Radar
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Spiel öffnen / Neu verbinden */}
|
||||||
|
{variant === 'connected' ? (
|
||||||
|
<Button
|
||||||
|
color="green"
|
||||||
|
variant="solid"
|
||||||
|
size="md"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
try { window.location.href = 'steam://rungameid/730' } catch {}
|
||||||
|
}}
|
||||||
|
title="Spiel öffnen"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
color="green"
|
||||||
|
variant="solid"
|
||||||
|
size="md"
|
||||||
|
onClick={() => onReconnect()}
|
||||||
|
title="Neu verbinden"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* „X“ Disconnect ganz rechts */}
|
||||||
|
<Button
|
||||||
|
color="transparent"
|
||||||
|
variant="ghost"
|
||||||
|
size="md"
|
||||||
|
textSize="3xl" // darf bleiben, beeinflusst SVG nicht
|
||||||
|
className="h-9 w-9 aspect-square !px-0 grid place-items-center"
|
||||||
|
onClick={() => onDisconnect?.()}
|
||||||
|
aria-label="Verbindung trennen"
|
||||||
|
title={undefined}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
className="h-6 w-6"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
|
||||||
|
</svg>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* CSS für Radar-Ping & Sweep */}
|
||||||
|
<style jsx>{`
|
||||||
|
@keyframes ringPing {
|
||||||
|
0% { transform: scale(0.4); opacity: 0.85; }
|
||||||
|
70% { transform: scale(1.05); opacity: 0.15; }
|
||||||
|
100% { transform: scale(1.2); opacity: 0; }
|
||||||
|
}
|
||||||
|
@keyframes sweepRotate {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
.animate-ping-slow { animation: ringPing 2.2s ease-out infinite; }
|
||||||
|
.animate-ping-slower { animation: ringPing 3.0s ease-out infinite; animation-delay: .6s; }
|
||||||
|
.animate-ping-slowest { animation: ringPing 4.0s ease-out infinite; animation-delay: 1.2s; }
|
||||||
|
.animate-sweep { animation: sweepRotate 2.8s linear infinite; }
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,12 +1,14 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import { createPortal } from 'react-dom'
|
||||||
|
import { useSession } from 'next-auth/react'
|
||||||
|
import { useReadyOverlayStore } from '@/app/lib/useReadyOverlayStore'
|
||||||
import { usePresenceStore } from '@/app/lib/usePresenceStore'
|
import { usePresenceStore } from '@/app/lib/usePresenceStore'
|
||||||
import { useTelemetryStore } from '@/app/lib/useTelemetryStore'
|
import { useTelemetryStore } from '@/app/lib/useTelemetryStore'
|
||||||
import { useMatchRosterStore } from '@/app/lib/useMatchRosterStore'
|
import { useMatchRosterStore } from '@/app/lib/useMatchRosterStore'
|
||||||
import { useSession } from 'next-auth/react'
|
import TelemetryBanner from './TelemetryBanner'
|
||||||
|
import { MAP_OPTIONS } from '@/app/lib/mapOptions'
|
||||||
type Status = 'idle'|'connecting'|'open'|'closed'|'error'
|
|
||||||
|
|
||||||
function makeWsUrl(host?: string, port?: string, path?: string, scheme?: string) {
|
function makeWsUrl(host?: string, port?: string, path?: string, scheme?: string) {
|
||||||
const h = (host ?? '').trim() || '127.0.0.1'
|
const h = (host ?? '').trim() || '127.0.0.1'
|
||||||
@ -16,51 +18,90 @@ function makeWsUrl(host?: string, port?: string, path?: string, scheme?: string)
|
|||||||
const pageHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'
|
const pageHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'
|
||||||
const useWss = sch === 'wss' || (sch !== 'ws' && (p === '443' || pageHttps))
|
const useWss = sch === 'wss' || (sch !== 'ws' && (p === '443' || pageHttps))
|
||||||
const proto = useWss ? 'wss' : 'ws'
|
const proto = useWss ? 'wss' : 'ws'
|
||||||
const portPart = (p === '80' || p === '443') ? '' : `:${p}`
|
const portPart = p === '80' || p === '443' ? '' : `:${p}`
|
||||||
return `${proto}://${h}${portPart}${pa}`
|
return `${proto}://${h}${portPart}${pa}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sidOf = (p: any) => String(p?.steamId ?? p?.steam_id ?? p?.id ?? '')
|
||||||
|
const toSet = (arr: Iterable<string>) => new Set(Array.from(arr).map(String))
|
||||||
|
|
||||||
|
function parseServerLabel(uri: string | null | undefined): string {
|
||||||
|
if (!uri) return 'CS2-Server'
|
||||||
|
const m = uri.match(/steam:\/\/connect\/([^/]+)/i)
|
||||||
|
if (m && m[1]) return m[1].split('/')[0] || 'CS2-Server'
|
||||||
|
try {
|
||||||
|
const u = new URL(uri)
|
||||||
|
return u.host || 'CS2-Server'
|
||||||
|
} catch {
|
||||||
|
return uri ?? 'CS2-Server'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function labelForMap(key?: string | null): string {
|
||||||
|
if (!key) return '—'
|
||||||
|
const k = String(key).toLowerCase()
|
||||||
|
const opt = MAP_OPTIONS.find(o => o.key.toLowerCase() === k)
|
||||||
|
if (opt?.label) return opt.label
|
||||||
|
// Fallback: "de_dust2" -> "Dust 2"
|
||||||
|
let s = k.replace(/^(de|cs)_/, '').replace(/_/g, ' ').replace(/(\d)/g, ' $1').replace(/\s+/g, ' ').trim()
|
||||||
|
s = s.split(' ').map(w => (w ? w[0].toUpperCase() + w.slice(1) : w)).join(' ')
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
export default function TelemetrySocket() {
|
export default function TelemetrySocket() {
|
||||||
const url = useMemo(
|
const url = useMemo(
|
||||||
() => makeWsUrl(
|
() =>
|
||||||
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_HOST,
|
makeWsUrl(
|
||||||
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PORT,
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_HOST,
|
||||||
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PATH,
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PORT,
|
||||||
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_SCHEME
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PATH,
|
||||||
),
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_SCHEME
|
||||||
|
),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
const mySteamId = (session?.user as any)?.steamId ?? null
|
const mySteamId = (session?.user as any)?.steamId ?? null
|
||||||
|
|
||||||
const setSnapshot = usePresenceStore(s => s.setSnapshot)
|
// overlay control
|
||||||
const setJoin = usePresenceStore(s => s.setJoin)
|
const hideOverlay = useReadyOverlayStore((s) => s.hide)
|
||||||
const setLeave = usePresenceStore(s => s.setLeave)
|
|
||||||
|
|
||||||
const setMapKey = useTelemetryStore(s => s.setMapKey)
|
// presence/telemetry stores
|
||||||
const phase = useTelemetryStore(s => s.phase)
|
const setSnapshot = usePresenceStore((s) => s.setSnapshot)
|
||||||
const setPhase = useTelemetryStore(s => s.setPhase)
|
const setJoin = usePresenceStore((s) => s.setJoin)
|
||||||
|
const setLeave = usePresenceStore((s) => s.setLeave)
|
||||||
|
|
||||||
const rosterSet = useMatchRosterStore(s => s.roster)
|
const setMapKey = useTelemetryStore((s) => s.setMapKey)
|
||||||
|
const phase = useTelemetryStore((s) => s.phase)
|
||||||
|
const setPhase = useTelemetryStore((s) => s.setPhase)
|
||||||
|
|
||||||
// 👇 Tracke, ob ICH gerade auf dem Server bin
|
// roster (persisted by ReadyOverlayHost)
|
||||||
const [myConnected, setMyConnected] = useState(false)
|
const rosterSet = useMatchRosterStore((s) => s.roster)
|
||||||
|
|
||||||
// internes Dismiss-Flag fürs Banner (pro Mount)
|
// local telemetry state
|
||||||
const [dismissed, setDismissed] = useState(false)
|
const [telemetrySet, setTelemetrySet] = useState<Set<string>>(new Set())
|
||||||
|
const [mapKeyForUi, setMapKeyForUi] = useState<string | null>(null)
|
||||||
|
const [score, setScore] = useState<{ a: number | null; b: number | null }>({ a: null, b: null })
|
||||||
|
|
||||||
// connectHref optional dynamisch vom Backend ziehen
|
// connect uri + server name
|
||||||
const [connectHref, setConnectHref] = useState<string | null>(null)
|
const [connectHref, setConnectHref] = useState<string | null>(null)
|
||||||
|
const [serverName, setServerName] = useState<string | null>(null)
|
||||||
|
|
||||||
// WS-Reconnect
|
// ws
|
||||||
const aliveRef = useRef(true)
|
const aliveRef = useRef(true)
|
||||||
const retryRef = useRef<number | null>(null)
|
const retryRef = useRef<number | null>(null)
|
||||||
const wsRef = useRef<WebSocket | null>(null)
|
const wsRef = useRef<WebSocket | null>(null)
|
||||||
|
|
||||||
// Connect-Href laden (Passwort etc. aus DB)
|
// dock element (unter dem Main)
|
||||||
|
const [dockEl, setDockEl] = useState<HTMLElement | null>(null)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
if (typeof window === 'undefined') return
|
||||||
|
setDockEl(document.getElementById('telemetry-banner-dock') as HTMLElement | null)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// connect href from API
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
const r = await fetch('/api/cs2/server', { cache: 'no-store' })
|
const r = await fetch('/api/cs2/server', { cache: 'no-store' })
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
@ -71,6 +112,7 @@ export default function TelemetrySocket() {
|
|||||||
})()
|
})()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// websocket connect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
aliveRef.current = true
|
aliveRef.current = true
|
||||||
|
|
||||||
@ -95,40 +137,70 @@ export default function TelemetrySocket() {
|
|||||||
try { msg = JSON.parse(String(ev.data ?? '')) } catch {}
|
try { msg = JSON.parse(String(ev.data ?? '')) } catch {}
|
||||||
if (!msg) return
|
if (!msg) return
|
||||||
|
|
||||||
if (msg.type === 'players' && Array.isArray(msg.players)) {
|
// --- server name (optional)
|
||||||
setSnapshot(msg.players)
|
if (msg.type === 'server' && typeof msg.name === 'string' && msg.name.trim()) {
|
||||||
// 👇 bin ich in der aktuellen Players-Liste?
|
setServerName(msg.name.trim())
|
||||||
if (mySteamId) {
|
|
||||||
const present = msg.players.some((p: any) =>
|
|
||||||
String(p?.steamId ?? p?.steam_id ?? p?.id) === String(mySteamId)
|
|
||||||
)
|
|
||||||
setMyConnected(present)
|
|
||||||
}
|
|
||||||
} else if (msg.type === 'player_join' && msg.player) {
|
|
||||||
setJoin(msg.player)
|
|
||||||
// 👇 falls ich join:
|
|
||||||
const sid = msg.player?.steamId ?? msg.player?.steam_id ?? msg.player?.id
|
|
||||||
if (mySteamId && String(sid) === String(mySteamId)) setMyConnected(true)
|
|
||||||
} else if (msg.type === 'player_leave') {
|
|
||||||
const sid = msg.steamId ?? msg.steam_id ?? msg.id
|
|
||||||
if (sid != null) setLeave(sid)
|
|
||||||
// 👇 falls ich leave:
|
|
||||||
if (mySteamId && String(sid) === String(mySteamId)) setMyConnected(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map (inkl. optionaler Phase)
|
// --- full roster
|
||||||
if (msg.type === 'map' && typeof msg.name === 'string') {
|
if (msg.type === 'players' && Array.isArray(msg.players)) {
|
||||||
const key = msg.name.toLowerCase()
|
setSnapshot(msg.players)
|
||||||
if (process.env.NODE_ENV!=='production') console.debug('[TelemetrySocket] map:', key)
|
const ids = msg.players.map(sidOf).filter(Boolean)
|
||||||
setMapKey(key)
|
setTelemetrySet(toSet(ids))
|
||||||
if (typeof msg.phase === 'string') {
|
if (mySteamId) {
|
||||||
setPhase(String(msg.phase).toLowerCase() as any)
|
const present = msg.players.some((p: any) => sidOf(p) === String(mySteamId))
|
||||||
|
if (present) hideOverlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reine Phase-Events
|
|
||||||
|
// --- incremental roster
|
||||||
|
if (msg.type === 'player_join' && msg.player) {
|
||||||
|
setJoin(msg.player)
|
||||||
|
setTelemetrySet(prev => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
const sid = sidOf(msg.player)
|
||||||
|
if (sid) next.add(sid)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
const sid = sidOf(msg.player)
|
||||||
|
if (mySteamId && sid && sid === String(mySteamId)) hideOverlay()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.type === 'player_leave') {
|
||||||
|
const sid = String(msg.steamId ?? msg.steam_id ?? msg.id ?? '')
|
||||||
|
if (sid) setLeave(sid)
|
||||||
|
setTelemetrySet(prev => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
if (sid) next.delete(sid)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- map: NUR map + optional serverName, NICHT die Phase übernehmen
|
||||||
|
if (msg.type === 'map' && typeof msg.name === 'string') {
|
||||||
|
const key = msg.name.toLowerCase()
|
||||||
|
setMapKey(key)
|
||||||
|
setMapKeyForUi(key)
|
||||||
|
if (typeof msg.serverName === 'string' && msg.serverName.trim()) {
|
||||||
|
setServerName(msg.serverName.trim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- phase: AUSSCHLIESSLICHE Quelle für die Phase
|
||||||
if (msg.type === 'phase' && typeof msg.phase === 'string') {
|
if (msg.type === 'phase' && typeof msg.phase === 'string') {
|
||||||
setPhase(String(msg.phase).toLowerCase() as any)
|
setPhase(String(msg.phase).toLowerCase() as any)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- score (unverändert)
|
||||||
|
if (msg.type === 'score') {
|
||||||
|
const a = Number(msg.team1 ?? msg.ct)
|
||||||
|
const b = Number(msg.team2 ?? msg.t)
|
||||||
|
setScore({ a: Number.isFinite(a) ? a : null, b: Number.isFinite(b) ? b : null })
|
||||||
|
} else if (msg.score) {
|
||||||
|
const a = Number(msg.score.team1 ?? msg.score.ct)
|
||||||
|
const b = Number(msg.score.team2 ?? msg.score.t)
|
||||||
|
setScore({ a: Number.isFinite(a) ? a : null, b: Number.isFinite(b) ? b : null })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,61 +210,87 @@ export default function TelemetrySocket() {
|
|||||||
if (retryRef.current) window.clearTimeout(retryRef.current)
|
if (retryRef.current) window.clearTimeout(retryRef.current)
|
||||||
try { wsRef.current?.close(1000, 'telemetry socket unmounted') } catch {}
|
try { wsRef.current?.close(1000, 'telemetry socket unmounted') } catch {}
|
||||||
}
|
}
|
||||||
}, [url, setSnapshot, setJoin, setLeave, setMapKey, setPhase, mySteamId])
|
}, [url, setSnapshot, setJoin, setLeave, setMapKey, setPhase, hideOverlay, mySteamId])
|
||||||
|
|
||||||
// Anzeige-Logik Banner:
|
// ----- banner logic (connected + disconnected variants) with roster fallback
|
||||||
// - Ich bin im Roster (Match wurde geladen & ich bin Teilnehmer)
|
const myId = mySteamId ? String(mySteamId) : null
|
||||||
// - Match-Phase live
|
const roster =
|
||||||
// - Ich bin NICHT connected (disconnect)
|
rosterSet instanceof Set && rosterSet.size > 0
|
||||||
const meInRoster = !!mySteamId && rosterSet instanceof Set && rosterSet.has(String(mySteamId))
|
? rosterSet
|
||||||
const shouldShow = !dismissed && (phase === 'live') && meInRoster && !myConnected
|
: (myId ? new Set<string>([myId]) : new Set<string>())
|
||||||
|
|
||||||
|
const iAmExpected = !!myId && roster.has(myId)
|
||||||
|
const iAmOnline = !!myId && telemetrySet.has(myId)
|
||||||
|
|
||||||
|
const intersectCount = (() => {
|
||||||
|
if (roster.size === 0) return 0
|
||||||
|
let n = 0
|
||||||
|
for (const sid of roster) if (telemetrySet.has(sid)) n++
|
||||||
|
return n
|
||||||
|
})()
|
||||||
|
const totalExpected = roster.size
|
||||||
|
|
||||||
const connectUri =
|
const connectUri =
|
||||||
connectHref // ⬅️ bevorzugt API-Route (inkl. Passwort)
|
connectHref ||
|
||||||
|| process.env.NEXT_PUBLIC_STEAM_CONNECT_URI
|
process.env.NEXT_PUBLIC_STEAM_CONNECT_URI ||
|
||||||
|| process.env.NEXT_PUBLIC_CS2_CONNECT_URI
|
process.env.NEXT_PUBLIC_CS2_CONNECT_URI ||
|
||||||
|| 'steam://rungameid/730//+retry' // Fallback
|
'steam://rungameid/730//+retry'
|
||||||
|
|
||||||
|
// Fallback-Label aus URI, falls kein Servername vom WS kam
|
||||||
|
const fallbackServerLabel = parseServerLabel(connectUri)
|
||||||
|
const effectiveServerLabel = (serverName && serverName.trim()) || fallbackServerLabel
|
||||||
|
|
||||||
|
const prettyPhase = phase ?? 'unknown'
|
||||||
|
const prettyScore = (score.a == null || score.b == null) ? '– : –' : `${score.a} : ${score.b}`
|
||||||
|
const prettyMapLabel = labelForMap(mapKeyForUi)
|
||||||
|
|
||||||
const handleReconnect = () => {
|
const handleReconnect = () => {
|
||||||
try {
|
try { window.location.href = connectUri } catch {}
|
||||||
window.location.href = connectUri
|
|
||||||
} catch {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const handleDisconnect = () => {
|
||||||
<>
|
// Auto-Reconnect stoppen
|
||||||
{/* WebSocket-Client selbst rendert nichts */}
|
aliveRef.current = false;
|
||||||
{shouldShow && (
|
if (retryRef.current) {
|
||||||
<div className="fixed inset-x-0 bottom-0 z-[9999] mx-auto mb-3 max-w-3xl">
|
window.clearTimeout(retryRef.current);
|
||||||
<div className="mx-3 rounded-md bg-neutral-900/95 text-white shadow-lg ring-1 ring-black/10">
|
retryRef.current = null;
|
||||||
<div className="p-3 flex items-center gap-3">
|
}
|
||||||
<div className="flex-1">
|
|
||||||
<div className="text-sm font-semibold">Match läuft · Reconnect verfügbar</div>
|
// WebSocket sauber schließen
|
||||||
<div className="text-xs opacity-80">
|
try { wsRef.current?.close(1000, 'user requested disconnect') } catch {}
|
||||||
Du bist im aufgesetzten Match eingetragen. Klicke „Reconnect“, um wieder zu joinen.
|
wsRef.current = null;
|
||||||
</div>
|
|
||||||
</div>
|
// Lokalen Zustand zurücksetzen (wir bleiben im "disconnected"-Banner)
|
||||||
<div className="flex items-center gap-2">
|
setTelemetrySet(new Set());
|
||||||
<button
|
setServerName(null);
|
||||||
onClick={handleReconnect}
|
setMapKeyForUi(null);
|
||||||
className="px-3 py-1.5 rounded bg-emerald-500 hover:bg-emerald-600 text-sm font-semibold"
|
setPhase('unknown' as any);
|
||||||
>
|
setScore({ a: null, b: null });
|
||||||
Reconnect
|
};
|
||||||
</button>
|
|
||||||
<button
|
const variant: 'connected' | 'disconnected' = iAmOnline ? 'connected' : 'disconnected'
|
||||||
onClick={() => setDismissed(true)}
|
const visible = iAmExpected
|
||||||
className="px-2 py-1 rounded bg-neutral-700 hover:bg-neutral-600 text-xs"
|
const zIndex = iAmOnline ? 9998 : 9999
|
||||||
aria-label="schließen"
|
|
||||||
>
|
const bannerEl = (
|
||||||
✕
|
<TelemetryBanner
|
||||||
</button>
|
variant={variant}
|
||||||
</div>
|
visible={visible}
|
||||||
</div>
|
zIndex={zIndex}
|
||||||
</div>
|
inline={!!dockEl}
|
||||||
</div>
|
connectedCount={intersectCount}
|
||||||
)}
|
totalExpected={totalExpected}
|
||||||
</>
|
connectUri={connectUri}
|
||||||
|
onReconnect={handleReconnect}
|
||||||
|
onDisconnect={handleDisconnect}
|
||||||
|
serverLabel={effectiveServerLabel}
|
||||||
|
mapKey={mapKeyForUi ?? undefined}
|
||||||
|
mapLabel={prettyMapLabel}
|
||||||
|
phase={prettyPhase}
|
||||||
|
score={prettyScore}
|
||||||
|
missingCount={totalExpected - intersectCount}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return dockEl ? createPortal(bannerEl, dockEl) : bannerEl
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/components/UserAvatarWithStatus.tsx
|
// /src/app/components/UserAvatarWithStatus.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState, useMemo } from 'react'
|
import { useEffect, useState, useMemo } from 'react'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/components/UserHeader.tsx
|
// /src/app/components/UserHeader.tsx
|
||||||
import { Tabs } from '@/app/components/Tabs'
|
import { Tabs } from '@/app/components/Tabs'
|
||||||
import PremierRankBadge from './PremierRankBadge'
|
import PremierRankBadge from './PremierRankBadge'
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// /src/app/components/admin/teams/AdminTeamsView.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState, useRef, useCallback } from 'react'
|
import { useEffect, useState, useRef, useCallback } from 'react'
|
||||||
@ -25,9 +27,15 @@ export default function AdminTeamsView() {
|
|||||||
const fetchTeams = useCallback(async () => {
|
const fetchTeams = useCallback(async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/teams')
|
const res = await fetch('/api/teams', { cache: 'no-store' })
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
setTeams(json.teams ?? [])
|
|
||||||
|
// robust parsen: Array ODER Objekt mit teams/items
|
||||||
|
const list: Team[] = Array.isArray(json)
|
||||||
|
? json
|
||||||
|
: (json?.teams ?? json?.items ?? [])
|
||||||
|
|
||||||
|
setTeams(list)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[AdminTeamsView] /api/teams:', err)
|
console.error('[AdminTeamsView] /api/teams:', err)
|
||||||
setTeams([])
|
setTeams([])
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// /src/app/components/profile/[steamId]/matches/UserMatchesList.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useRef, useState, useCallback } from 'react'
|
import { useEffect, useRef, useState, useCallback } from 'react'
|
||||||
@ -230,13 +232,47 @@ export default function UserMatchesList({ steamId }: { steamId: string }) {
|
|||||||
>
|
>
|
||||||
<Table.Cell hoverable>
|
<Table.Cell hoverable>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<img
|
{(() => {
|
||||||
src={`/assets/img/mapicons/${m.map}.webp`}
|
const raw = m.map || ''
|
||||||
alt={mapInfo?.label}
|
const normKey = raw.replace(/^de_/, '') // "de_ancient" -> "ancient"
|
||||||
width={32}
|
|
||||||
height={32}
|
// 1) Versuch: exact normKey
|
||||||
/>
|
// 2) Versuch: raw (mit "de_")
|
||||||
{mapInfo?.label}
|
// 3) Versuch: wieder mit "de_" (falls m.map ohne Prefix kam)
|
||||||
|
const opt =
|
||||||
|
MAP_OPTIONS.find(o => o.key === normKey) ||
|
||||||
|
MAP_OPTIONS.find(o => o.key === raw) ||
|
||||||
|
MAP_OPTIONS.find(o => o.key === `de_${normKey}`) ||
|
||||||
|
null
|
||||||
|
|
||||||
|
const label =
|
||||||
|
opt?.label ||
|
||||||
|
normKey || // sinnvoller Text, falls alles fehlt
|
||||||
|
'Map'
|
||||||
|
|
||||||
|
// Icon-Quelle: erst aus MAP_OPTIONS, sonst generischer Pfad auf Basis des normKey
|
||||||
|
const iconSrc = opt?.icon || `/assets/img/mapicons/map_icon_${normKey}.svg`
|
||||||
|
|
||||||
|
// Debug (kannst du wieder entfernen)
|
||||||
|
// console.log({ raw, normKey, optKey: opt?.key, label, iconSrc })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<img
|
||||||
|
src={iconSrc}
|
||||||
|
alt={label}
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
className="shrink-0"
|
||||||
|
onError={(e) => {
|
||||||
|
(e.currentTarget as HTMLImageElement).src =
|
||||||
|
'/assets/img/mapicons/map_icon_lobby_mapveto.svg'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{label}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/components/radar/StaticEffects.tsx
|
// /src/app/components/radar/StaticEffects.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|||||||
@ -1,76 +1,54 @@
|
|||||||
|
// /src/app/dashboard/page.tsx
|
||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useSession } from 'next-auth/react'
|
import { useSession } from 'next-auth/react'
|
||||||
import Modal from '@/app/components/Modal'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import Button from '../components/Button'
|
|
||||||
import ComboBox from '../components/ComboBox'
|
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const { data: session, status } = useSession()
|
const { data: session, status } = useSession()
|
||||||
const [showTeamModal, setShowTeamModal] = useState(false)
|
|
||||||
const [teams, setTeams] = useState<string[]>([])
|
const [teams, setTeams] = useState<string[]>([])
|
||||||
const [selectedTeam, setSelectedTeam] = useState('')
|
const [selectedTeam, setSelectedTeam] = useState('')
|
||||||
|
|
||||||
|
// Teams laden (robust)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'authenticated' && !session?.user?.team) {
|
let abort = false
|
||||||
setShowTeamModal(true)
|
|
||||||
}
|
|
||||||
}, [session, status])
|
|
||||||
|
|
||||||
useEffect(() => {
|
async function fetchTeams() {
|
||||||
if (showTeamModal) {
|
|
||||||
const open = setTimeout(() => {
|
|
||||||
const modalEl = document.getElementById('hs-vertically-centered-modal')
|
|
||||||
if (modalEl && typeof window.HSOverlay?.open === 'function') {
|
|
||||||
try {
|
|
||||||
window.HSOverlay.open(modalEl)
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Fehler beim Öffnen des Modals:', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
return () => clearTimeout(open)
|
|
||||||
}
|
|
||||||
}, [showTeamModal])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchTeams = async () => {
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/teams')
|
const res = await fetch('/api/teams', { cache: 'no-store' })
|
||||||
const data = await res.json()
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||||
setTeams(data.teams.map((t: { teamname: string }) => t.teamname))
|
|
||||||
|
let json: any = null
|
||||||
|
try { json = await res.json() } catch {}
|
||||||
|
|
||||||
|
const teamsArr: any[] =
|
||||||
|
Array.isArray(json?.teams) ? json.teams :
|
||||||
|
Array.isArray(json?.data) ? json.data :
|
||||||
|
Array.isArray(json) ? json :
|
||||||
|
[]
|
||||||
|
|
||||||
|
if (!abort) {
|
||||||
|
setTeams(teamsArr.map((t) => t?.teamname ?? t?.name ?? 'Unbenannt'))
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fehler beim Laden der Teams:', error)
|
console.error('Fehler beim Laden der Teams:', error)
|
||||||
|
if (!abort) setTeams([])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchTeams()
|
fetchTeams()
|
||||||
|
return () => { abort = true }
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showTeamModal && (
|
|
||||||
<Modal
|
|
||||||
title="Kein Team gefunden"
|
|
||||||
show={true}
|
|
||||||
id="no-team-modal"
|
|
||||||
closeButtonColor="blue"
|
|
||||||
hideCloseButton
|
|
||||||
>
|
|
||||||
<p className="text-sm text-gray-700 dark:text-neutral-300">
|
|
||||||
Du bist aktuell keinem Team beigetreten. Bitte tritt einem Team bei oder erstelle eines.
|
|
||||||
</p>
|
|
||||||
<Link href='/settings/team' className='center'>
|
|
||||||
<Button title='Team auswählen'></Button>
|
|
||||||
</Link>
|
|
||||||
</Modal>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<h1 className="text-2xl font-bold mb-4 text-gray-800 dark:text-white">
|
<h1 className="text-2xl font-bold mb-4 text-gray-800 dark:text-white">
|
||||||
Willkommen im Dashboard!
|
Willkommen im Dashboard!
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
{/* Beispiel: Teams anzeigen (optional) */}
|
||||||
|
{/* <pre className="text-xs opacity-70">{JSON.stringify(teams, null, 2)}</pre> */}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -53,6 +53,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
<div id="telemetry-banner-dock" className="h-full max-h-[65px]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,6 @@ export const MAP_OPTIONS: MapOption[] = [
|
|||||||
'de_dust2_1_png.webp',
|
'de_dust2_1_png.webp',
|
||||||
'de_dust2_2_png.webp',
|
'de_dust2_2_png.webp',
|
||||||
'de_dust2_3_png.webp',
|
'de_dust2_3_png.webp',
|
||||||
'de_dust2_4_png.webp',
|
|
||||||
'de_dust2_png.webp',
|
'de_dust2_png.webp',
|
||||||
]),
|
]),
|
||||||
icon: iconFor('de_dust2'),
|
icon: iconFor('de_dust2'),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/lib/prisma.ts
|
// /src/lib/prisma.ts
|
||||||
import { PrismaClient } from '@/generated/prisma'
|
import { PrismaClient } from '@/generated/prisma'
|
||||||
|
|
||||||
const globalForPrisma = globalThis as unknown as {
|
const globalForPrisma = globalThis as unknown as {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/lib/signOutWithStatus.ts
|
// /src/app/lib/signOutWithStatus.ts
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { signOut } from 'next-auth/react'
|
import { signOut } from 'next-auth/react'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/lib/sseEvents.ts
|
// /src/app/lib/sseEvents.ts
|
||||||
|
|
||||||
export const SSE_EVENT_TYPES = [
|
export const SSE_EVENT_TYPES = [
|
||||||
// Kanonisch
|
// Kanonisch
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/lib/useMatchRosterStore.ts
|
// /src/app/lib/useMatchRosterStore.ts
|
||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
import { persist } from 'zustand/middleware'
|
import { persist } from 'zustand/middleware'
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/lib/useTelemetryStore.ts
|
// /src/app/lib/useTelemetryStore.ts
|
||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
|
|
||||||
type TelemetryState = {
|
type TelemetryState = {
|
||||||
|
|||||||
12
src/app/lib/useUiChromeStore.ts
Normal file
12
src/app/lib/useUiChromeStore.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
'use client'
|
||||||
|
import { create } from 'zustand'
|
||||||
|
|
||||||
|
type UiChromeState = {
|
||||||
|
telemetryBannerPx: number // aktuelle Bannerhöhe in Pixel (0 wenn unsichtbar)
|
||||||
|
setTelemetryBannerPx: (px: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUiChromeStore = create<UiChromeState>((set) => ({
|
||||||
|
telemetryBannerPx: 0,
|
||||||
|
setTelemetryBannerPx: (px) => set({ telemetryBannerPx: Math.max(0, Math.floor(px)) }),
|
||||||
|
}))
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/profile/[steamId]/layout.tsx
|
// /src/app/profile/[steamId]/layout.tsx
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { notFound } from 'next/navigation'
|
import { notFound } from 'next/navigation'
|
||||||
import { prisma } from '@/app/lib/prisma'
|
import { prisma } from '@/app/lib/prisma'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/profile/[steamId]/matches/page.tsx
|
// /src/app/profile/[steamId]/matches/page.tsx
|
||||||
import Card from '@/app/components/Card'
|
import Card from '@/app/components/Card'
|
||||||
import UserMatchesList from '@/app/components/profile/[steamId]/matches/UserMatchesList'
|
import UserMatchesList from '@/app/components/profile/[steamId]/matches/UserMatchesList'
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/profile/[steamId]/page.tsx
|
// /src/app/profile/[steamId]/page.tsx
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
export default function ProfileRedirect({ params }: { params: { steamId: string } }) {
|
export default function ProfileRedirect({ params }: { params: { steamId: string } }) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/profile/[steamId]/stats/page.tsx
|
// /src/app/profile/[steamId]/stats/page.tsx
|
||||||
import UserProfile from '@/app/components/profile/[steamId]/stats/UserProfile'
|
import UserProfile from '@/app/components/profile/[steamId]/stats/UserProfile'
|
||||||
import { MatchStats } from '@/app/types/match'
|
import { MatchStats } from '@/app/types/match'
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/components/radar/LiveRadar.tsx
|
// /src/app/components/radar/LiveRadar.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/team/[teamId]/page.tsx
|
// /src/app/team/[teamId]/page.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState, KeyboardEvent, MouseEvent } from 'react'
|
import { useEffect, useState, KeyboardEvent, MouseEvent } from 'react'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// /app/team/page.tsx
|
// /src/app/team/page.tsx
|
||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
|||||||
173
src/app/teams/page.tsx
Normal file
173
src/app/teams/page.tsx
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// /app/teams/page.tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState, useCallback } from 'react'
|
||||||
|
import { useSession } from 'next-auth/react'
|
||||||
|
import Button from '@/app/components/Button'
|
||||||
|
import Modal from '@/app/components/Modal'
|
||||||
|
import Input from '@/app/components/Input'
|
||||||
|
import TeamCard from '@/app/components/TeamCard'
|
||||||
|
import LoadingSpinner from '@/app/components/LoadingSpinner'
|
||||||
|
import type { Team } from '@/app/types/team'
|
||||||
|
import Card from '../components/Card'
|
||||||
|
|
||||||
|
type TeamsResp = any
|
||||||
|
type InvitesResp = { invitations?: any[] } | any
|
||||||
|
type UserResp = { team?: any } | any
|
||||||
|
|
||||||
|
export default function TeamsPage() {
|
||||||
|
const { data: session } = useSession()
|
||||||
|
const mySteamId = (session?.user as any)?.steamId ?? ''
|
||||||
|
|
||||||
|
const [teams, setTeams] = useState<Team[]>([])
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
|
const [invitationMap, setInvitationMap] = useState<Record<string, string>>({})
|
||||||
|
const [showCreate, setShowCreate] = useState(false)
|
||||||
|
const [newName, setNewName] = useState('')
|
||||||
|
const [saving, setSaving] = useState(false)
|
||||||
|
|
||||||
|
// NEU: Flag aus /api/user
|
||||||
|
const [userHasTeam, setUserHasTeam] = useState<boolean>(false)
|
||||||
|
|
||||||
|
const parseTeams = (data: TeamsResp): Team[] => {
|
||||||
|
if (Array.isArray(data)) return data
|
||||||
|
return (data?.items ?? data?.teams ?? []) as Team[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchAll = useCallback(async () => {
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const [tRes, iRes, uRes] = await Promise.all([
|
||||||
|
fetch('/api/teams', { cache: 'no-store' }),
|
||||||
|
fetch('/api/user/invitations', { cache: 'no-store' }),
|
||||||
|
fetch('/api/user', { cache: 'no-store' }), // ⬅️ eigene Team-Mitgliedschaft
|
||||||
|
])
|
||||||
|
|
||||||
|
const [tJson, iJson, uJson]: [TeamsResp, InvitesResp, UserResp] = await Promise.all([
|
||||||
|
tRes.json(),
|
||||||
|
iRes.json().catch(() => ({} as any)),
|
||||||
|
uRes.ok ? uRes.json() : ({} as any),
|
||||||
|
])
|
||||||
|
|
||||||
|
const nextTeams = parseTeams(tJson)
|
||||||
|
const nextMap: Record<string, string> = {}
|
||||||
|
|
||||||
|
const invites = Array.isArray(iJson) ? iJson : (iJson?.invitations ?? [])
|
||||||
|
for (const inv of invites) {
|
||||||
|
if (inv?.type === 'team-join-request' && inv?.teamId && inv?.id) {
|
||||||
|
nextMap[inv.teamId] = inv.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTeams(nextTeams)
|
||||||
|
setInvitationMap(nextMap)
|
||||||
|
setUserHasTeam(!!uJson?.team) // ⬅️ entscheidend
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[TeamsPage] load failed:', err)
|
||||||
|
setTeams([])
|
||||||
|
setInvitationMap({})
|
||||||
|
setUserHasTeam(false)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const fetchedOnce = useRef(false)
|
||||||
|
useEffect(() => {
|
||||||
|
if (fetchedOnce.current) return
|
||||||
|
fetchedOnce.current = true
|
||||||
|
fetchAll()
|
||||||
|
}, [fetchAll])
|
||||||
|
|
||||||
|
const createTeam = async () => {
|
||||||
|
if (!newName.trim()) return
|
||||||
|
setSaving(true)
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/team/create', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ teamname: newName.trim() }),
|
||||||
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
const j = await res.json().catch(() => ({}))
|
||||||
|
alert(j?.message ?? 'Team konnte nicht erstellt werden.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await fetchAll()
|
||||||
|
setShowCreate(false)
|
||||||
|
setNewName('')
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[TeamsPage] createTeam:', e)
|
||||||
|
alert('Team konnte nicht erstellt werden.')
|
||||||
|
} finally {
|
||||||
|
setSaving(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="text-gray-500 dark:text-gray-400">
|
||||||
|
<LoadingSpinner />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur anzeigen, wenn der Spieler in KEINEM Team ist
|
||||||
|
const canRequestJoin = !userHasTeam
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card maxWidth='full'>
|
||||||
|
<div className="flex justify-between items-center mb-6">
|
||||||
|
<h2 className="text-lg font-semibold text-gray-800 dark:text-white">
|
||||||
|
Teams verwalten
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<Button color="blue" onClick={() => setShowCreate(true)}>
|
||||||
|
Neues Team erstellen
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{teams.length === 0 ? (
|
||||||
|
<div className="text-gray-500 dark:text-gray-400">
|
||||||
|
Es wurden noch keine Teams erstellt.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{teams.map((t) => (
|
||||||
|
<TeamCard
|
||||||
|
key={t.id}
|
||||||
|
team={t}
|
||||||
|
currentUserSteamId={mySteamId}
|
||||||
|
invitationId={invitationMap[t.id]}
|
||||||
|
onUpdateInvitation={(teamId, inviteId) =>
|
||||||
|
setInvitationMap((prev) => ({ ...prev, [teamId]: inviteId }))
|
||||||
|
}
|
||||||
|
canRequestJoin={canRequestJoin} // ⬅️ Button-Logik
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
id="create-team-modal"
|
||||||
|
title="Neues Team erstellen"
|
||||||
|
show={showCreate}
|
||||||
|
onClose={() => {
|
||||||
|
setShowCreate(false)
|
||||||
|
setNewName('')
|
||||||
|
}}
|
||||||
|
onSave={createTeam}
|
||||||
|
closeButtonColor="blue"
|
||||||
|
closeButtonTitle={saving ? 'Speichern …' : 'Erstellen'}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
label="Teamname"
|
||||||
|
value={newName}
|
||||||
|
placeholder="z. B. Ironie eSports"
|
||||||
|
onChange={(e) => setNewName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// src/app/types/match.ts
|
// /src/app/types/match.ts
|
||||||
|
|
||||||
import { Player, Team } from './team'
|
import { Player, Team } from './team'
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -186,7 +186,9 @@ exports.Prisma.MatchScalarFieldEnum = {
|
|||||||
bestOf: 'bestOf',
|
bestOf: 'bestOf',
|
||||||
matchDate: 'matchDate',
|
matchDate: 'matchDate',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt'
|
updatedAt: 'updatedAt',
|
||||||
|
cs2MatchId: 'cs2MatchId',
|
||||||
|
exportedAt: 'exportedAt'
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Prisma.MatchPlayerScalarFieldEnum = {
|
exports.Prisma.MatchPlayerScalarFieldEnum = {
|
||||||
|
|||||||
162
src/generated/prisma/index.d.ts
vendored
162
src/generated/prisma/index.d.ts
vendored
@ -7604,6 +7604,7 @@ export namespace Prisma {
|
|||||||
scoreB: number | null
|
scoreB: number | null
|
||||||
roundCount: number | null
|
roundCount: number | null
|
||||||
bestOf: number | null
|
bestOf: number | null
|
||||||
|
cs2MatchId: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchSumAggregateOutputType = {
|
export type MatchSumAggregateOutputType = {
|
||||||
@ -7611,6 +7612,7 @@ export namespace Prisma {
|
|||||||
scoreB: number | null
|
scoreB: number | null
|
||||||
roundCount: number | null
|
roundCount: number | null
|
||||||
bestOf: number | null
|
bestOf: number | null
|
||||||
|
cs2MatchId: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMinAggregateOutputType = {
|
export type MatchMinAggregateOutputType = {
|
||||||
@ -7631,6 +7633,8 @@ export namespace Prisma {
|
|||||||
matchDate: Date | null
|
matchDate: Date | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
|
cs2MatchId: number | null
|
||||||
|
exportedAt: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMaxAggregateOutputType = {
|
export type MatchMaxAggregateOutputType = {
|
||||||
@ -7651,6 +7655,8 @@ export namespace Prisma {
|
|||||||
matchDate: Date | null
|
matchDate: Date | null
|
||||||
createdAt: Date | null
|
createdAt: Date | null
|
||||||
updatedAt: Date | null
|
updatedAt: Date | null
|
||||||
|
cs2MatchId: number | null
|
||||||
|
exportedAt: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchCountAggregateOutputType = {
|
export type MatchCountAggregateOutputType = {
|
||||||
@ -7673,6 +7679,8 @@ export namespace Prisma {
|
|||||||
matchDate: number
|
matchDate: number
|
||||||
createdAt: number
|
createdAt: number
|
||||||
updatedAt: number
|
updatedAt: number
|
||||||
|
cs2MatchId: number
|
||||||
|
exportedAt: number
|
||||||
_all: number
|
_all: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7682,6 +7690,7 @@ export namespace Prisma {
|
|||||||
scoreB?: true
|
scoreB?: true
|
||||||
roundCount?: true
|
roundCount?: true
|
||||||
bestOf?: true
|
bestOf?: true
|
||||||
|
cs2MatchId?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchSumAggregateInputType = {
|
export type MatchSumAggregateInputType = {
|
||||||
@ -7689,6 +7698,7 @@ export namespace Prisma {
|
|||||||
scoreB?: true
|
scoreB?: true
|
||||||
roundCount?: true
|
roundCount?: true
|
||||||
bestOf?: true
|
bestOf?: true
|
||||||
|
cs2MatchId?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMinAggregateInputType = {
|
export type MatchMinAggregateInputType = {
|
||||||
@ -7709,6 +7719,8 @@ export namespace Prisma {
|
|||||||
matchDate?: true
|
matchDate?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
|
cs2MatchId?: true
|
||||||
|
exportedAt?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMaxAggregateInputType = {
|
export type MatchMaxAggregateInputType = {
|
||||||
@ -7729,6 +7741,8 @@ export namespace Prisma {
|
|||||||
matchDate?: true
|
matchDate?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
|
cs2MatchId?: true
|
||||||
|
exportedAt?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchCountAggregateInputType = {
|
export type MatchCountAggregateInputType = {
|
||||||
@ -7751,6 +7765,8 @@ export namespace Prisma {
|
|||||||
matchDate?: true
|
matchDate?: true
|
||||||
createdAt?: true
|
createdAt?: true
|
||||||
updatedAt?: true
|
updatedAt?: true
|
||||||
|
cs2MatchId?: true
|
||||||
|
exportedAt?: true
|
||||||
_all?: true
|
_all?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7860,6 +7876,8 @@ export namespace Prisma {
|
|||||||
matchDate: Date | null
|
matchDate: Date | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
cs2MatchId: number | null
|
||||||
|
exportedAt: Date | null
|
||||||
_count: MatchCountAggregateOutputType | null
|
_count: MatchCountAggregateOutputType | null
|
||||||
_avg: MatchAvgAggregateOutputType | null
|
_avg: MatchAvgAggregateOutputType | null
|
||||||
_sum: MatchSumAggregateOutputType | null
|
_sum: MatchSumAggregateOutputType | null
|
||||||
@ -7901,6 +7919,8 @@ export namespace Prisma {
|
|||||||
matchDate?: boolean
|
matchDate?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
|
cs2MatchId?: boolean
|
||||||
|
exportedAt?: boolean
|
||||||
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
||||||
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
||||||
teamAUsers?: boolean | Match$teamAUsersArgs<ExtArgs>
|
teamAUsers?: boolean | Match$teamAUsersArgs<ExtArgs>
|
||||||
@ -7934,6 +7954,8 @@ export namespace Prisma {
|
|||||||
matchDate?: boolean
|
matchDate?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
|
cs2MatchId?: boolean
|
||||||
|
exportedAt?: boolean
|
||||||
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
||||||
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["match"]>
|
}, ExtArgs["result"]["match"]>
|
||||||
@ -7958,6 +7980,8 @@ export namespace Prisma {
|
|||||||
matchDate?: boolean
|
matchDate?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
|
cs2MatchId?: boolean
|
||||||
|
exportedAt?: boolean
|
||||||
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
||||||
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["match"]>
|
}, ExtArgs["result"]["match"]>
|
||||||
@ -7982,9 +8006,11 @@ export namespace Prisma {
|
|||||||
matchDate?: boolean
|
matchDate?: boolean
|
||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
|
cs2MatchId?: boolean
|
||||||
|
exportedAt?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "title" | "matchType" | "map" | "description" | "scoreA" | "scoreB" | "teamAId" | "teamBId" | "filePath" | "demoDate" | "demoData" | "roundCount" | "roundHistory" | "winnerTeam" | "bestOf" | "matchDate" | "createdAt" | "updatedAt", ExtArgs["result"]["match"]>
|
export type MatchOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "title" | "matchType" | "map" | "description" | "scoreA" | "scoreB" | "teamAId" | "teamBId" | "filePath" | "demoDate" | "demoData" | "roundCount" | "roundHistory" | "winnerTeam" | "bestOf" | "matchDate" | "createdAt" | "updatedAt" | "cs2MatchId" | "exportedAt", ExtArgs["result"]["match"]>
|
||||||
export type MatchInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
|
export type MatchInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
|
||||||
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
teamA?: boolean | Match$teamAArgs<ExtArgs>
|
||||||
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
teamB?: boolean | Match$teamBArgs<ExtArgs>
|
||||||
@ -8041,6 +8067,8 @@ export namespace Prisma {
|
|||||||
matchDate: Date | null
|
matchDate: Date | null
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
cs2MatchId: number | null
|
||||||
|
exportedAt: Date | null
|
||||||
}, ExtArgs["result"]["match"]>
|
}, ExtArgs["result"]["match"]>
|
||||||
composites: {}
|
composites: {}
|
||||||
}
|
}
|
||||||
@ -8493,6 +8521,8 @@ export namespace Prisma {
|
|||||||
readonly matchDate: FieldRef<"Match", 'DateTime'>
|
readonly matchDate: FieldRef<"Match", 'DateTime'>
|
||||||
readonly createdAt: FieldRef<"Match", 'DateTime'>
|
readonly createdAt: FieldRef<"Match", 'DateTime'>
|
||||||
readonly updatedAt: FieldRef<"Match", 'DateTime'>
|
readonly updatedAt: FieldRef<"Match", 'DateTime'>
|
||||||
|
readonly cs2MatchId: FieldRef<"Match", 'Int'>
|
||||||
|
readonly exportedAt: FieldRef<"Match", 'DateTime'>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -20998,7 +21028,9 @@ export namespace Prisma {
|
|||||||
bestOf: 'bestOf',
|
bestOf: 'bestOf',
|
||||||
matchDate: 'matchDate',
|
matchDate: 'matchDate',
|
||||||
createdAt: 'createdAt',
|
createdAt: 'createdAt',
|
||||||
updatedAt: 'updatedAt'
|
updatedAt: 'updatedAt',
|
||||||
|
cs2MatchId: 'cs2MatchId',
|
||||||
|
exportedAt: 'exportedAt'
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MatchScalarFieldEnum = (typeof MatchScalarFieldEnum)[keyof typeof MatchScalarFieldEnum]
|
export type MatchScalarFieldEnum = (typeof MatchScalarFieldEnum)[keyof typeof MatchScalarFieldEnum]
|
||||||
@ -21734,6 +21766,8 @@ export namespace Prisma {
|
|||||||
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
createdAt?: DateTimeFilter<"Match"> | Date | string
|
createdAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
|
cs2MatchId?: IntNullableFilter<"Match"> | number | null
|
||||||
|
exportedAt?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
||||||
teamB?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
teamB?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
||||||
teamAUsers?: UserListRelationFilter
|
teamAUsers?: UserListRelationFilter
|
||||||
@ -21766,6 +21800,8 @@ export namespace Prisma {
|
|||||||
matchDate?: SortOrderInput | SortOrder
|
matchDate?: SortOrderInput | SortOrder
|
||||||
createdAt?: SortOrder
|
createdAt?: SortOrder
|
||||||
updatedAt?: SortOrder
|
updatedAt?: SortOrder
|
||||||
|
cs2MatchId?: SortOrderInput | SortOrder
|
||||||
|
exportedAt?: SortOrderInput | SortOrder
|
||||||
teamA?: TeamOrderByWithRelationInput
|
teamA?: TeamOrderByWithRelationInput
|
||||||
teamB?: TeamOrderByWithRelationInput
|
teamB?: TeamOrderByWithRelationInput
|
||||||
teamAUsers?: UserOrderByRelationAggregateInput
|
teamAUsers?: UserOrderByRelationAggregateInput
|
||||||
@ -21801,6 +21837,8 @@ export namespace Prisma {
|
|||||||
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
createdAt?: DateTimeFilter<"Match"> | Date | string
|
createdAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
|
cs2MatchId?: IntNullableFilter<"Match"> | number | null
|
||||||
|
exportedAt?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
||||||
teamB?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
teamB?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
|
||||||
teamAUsers?: UserListRelationFilter
|
teamAUsers?: UserListRelationFilter
|
||||||
@ -21833,6 +21871,8 @@ export namespace Prisma {
|
|||||||
matchDate?: SortOrderInput | SortOrder
|
matchDate?: SortOrderInput | SortOrder
|
||||||
createdAt?: SortOrder
|
createdAt?: SortOrder
|
||||||
updatedAt?: SortOrder
|
updatedAt?: SortOrder
|
||||||
|
cs2MatchId?: SortOrderInput | SortOrder
|
||||||
|
exportedAt?: SortOrderInput | SortOrder
|
||||||
_count?: MatchCountOrderByAggregateInput
|
_count?: MatchCountOrderByAggregateInput
|
||||||
_avg?: MatchAvgOrderByAggregateInput
|
_avg?: MatchAvgOrderByAggregateInput
|
||||||
_max?: MatchMaxOrderByAggregateInput
|
_max?: MatchMaxOrderByAggregateInput
|
||||||
@ -21863,6 +21903,8 @@ export namespace Prisma {
|
|||||||
matchDate?: DateTimeNullableWithAggregatesFilter<"Match"> | Date | string | null
|
matchDate?: DateTimeNullableWithAggregatesFilter<"Match"> | Date | string | null
|
||||||
createdAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
|
createdAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
|
||||||
updatedAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
|
updatedAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
|
||||||
|
cs2MatchId?: IntNullableWithAggregatesFilter<"Match"> | number | null
|
||||||
|
exportedAt?: DateTimeNullableWithAggregatesFilter<"Match"> | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchPlayerWhereInput = {
|
export type MatchPlayerWhereInput = {
|
||||||
@ -23152,6 +23194,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -23184,6 +23228,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -23212,6 +23258,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -23244,6 +23292,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -23274,6 +23324,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchUpdateManyMutationInput = {
|
export type MatchUpdateManyMutationInput = {
|
||||||
@ -23294,6 +23346,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchUncheckedUpdateManyInput = {
|
export type MatchUncheckedUpdateManyInput = {
|
||||||
@ -23316,6 +23370,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchPlayerCreateInput = {
|
export type MatchPlayerCreateInput = {
|
||||||
@ -24757,6 +24813,8 @@ export namespace Prisma {
|
|||||||
matchDate?: SortOrder
|
matchDate?: SortOrder
|
||||||
createdAt?: SortOrder
|
createdAt?: SortOrder
|
||||||
updatedAt?: SortOrder
|
updatedAt?: SortOrder
|
||||||
|
cs2MatchId?: SortOrder
|
||||||
|
exportedAt?: SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchAvgOrderByAggregateInput = {
|
export type MatchAvgOrderByAggregateInput = {
|
||||||
@ -24764,6 +24822,7 @@ export namespace Prisma {
|
|||||||
scoreB?: SortOrder
|
scoreB?: SortOrder
|
||||||
roundCount?: SortOrder
|
roundCount?: SortOrder
|
||||||
bestOf?: SortOrder
|
bestOf?: SortOrder
|
||||||
|
cs2MatchId?: SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMaxOrderByAggregateInput = {
|
export type MatchMaxOrderByAggregateInput = {
|
||||||
@ -24784,6 +24843,8 @@ export namespace Prisma {
|
|||||||
matchDate?: SortOrder
|
matchDate?: SortOrder
|
||||||
createdAt?: SortOrder
|
createdAt?: SortOrder
|
||||||
updatedAt?: SortOrder
|
updatedAt?: SortOrder
|
||||||
|
cs2MatchId?: SortOrder
|
||||||
|
exportedAt?: SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchMinOrderByAggregateInput = {
|
export type MatchMinOrderByAggregateInput = {
|
||||||
@ -24804,6 +24865,8 @@ export namespace Prisma {
|
|||||||
matchDate?: SortOrder
|
matchDate?: SortOrder
|
||||||
createdAt?: SortOrder
|
createdAt?: SortOrder
|
||||||
updatedAt?: SortOrder
|
updatedAt?: SortOrder
|
||||||
|
cs2MatchId?: SortOrder
|
||||||
|
exportedAt?: SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchSumOrderByAggregateInput = {
|
export type MatchSumOrderByAggregateInput = {
|
||||||
@ -24811,6 +24874,7 @@ export namespace Prisma {
|
|||||||
scoreB?: SortOrder
|
scoreB?: SortOrder
|
||||||
roundCount?: SortOrder
|
roundCount?: SortOrder
|
||||||
bestOf?: SortOrder
|
bestOf?: SortOrder
|
||||||
|
cs2MatchId?: SortOrder
|
||||||
}
|
}
|
||||||
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
|
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
|
||||||
| PatchUndefined<
|
| PatchUndefined<
|
||||||
@ -27636,6 +27700,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
@ -27667,6 +27733,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
||||||
@ -27699,6 +27767,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -27730,6 +27800,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
||||||
@ -28173,6 +28245,8 @@ export namespace Prisma {
|
|||||||
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
matchDate?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
createdAt?: DateTimeFilter<"Match"> | Date | string
|
createdAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
updatedAt?: DateTimeFilter<"Match"> | Date | string
|
||||||
|
cs2MatchId?: IntNullableFilter<"Match"> | number | null
|
||||||
|
exportedAt?: DateTimeNullableFilter<"Match"> | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchUpsertWithWhereUniqueWithoutTeamBUsersInput = {
|
export type MatchUpsertWithWhereUniqueWithoutTeamBUsersInput = {
|
||||||
@ -28670,6 +28744,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
@ -28700,6 +28776,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -28738,6 +28816,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
@ -28768,6 +28848,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -30174,6 +30256,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -30205,6 +30289,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -30425,6 +30511,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -30456,6 +30544,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -30738,6 +30828,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -30769,6 +30861,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -30881,6 +30975,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -30912,6 +31008,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -31143,6 +31241,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -31174,6 +31274,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -31445,6 +31547,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -31476,6 +31580,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -31503,6 +31609,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -31534,6 +31642,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
|
||||||
@ -31640,6 +31750,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -31671,6 +31783,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
||||||
@ -31899,6 +32013,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -31930,6 +32046,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -32003,6 +32121,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -32034,6 +32154,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -32369,6 +32491,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
|
||||||
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
|
||||||
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
@ -32400,6 +32524,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
teamAUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamAInput
|
||||||
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
teamBUsers?: UserUncheckedCreateNestedManyWithoutMatchesAsTeamBInput
|
||||||
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
|
||||||
@ -32506,6 +32632,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -32537,6 +32665,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -32732,6 +32862,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
@ -32763,6 +32895,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
||||||
@ -32792,6 +32926,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchUpdateWithoutTeamBUsersInput = {
|
export type MatchUpdateWithoutTeamBUsersInput = {
|
||||||
@ -32812,6 +32948,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
@ -32843,6 +32981,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
|
||||||
@ -32872,6 +33012,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TeamInviteUpdateWithoutUserInput = {
|
export type TeamInviteUpdateWithoutUserInput = {
|
||||||
@ -33222,6 +33364,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchCreateManyTeamBInput = {
|
export type MatchCreateManyTeamBInput = {
|
||||||
@ -33243,6 +33387,8 @@ export namespace Prisma {
|
|||||||
matchDate?: Date | string | null
|
matchDate?: Date | string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
cs2MatchId?: number | null
|
||||||
|
exportedAt?: Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ScheduleCreateManyTeamAInput = {
|
export type ScheduleCreateManyTeamAInput = {
|
||||||
@ -33421,6 +33567,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
@ -33451,6 +33599,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -33480,6 +33630,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MatchUpdateWithoutTeamBInput = {
|
export type MatchUpdateWithoutTeamBInput = {
|
||||||
@ -33500,6 +33652,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
|
||||||
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
@ -33530,6 +33684,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
teamAUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamANestedInput
|
||||||
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
teamBUsers?: UserUncheckedUpdateManyWithoutMatchesAsTeamBNestedInput
|
||||||
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
|
||||||
@ -33559,6 +33715,8 @@ export namespace Prisma {
|
|||||||
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
matchDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
cs2MatchId?: NullableIntFieldUpdateOperationsInput | number | null
|
||||||
|
exportedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ScheduleUpdateWithoutTeamAInput = {
|
export type ScheduleUpdateWithoutTeamAInput = {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "prisma-client-85c440bbfe4ddbdbf4749495c6ef753c2d4a73eb44baae0e95774ed8e7b86d85",
|
"name": "prisma-client-dccc49918d4c87081feec825d7e8f9d86eb03460cb722e1aeb3c8b2bf7d2181c",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"browser": "default.js",
|
"browser": "default.js",
|
||||||
|
|||||||
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp26516
Normal file
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp26516
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user