diff --git a/package-lock.json b/package-lock.json index 26fc1ca..2e88b59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,6 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "vanilla-calendar-pro": "^3.0.4", - "ws": "^8.18.1", "zustand": "^5.0.3" }, "devDependencies": { @@ -7503,27 +7502,6 @@ "node": ">=0.10.0" } }, - "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index bfda0c4..2cedb93 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "vanilla-calendar-pro": "^3.0.4", - "ws": "^8.18.1", "zustand": "^5.0.3" }, "devDependencies": { diff --git a/src/app/api/team/create/route.ts b/src/app/api/team/create/route.ts index b46eaaf..91a9679 100644 --- a/src/app/api/team/create/route.ts +++ b/src/app/api/team/create/route.ts @@ -1,7 +1,7 @@ // /api/team/create/route.ts import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma'; -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client'; +import { sendServerSSEMessage } from '@/app/lib/sse-server-client'; export async function POST(req: NextRequest) { try { @@ -37,14 +37,14 @@ export async function POST(req: NextRequest) { await prisma.notification.create({ data: { - userId: leader.steamId, + steamId: leader.steamId, title: 'Team erstellt', message: `Du hast erfolgreich das Team "${teamname}" erstellt.`, }, }); - // 📢 WebSocket Nachricht senden - await sendServerWebSocketMessage({ + // 📢 SSE Nachricht senden + await sendServerSSEMessage({ type: 'team-created', title: 'Team erstellt', message: `Das Team "${teamname}" wurde erstellt.`, diff --git a/src/app/api/team/invite/route.ts b/src/app/api/team/invite/route.ts index c1def09..d21af1e 100644 --- a/src/app/api/team/invite/route.ts +++ b/src/app/api/team/invite/route.ts @@ -1,6 +1,6 @@ import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { try { @@ -45,7 +45,7 @@ export async function POST(req: NextRequest) { }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [userId], message: notification.message, diff --git a/src/app/api/team/kick/route.ts b/src/app/api/team/kick/route.ts index dadea65..d297e9a 100644 --- a/src/app/api/team/kick/route.ts +++ b/src/app/api/team/kick/route.ts @@ -1,6 +1,6 @@ import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export const dynamic = 'force-dynamic' @@ -52,7 +52,7 @@ export async function POST(req: NextRequest) { }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [steamId], message: notification.message, @@ -76,7 +76,7 @@ export async function POST(req: NextRequest) { }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [userId], message: notification.message, diff --git a/src/app/api/team/leave/route.ts b/src/app/api/team/leave/route.ts index 35b673a..2a03724 100644 --- a/src/app/api/team/leave/route.ts +++ b/src/app/api/team/leave/route.ts @@ -1,7 +1,7 @@ import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' import { removePlayerFromTeam } from '@/app/lib/removePlayerFromTeam' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { try { @@ -66,7 +66,7 @@ export async function POST(req: NextRequest) { }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [steamId], message: notification.message, @@ -93,7 +93,7 @@ export async function POST(req: NextRequest) { }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [userId], message: notification.message, diff --git a/src/app/api/team/rename/route.ts b/src/app/api/team/rename/route.ts index c530d27..c03ec6a 100644 --- a/src/app/api/team/rename/route.ts +++ b/src/app/api/team/rename/route.ts @@ -1,7 +1,7 @@ // /app/api/team/rename/route.ts import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { try { @@ -16,8 +16,8 @@ export async function POST(req: NextRequest) { data: { name: newName }, }) - // 🔔 WebSocket Nachricht an alle User (global) - await sendServerWebSocketMessage({ + // 🔔 SSE Nachricht an alle User (global) + await sendServerSSEMessage({ type: 'team-renamed', title: 'Team umbenannt!', message: `Das Team wurde umbenannt in "${newName}".`, diff --git a/src/app/api/team/request-join/route.ts b/src/app/api/team/request-join/route.ts index 253d724..2cd80c8 100644 --- a/src/app/api/team/request-join/route.ts +++ b/src/app/api/team/request-join/route.ts @@ -3,7 +3,7 @@ import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' import { getServerSession } from 'next-auth' import { authOptions } from '@/app/lib/auth' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { try { @@ -37,7 +37,7 @@ export async function POST(req: NextRequest) { /* ---- Doppelte Anfrage vermeiden ------------------------------ */ const existingInvite = await prisma.teamInvite.findFirst({ - where: { userId: requesterSteamId, teamId }, + where: { steamId: requesterSteamId, teamId }, }) if (existingInvite) { return NextResponse.json({ message: 'Anfrage läuft bereits' }, { status: 200 }) @@ -46,7 +46,7 @@ export async function POST(req: NextRequest) { /* ---- Invitation anlegen -------------------------------------- */ await prisma.teamInvite.create({ data: { - userId: requesterSteamId, // User.steamId + steamId: requesterSteamId, // User.steamId teamId, type: 'team-join-request', }, @@ -55,7 +55,7 @@ export async function POST(req: NextRequest) { /* ---- Leader benachrichtigen ---------------------------------- */ const notification = await prisma.notification.create({ data: { - userId: team.leaderId!, + steamId: team.leaderId!, title: 'Beitrittsanfrage', message: `${session.user.name ?? 'Ein Spieler'} möchte deinem Team beitreten.`, actionType: 'team-join-request', @@ -63,8 +63,8 @@ export async function POST(req: NextRequest) { }, }) - /* ---- WebSocket Event (optional) ------------------------------ */ - await sendServerWebSocketMessage({ + /* ---- SSE Event (optional) ------------------------------ */ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [team.leaderId], message: notification.message, diff --git a/src/app/api/team/transfer-leader/route.ts b/src/app/api/team/transfer-leader/route.ts index e19d8f9..a615461 100644 --- a/src/app/api/team/transfer-leader/route.ts +++ b/src/app/api/team/transfer-leader/route.ts @@ -2,7 +2,7 @@ import { prisma } from '@/app/lib/prisma' import { NextResponse, type NextRequest } from 'next/server' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { try { @@ -39,7 +39,7 @@ export async function POST(req: NextRequest) { select: { name: true }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: 'team-leader-changed', title: 'Neuer Teamleader', message: `${newLeader?.name ?? 'Ein Spieler'} ist jetzt Teamleader.`, diff --git a/src/app/api/team/update-players/route.ts b/src/app/api/team/update-players/route.ts index 6c1c76b..29d9eee 100644 --- a/src/app/api/team/update-players/route.ts +++ b/src/app/api/team/update-players/route.ts @@ -1,6 +1,6 @@ // ✅ /api/team/update-players/route.ts import { prisma } from '@/app/lib/prisma' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' import { NextResponse, type NextRequest } from 'next/server' export async function POST(req: NextRequest) { @@ -18,7 +18,7 @@ export async function POST(req: NextRequest) { const allSteamIds = [...activePlayers, ...inactivePlayers] - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: 'team-updated', teamId, targetUserIds: allSteamIds, diff --git a/src/app/api/team/upload-logo/route.ts b/src/app/api/team/upload-logo/route.ts index 165c092..f2be047 100644 --- a/src/app/api/team/upload-logo/route.ts +++ b/src/app/api/team/upload-logo/route.ts @@ -3,7 +3,7 @@ import { NextResponse, type NextRequest } from 'next/server' import { writeFile, mkdir, unlink } from 'fs/promises' import { join, dirname } from 'path' import { randomUUID } from 'crypto' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export async function POST(req: NextRequest) { const formData = await req.formData() @@ -47,7 +47,7 @@ export async function POST(req: NextRequest) { data: { logo: filename }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: 'team-logo-updated', title: 'Team-Logo hochgeladen!', message: `Das Teamlogo wurde aktualisiert.`, diff --git a/src/app/api/user/invitations/[action]/route.ts b/src/app/api/user/invitations/[action]/route.ts index 6d58e6d..1f35e9b 100644 --- a/src/app/api/user/invitations/[action]/route.ts +++ b/src/app/api/user/invitations/[action]/route.ts @@ -1,7 +1,7 @@ // /api/user/invitations/[action]/route.ts import { NextResponse, type NextRequest } from 'next/server' import { prisma } from '@/app/lib/prisma' -import { sendServerWebSocketMessage } from '@/app/lib/websocket-server-client' +import { sendServerSSEMessage } from '@/app/lib/sse-server-client' export const dynamic = 'force-dynamic' @@ -58,7 +58,7 @@ export async function POST( }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [steamId], message: notification.message, @@ -86,7 +86,7 @@ export async function POST( }, }) - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: notification.actionType ?? 'notification', targetUserIds: [otherUserId], message: notification.message, @@ -118,7 +118,7 @@ export async function POST( ? 'team-join-request-reject' : 'team-invite-reject' - await sendServerWebSocketMessage({ + await sendServerSSEMessage({ type: eventType, targetUserIds: [steamId], message: `Einladung zu Team "${team?.name}" wurde abgelehnt.`, diff --git a/src/app/components/Button.tsx b/src/app/components/Button.tsx index 6eab8cd..698dffc 100644 --- a/src/app/components/Button.tsx +++ b/src/app/components/Button.tsx @@ -5,7 +5,7 @@ import { ReactNode, forwardRef, useState, useRef, useEffect } from 'react' type ButtonProps = { title?: string children?: ReactNode - onClick?: () => void + onClick?: (event: React.MouseEvent) => void onToggle?: (open: boolean) => void modalId?: string color?: 'blue' | 'red' | 'gray' | 'green' | 'teal' | 'transparent' @@ -13,6 +13,7 @@ type ButtonProps = { size?: 'sm' | 'md' | 'lg' className?: string dropDirection?: "up" | "down" | "auto" + disabled?: boolean } const Button = forwardRef(function Button( @@ -26,7 +27,8 @@ const Button = forwardRef(function Button( variant = 'solid', size = 'md', className, - dropDirection = "down" + dropDirection = "down", + disabled = false }, ref ) { @@ -130,12 +132,12 @@ const Button = forwardRef(function Button( } }, [open, dropDirection]); - const toggle = () => { + const toggle = (event: React.MouseEvent) => { const next = !open setOpen(next) onToggle?.(next) - onClick?.() - } + onClick?.(event) +} return (