updated matchlist

This commit is contained in:
Linrador 2025-06-11 22:49:25 +02:00
parent 63becfbc3a
commit 16ddd1baa0
23 changed files with 447 additions and 73 deletions

View File

@ -66,14 +66,18 @@ model Match {
demoFilePath String?
scoreA Int?
scoreB Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
teamA Team? @relation("TeamA", fields: [teamAId], references: [id])
teamB Team? @relation("TeamB", fields: [teamBId], references: [id])
demoFile DemoFile?
players MatchPlayer[]
rankUpdates PremierRankHistory[] @relation("MatchRankHistory")
roundCount Int?
roundHistory Json?
winnerTeam String?
demoDate DateTime? // echtes Datum aus der Demo (falls vorhanden)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model MatchPlayer {

View File

@ -9,7 +9,7 @@ import type { NextRequest } from 'next/server'
export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
const session = await getServerSession(authOptions(req))
if (!session?.user?.id) {
if (!session?.user?.steamId) {
return NextResponse.json({ error: 'Nicht eingeloggt' }, { status: 401 })
}
@ -21,7 +21,7 @@ export async function POST(req: NextRequest, { params }: { params: { id: string
where: { id: notificationId },
})
if (!notification || notification.userId !== session.user.id) {
if (!notification || notification.userId !== session.user.steamId) {
return NextResponse.json({ error: 'Nicht gefunden oder nicht erlaubt' }, { status: 403 })
}

View File

@ -21,8 +21,6 @@ export async function GET(req: NextRequest) {
map: true,
scoreA: true,
scoreB: true,
matchType: true,
rankUpdates: true,
},
},
stats: true,
@ -35,19 +33,27 @@ export async function GET(req: NextRequest) {
});
const data = matchPlayers.map((mp) => {
const isTeamA = mp.teamId === mp.match.teamAId;
const kills = mp.stats?.kills ?? 0;
const deaths = mp.stats?.deaths ?? 0;
const match = mp.match;
const stats = mp.stats;
const kills = stats?.kills ?? 0;
const deaths = stats?.deaths ?? 0;
const kd = deaths > 0 ? (kills / deaths).toFixed(2) : '∞';
const rankOld = stats?.rankOld ?? null;
const rankNew = stats?.rankNew ?? null;
const rankChange =
typeof rankNew === 'number' && typeof rankOld === 'number'
? rankNew - rankOld
: null;
return {
map: mp.match.map ?? 'Unknown',
date: mp.match.matchDate,
score: `${mp.match.scoreA ?? 0} : ${mp.match.scoreB ?? 0}`,
isTeamA,
rankNew: mp.stats?.rankNew ?? null,
rankOld: mp.stats?.rankOld ?? null,
rating: (mp.stats?.adr ?? 0).toFixed(2), // optional: hier besser eigener Rating-Alg.
map: match.map ?? 'Unknown',
date: match.matchDate,
score: `${match.scoreA ?? 0} : ${match.scoreB ?? 0}`,
rankOld,
rankNew,
rankChange,
kills,
deaths,
kd,

View File

@ -16,6 +16,7 @@ type Notification = {
createdAt?: string
}
export default function NotificationCenter() {
const { data: session } = useSession()
const [notifications, setNotifications] = useState<Notification[]>([])
@ -27,6 +28,20 @@ export default function NotificationCenter() {
const [showPreview, setShowPreview] = useState(false)
const [animateBell, setAnimateBell] = useState(false)
const onNotificationClick = (notification: Notification) => {
if (!notification.actionData) return;
try {
const data = JSON.parse(notification.actionData);
console.error('Weiterleitung: ', notification.actionData);
if (data.redirectUrl) {
router.push(data.redirectUrl);
}
} catch (err) {
console.error('Ungültige actionData:', err);
}
}
useEffect(() => {
const steamId = session?.user?.steamId
if (!steamId) return
@ -176,6 +191,7 @@ export default function NotificationCenter() {
)
if (action === 'accept') router.refresh()
}}
onClickNotification={onNotificationClick}
/>
)}
</div>

View File

@ -20,6 +20,7 @@ type Props = {
onSingleRead: (id: string) => void
onClose: () => void
onAction: (action: 'accept' | 'reject', invitationId: string) => void
onClickNotification?: (notification: Notification) => void
}
export default function NotificationDropdown({
@ -28,6 +29,7 @@ export default function NotificationDropdown({
onSingleRead,
onClose,
onAction,
onClickNotification
}: Props) {
const dropdownRef = useRef<HTMLDivElement>(null)
@ -89,7 +91,11 @@ export default function NotificationDropdown({
return (
<div
key={n.id}
className="grid grid-cols-[auto_1fr_auto] items-center gap-2 py-3 px-2 border-b border-gray-200 dark:border-neutral-700 text-sm hover:bg-gray-50 dark:hover:bg-neutral-700"
className="grid grid-cols-[auto_1fr_auto] items-center gap-2 py-3 px-2 border-b border-gray-200 dark:border-neutral-700 text-sm hover:bg-gray-50 dark:hover:bg-neutral-700 cursor-pointer"
onClick={() => {
onClickNotification?.(n) // ⬅️ Navigation / Weiterverarbeitung
if (!n.read) onSingleRead(n.id) // ⬅️ erst danach als gelesen markieren
}}
>
{/* roter Punkt */}
<div className="flex items-center justify-center h-full">

View File

@ -0,0 +1,51 @@
import React from 'react';
type Props = {
rankNew: number | null;
};
function getPremierRankColors(rank: number): [string, string] {
if (rank >= 30000) return ['#EDC903', '#645104'];
if (rank >= 25000) return ['#DF1D1B', '#650A0E'];
if (rank >= 20000) return ['#F9243A', '#5C0361'];
if (rank >= 15000) return ['#DF1D1B', '#4D1D65'];
if (rank >= 10000) return ['#3D5EDD', '#152062'];
if (rank >= 5000) return ['#74A9D5', '#74A9D5'];
return ['#A7B8CC', '#464952'];
}
export default function PremierRankBadge({ rankNew }: Props) {
if (rankNew === null) return <span></span>;
const [stripeColor, backgroundColor] = getPremierRankColors(rankNew);
return (
<div className="premier-rank-wrapper">
<svg
className="rank-stripes"
viewBox="0 0 12 28"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="0"
y="0"
width="3"
height="28"
className="rank-stripe"
fill={stripeColor}
/>
<rect
x="5"
y="0"
width="3"
height="28"
className="rank-stripe"
fill={stripeColor}
/>
</svg>
<div className="rank-box" style={{ backgroundColor, color: stripeColor }}>
<span>{rankNew.toLocaleString('de-DE')}</span>
</div>
</div>
);
}

View File

@ -5,6 +5,7 @@ import Table from './Table';
import Link from 'next/link';
import { mapNameMap } from '../lib/mapNameMap';
import { useRouter } from 'next/navigation';
import PremierRankBadge from './PremierRankBadge';
interface Match {
id: string;
@ -17,6 +18,7 @@ interface Match {
kd: string;
rankNew: number | null;
rankOld: number | null;
rankChange: number | null;
}
export default function UserMatchesTable() {
@ -38,6 +40,7 @@ export default function UserMatchesTable() {
<Table.Cell as="th">Date</Table.Cell>
<Table.Cell as="th">Score</Table.Cell>
<Table.Cell as="th">Rank</Table.Cell>
<Table.Cell as="th">New Rank</Table.Cell>
<Table.Cell as="th">Kills</Table.Cell>
<Table.Cell as="th">Deaths</Table.Cell>
<Table.Cell as="th">K/D</Table.Cell>
@ -66,18 +69,18 @@ export default function UserMatchesTable() {
<Table.Cell>{new Date(m.date).toLocaleString()}</Table.Cell>
<Table.Cell>{m.score}</Table.Cell>
<Table.Cell>
{m.rankNew !== null ? (
m.rankOld !== null ? (
<span className={m.rankNew > m.rankOld ? 'text-green-500' : m.rankNew < m.rankOld ? 'text-red-500' : ''}>
{m.rankNew > m.rankOld ? '+' : ''}
{m.rankNew - m.rankOld}
{m.rankChange !== null ? (
<span className={
m.rankChange > 0 ? 'text-green-500' :
m.rankChange < 0 ? 'text-red-500' : ''
}>
{m.rankChange > 0 ? '+' : ''}
{m.rankChange}
</span>
) : (
m.rankNew
)
) : (
'—'
)}
) : '—'}
</Table.Cell>
<Table.Cell>
<PremierRankBadge rankNew={m.rankNew} />
</Table.Cell>
<Table.Cell>{m.kills}</Table.Cell>
<Table.Cell>{m.deaths}</Table.Cell>

View File

@ -55,3 +55,35 @@ body {
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
.premier-rank-wrapper {
display: flex;
align-items: center;
}
.rank-stripes {
width: 24px;
height: 28px;
margin-right: -14px;
z-index: 2;
position: relative;
transform: skewX(-10deg);
}
.rank-box {
height: 28px;
padding: 3px 12px;
border-radius: 1px;
font-weight: bold;
font-size: 16px;
transform: skewX(-10deg);
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
}
.rank-box span {
transform: skewX(-5deg);
}

File diff suppressed because one or more lines are too long

View File

@ -157,6 +157,10 @@ exports.Prisma.MatchScalarFieldEnum = {
demoFilePath: 'demoFilePath',
scoreA: 'scoreA',
scoreB: 'scoreB',
roundCount: 'roundCount',
roundHistory: 'roundHistory',
winnerTeam: 'winnerTeam',
demoDate: 'demoDate',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};

View File

@ -4504,11 +4504,13 @@ export namespace Prisma {
export type MatchAvgAggregateOutputType = {
scoreA: number | null
scoreB: number | null
roundCount: number | null
}
export type MatchSumAggregateOutputType = {
scoreA: number | null
scoreB: number | null
roundCount: number | null
}
export type MatchMinAggregateOutputType = {
@ -4523,6 +4525,9 @@ export namespace Prisma {
demoFilePath: string | null
scoreA: number | null
scoreB: number | null
roundCount: number | null
winnerTeam: string | null
demoDate: Date | null
createdAt: Date | null
updatedAt: Date | null
}
@ -4539,6 +4544,9 @@ export namespace Prisma {
demoFilePath: string | null
scoreA: number | null
scoreB: number | null
roundCount: number | null
winnerTeam: string | null
demoDate: Date | null
createdAt: Date | null
updatedAt: Date | null
}
@ -4556,6 +4564,10 @@ export namespace Prisma {
demoFilePath: number
scoreA: number
scoreB: number
roundCount: number
roundHistory: number
winnerTeam: number
demoDate: number
createdAt: number
updatedAt: number
_all: number
@ -4565,11 +4577,13 @@ export namespace Prisma {
export type MatchAvgAggregateInputType = {
scoreA?: true
scoreB?: true
roundCount?: true
}
export type MatchSumAggregateInputType = {
scoreA?: true
scoreB?: true
roundCount?: true
}
export type MatchMinAggregateInputType = {
@ -4584,6 +4598,9 @@ export namespace Prisma {
demoFilePath?: true
scoreA?: true
scoreB?: true
roundCount?: true
winnerTeam?: true
demoDate?: true
createdAt?: true
updatedAt?: true
}
@ -4600,6 +4617,9 @@ export namespace Prisma {
demoFilePath?: true
scoreA?: true
scoreB?: true
roundCount?: true
winnerTeam?: true
demoDate?: true
createdAt?: true
updatedAt?: true
}
@ -4617,6 +4637,10 @@ export namespace Prisma {
demoFilePath?: true
scoreA?: true
scoreB?: true
roundCount?: true
roundHistory?: true
winnerTeam?: true
demoDate?: true
createdAt?: true
updatedAt?: true
_all?: true
@ -4721,6 +4745,10 @@ export namespace Prisma {
demoFilePath: string | null
scoreA: number | null
scoreB: number | null
roundCount: number | null
roundHistory: JsonValue | null
winnerTeam: string | null
demoDate: Date | null
createdAt: Date
updatedAt: Date
_count: MatchCountAggregateOutputType | null
@ -4757,6 +4785,10 @@ export namespace Prisma {
demoFilePath?: boolean
scoreA?: boolean
scoreB?: boolean
roundCount?: boolean
roundHistory?: boolean
winnerTeam?: boolean
demoDate?: boolean
createdAt?: boolean
updatedAt?: boolean
teamA?: boolean | Match$teamAArgs<ExtArgs>
@ -4780,6 +4812,10 @@ export namespace Prisma {
demoFilePath?: boolean
scoreA?: boolean
scoreB?: boolean
roundCount?: boolean
roundHistory?: boolean
winnerTeam?: boolean
demoDate?: boolean
createdAt?: boolean
updatedAt?: boolean
teamA?: boolean | Match$teamAArgs<ExtArgs>
@ -4799,6 +4835,10 @@ export namespace Prisma {
demoFilePath?: boolean
scoreA?: boolean
scoreB?: boolean
roundCount?: boolean
roundHistory?: boolean
winnerTeam?: boolean
demoDate?: boolean
createdAt?: boolean
updatedAt?: boolean
teamA?: boolean | Match$teamAArgs<ExtArgs>
@ -4818,11 +4858,15 @@ export namespace Prisma {
demoFilePath?: boolean
scoreA?: boolean
scoreB?: boolean
roundCount?: boolean
roundHistory?: boolean
winnerTeam?: boolean
demoDate?: boolean
createdAt?: boolean
updatedAt?: boolean
}
export type MatchOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "teamAId" | "teamBId" | "matchDate" | "matchType" | "map" | "title" | "description" | "demoData" | "demoFilePath" | "scoreA" | "scoreB" | "createdAt" | "updatedAt", ExtArgs["result"]["match"]>
export type MatchOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "teamAId" | "teamBId" | "matchDate" | "matchType" | "map" | "title" | "description" | "demoData" | "demoFilePath" | "scoreA" | "scoreB" | "roundCount" | "roundHistory" | "winnerTeam" | "demoDate" | "createdAt" | "updatedAt", ExtArgs["result"]["match"]>
export type MatchInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
teamA?: boolean | Match$teamAArgs<ExtArgs>
teamB?: boolean | Match$teamBArgs<ExtArgs>
@ -4862,6 +4906,10 @@ export namespace Prisma {
demoFilePath: string | null
scoreA: number | null
scoreB: number | null
roundCount: number | null
roundHistory: Prisma.JsonValue | null
winnerTeam: string | null
demoDate: Date | null
createdAt: Date
updatedAt: Date
}, ExtArgs["result"]["match"]>
@ -5304,6 +5352,10 @@ export namespace Prisma {
readonly demoFilePath: FieldRef<"Match", 'String'>
readonly scoreA: FieldRef<"Match", 'Int'>
readonly scoreB: FieldRef<"Match", 'Int'>
readonly roundCount: FieldRef<"Match", 'Int'>
readonly roundHistory: FieldRef<"Match", 'Json'>
readonly winnerTeam: FieldRef<"Match", 'String'>
readonly demoDate: FieldRef<"Match", 'DateTime'>
readonly createdAt: FieldRef<"Match", 'DateTime'>
readonly updatedAt: FieldRef<"Match", 'DateTime'>
}
@ -13986,6 +14038,10 @@ export namespace Prisma {
demoFilePath: 'demoFilePath',
scoreA: 'scoreA',
scoreB: 'scoreB',
roundCount: 'roundCount',
roundHistory: 'roundHistory',
winnerTeam: 'winnerTeam',
demoDate: 'demoDate',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
@ -14445,6 +14501,10 @@ export namespace Prisma {
demoFilePath?: StringNullableFilter<"Match"> | string | null
scoreA?: IntNullableFilter<"Match"> | number | null
scoreB?: IntNullableFilter<"Match"> | number | null
roundCount?: IntNullableFilter<"Match"> | number | null
roundHistory?: JsonNullableFilter<"Match">
winnerTeam?: StringNullableFilter<"Match"> | string | null
demoDate?: DateTimeNullableFilter<"Match"> | Date | string | null
createdAt?: DateTimeFilter<"Match"> | Date | string
updatedAt?: DateTimeFilter<"Match"> | Date | string
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
@ -14467,6 +14527,10 @@ export namespace Prisma {
demoFilePath?: SortOrderInput | SortOrder
scoreA?: SortOrderInput | SortOrder
scoreB?: SortOrderInput | SortOrder
roundCount?: SortOrderInput | SortOrder
roundHistory?: SortOrderInput | SortOrder
winnerTeam?: SortOrderInput | SortOrder
demoDate?: SortOrderInput | SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
teamA?: TeamOrderByWithRelationInput
@ -14492,6 +14556,10 @@ export namespace Prisma {
demoFilePath?: StringNullableFilter<"Match"> | string | null
scoreA?: IntNullableFilter<"Match"> | number | null
scoreB?: IntNullableFilter<"Match"> | number | null
roundCount?: IntNullableFilter<"Match"> | number | null
roundHistory?: JsonNullableFilter<"Match">
winnerTeam?: StringNullableFilter<"Match"> | string | null
demoDate?: DateTimeNullableFilter<"Match"> | Date | string | null
createdAt?: DateTimeFilter<"Match"> | Date | string
updatedAt?: DateTimeFilter<"Match"> | Date | string
teamA?: XOR<TeamNullableScalarRelationFilter, TeamWhereInput> | null
@ -14514,6 +14582,10 @@ export namespace Prisma {
demoFilePath?: SortOrderInput | SortOrder
scoreA?: SortOrderInput | SortOrder
scoreB?: SortOrderInput | SortOrder
roundCount?: SortOrderInput | SortOrder
roundHistory?: SortOrderInput | SortOrder
winnerTeam?: SortOrderInput | SortOrder
demoDate?: SortOrderInput | SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
_count?: MatchCountOrderByAggregateInput
@ -14539,6 +14611,10 @@ export namespace Prisma {
demoFilePath?: StringNullableWithAggregatesFilter<"Match"> | string | null
scoreA?: IntNullableWithAggregatesFilter<"Match"> | number | null
scoreB?: IntNullableWithAggregatesFilter<"Match"> | number | null
roundCount?: IntNullableWithAggregatesFilter<"Match"> | number | null
roundHistory?: JsonNullableWithAggregatesFilter<"Match">
winnerTeam?: StringNullableWithAggregatesFilter<"Match"> | string | null
demoDate?: DateTimeNullableWithAggregatesFilter<"Match"> | Date | string | null
createdAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
updatedAt?: DateTimeWithAggregatesFilter<"Match"> | Date | string
}
@ -15334,6 +15410,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
@ -15356,6 +15436,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
@ -15374,6 +15458,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
@ -15396,6 +15484,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
@ -15416,6 +15508,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
}
@ -15431,6 +15527,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
}
@ -15448,6 +15548,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
}
@ -16429,6 +16533,10 @@ export namespace Prisma {
demoFilePath?: SortOrder
scoreA?: SortOrder
scoreB?: SortOrder
roundCount?: SortOrder
roundHistory?: SortOrder
winnerTeam?: SortOrder
demoDate?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
}
@ -16436,6 +16544,7 @@ export namespace Prisma {
export type MatchAvgOrderByAggregateInput = {
scoreA?: SortOrder
scoreB?: SortOrder
roundCount?: SortOrder
}
export type MatchMaxOrderByAggregateInput = {
@ -16450,6 +16559,9 @@ export namespace Prisma {
demoFilePath?: SortOrder
scoreA?: SortOrder
scoreB?: SortOrder
roundCount?: SortOrder
winnerTeam?: SortOrder
demoDate?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
}
@ -16466,6 +16578,9 @@ export namespace Prisma {
demoFilePath?: SortOrder
scoreA?: SortOrder
scoreB?: SortOrder
roundCount?: SortOrder
winnerTeam?: SortOrder
demoDate?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
}
@ -16473,6 +16588,7 @@ export namespace Prisma {
export type MatchSumOrderByAggregateInput = {
scoreA?: SortOrder
scoreB?: SortOrder
roundCount?: SortOrder
}
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
| PatchUndefined<
@ -18818,6 +18934,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamB?: TeamCreateNestedOneWithoutMatchesAsTeamBInput
@ -18838,6 +18958,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
@ -18866,6 +18990,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
@ -18886,6 +19014,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
@ -19051,6 +19183,10 @@ export namespace Prisma {
demoFilePath?: StringNullableFilter<"Match"> | string | null
scoreA?: IntNullableFilter<"Match"> | number | null
scoreB?: IntNullableFilter<"Match"> | number | null
roundCount?: IntNullableFilter<"Match"> | number | null
roundHistory?: JsonNullableFilter<"Match">
winnerTeam?: StringNullableFilter<"Match"> | string | null
demoDate?: DateTimeNullableFilter<"Match"> | Date | string | null
createdAt?: DateTimeFilter<"Match"> | Date | string
updatedAt?: DateTimeFilter<"Match"> | Date | string
}
@ -19368,6 +19504,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
@ -19389,6 +19529,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
@ -19553,6 +19697,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
@ -19574,6 +19722,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
@ -19788,6 +19940,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
@ -19809,6 +19965,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
players?: MatchPlayerUncheckedCreateNestedManyWithoutMatchInput
@ -19887,6 +20047,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
@ -19908,6 +20072,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
players?: MatchPlayerUncheckedUpdateManyWithoutMatchNestedInput
@ -20381,6 +20549,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
teamA?: TeamCreateNestedOneWithoutMatchesAsTeamAInput
@ -20402,6 +20574,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
demoFile?: DemoFileUncheckedCreateNestedOneWithoutMatchInput
@ -20486,6 +20662,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
@ -20507,6 +20687,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
@ -20778,6 +20962,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
}
@ -20794,6 +20982,10 @@ export namespace Prisma {
demoFilePath?: string | null
scoreA?: number | null
scoreB?: number | null
roundCount?: number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: string | null
demoDate?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
}
@ -20906,6 +21098,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamB?: TeamUpdateOneWithoutMatchesAsTeamBNestedInput
@ -20926,6 +21122,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
@ -20945,6 +21145,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
}
@ -20960,6 +21164,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
teamA?: TeamUpdateOneWithoutMatchesAsTeamANestedInput
@ -20980,6 +21188,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
demoFile?: DemoFileUncheckedUpdateOneWithoutMatchNestedInput
@ -20999,6 +21211,10 @@ export namespace Prisma {
demoFilePath?: NullableStringFieldUpdateOperationsInput | string | null
scoreA?: NullableIntFieldUpdateOperationsInput | number | null
scoreB?: NullableIntFieldUpdateOperationsInput | number | null
roundCount?: NullableIntFieldUpdateOperationsInput | number | null
roundHistory?: NullableJsonNullValueInput | InputJsonValue
winnerTeam?: NullableStringFieldUpdateOperationsInput | string | null
demoDate?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"name": "prisma-client-9a8c37bb270b506ae34f7883dcf8d6883cab59123439f5237b94576b020b37c3",
"name": "prisma-client-cdb8210527297f74cd0635089f4e7e094bc51188ba7386e11a74e51dd944fdb8",
"main": "index.js",
"types": "index.d.ts",
"browser": "index-browser.js",

View File

@ -54,11 +54,11 @@ model Team {
}
model Match {
id String @id @default(uuid())
id String @id @default(uuid())
teamAId String?
teamBId String?
matchDate DateTime
matchType String @default("community")
matchType String @default("community")
map String?
title String
description String?
@ -66,14 +66,18 @@ model Match {
demoFilePath String?
scoreA Int?
scoreB Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
teamA Team? @relation("TeamA", fields: [teamAId], references: [id])
teamB Team? @relation("TeamB", fields: [teamBId], references: [id])
demoFile DemoFile?
players MatchPlayer[]
rankUpdates PremierRankHistory[] @relation("MatchRankHistory")
roundCount Int?
roundHistory Json?
winnerTeam String?
demoDate DateTime? // echtes Datum aus der Demo (falls vorhanden)
teamA Team? @relation("TeamA", fields: [teamAId], references: [id])
teamB Team? @relation("TeamB", fields: [teamBId], references: [id])
demoFile DemoFile?
players MatchPlayer[]
rankUpdates PremierRankHistory[] @relation("MatchRankHistory")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model MatchPlayer {

View File

@ -157,6 +157,10 @@ exports.Prisma.MatchScalarFieldEnum = {
demoFilePath: 'demoFilePath',
scoreA: 'scoreA',
scoreB: 'scoreB',
roundCount: 'roundCount',
roundHistory: 'roundHistory',
winnerTeam: 'winnerTeam',
demoDate: 'demoDate',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};

View File

@ -40,9 +40,16 @@ interface DemoMatchData {
duration: number;
map: string;
players: PlayerStatsExtended[];
scoreCT?: number;
scoreT?: number;
winnerTeam?: string;
roundCount?: number;
roundHistory?: { round: number; winner: string; winReason: string }[];
demoDate?: string;
};
}
const latestDemoDateCache: Record<string, { [type: string]: Date | null }> = {};
export async function parseAndStoreDemo(
@ -73,7 +80,7 @@ export async function parseAndStoreDemo(
const match = await prisma.match.create({
data: {
id: parsed.matchId,
title: `CS2 Match vom ${parsed.matchDate.toLocaleDateString()}`,
title: `CS2 Match auf ${parsed.map} am ${parsed.matchDate.toLocaleDateString('de-DE')}`,
matchDate: parsed.matchDate,
map: parsed.map,
demoFilePath: relativePath,
@ -82,9 +89,16 @@ export async function parseAndStoreDemo(
: demoPath.endsWith('_competitive.dem')
? 'competitive'
: 'community',
scoreA: parsed.meta.scoreCT,
scoreB: parsed.meta.scoreT,
winnerTeam: parsed.meta.winnerTeam ?? null,
roundCount: parsed.meta.roundCount ?? null,
roundHistory: parsed.meta.roundHistory ?? undefined,
demoDate: parsed.meta.demoDate ? new Date(parsed.meta.demoDate) : null,
},
});
await prisma.demoFile.create({
data: {
steamId,
@ -103,7 +117,7 @@ export async function parseAndStoreDemo(
let steamProfile = null;
if (!playerUser?.name || !playerUser?.avatar) {
steamProfile = await fetchSteamProfile(player.steamId).catch(() => null);
await delay(1000);
await delay(5000);
}
const isPremier = path.basename(actualDemoPath).toLowerCase().endsWith('_premier.dem');

View File

@ -42,38 +42,44 @@ async function runMatchCheck() {
let nextShareCode = await getNextShareCodeFromAPI(user.steamId, decryptedAuthCode, latestKnownCode);
if (nextShareCode === null) {
// log(`⚠️ Ungültiger lastKnownShareCode bei ${user.steamId}`)
const isTooOld =
user.lastKnownShareCodeDate &&
new Date().getTime() - user.lastKnownShareCodeDate.getTime() > 30 * 24 * 60 * 60 * 1000;
const alreadyNotified = await prisma.notification.findFirst({
where: {
userId: user.steamId,
actionType: 'expired-sharecode',
},
})
if (!alreadyNotified) {
const notification = await prisma.notification.create({
data: {
if (isTooOld) {
const alreadyNotified = await prisma.notification.findFirst({
where: {
userId: user.steamId,
title: 'Share Code abgelaufen',
message: 'Dein gespeicherter Share Code ist abgelaufen.',
actionType: 'expired-sharecode',
},
})
});
// WebSocket senden
await sendServerWebSocketMessage({
type: 'expired-sharecode',
targetUserIds: [user.steamId],
message: notification.message,
id: notification.id,
actionType: notification.actionType ?? undefined,
actionData: notification.actionData ?? undefined,
createdAt: notification.createdAt.toISOString(),
})
if (!alreadyNotified) {
const notification = await prisma.notification.create({
data: {
userId: user.steamId,
title: 'Austauschcode abgelaufen',
message: 'Dein gespeicherter Austauschcode ist abgelaufen.',
actionType: 'expired-sharecode',
actionData: JSON.stringify({
redirectUrl: '/settings/account',
}),
},
});
await sendServerWebSocketMessage({
type: 'expired-sharecode',
targetUserIds: [user.steamId],
message: notification.message,
id: notification.id,
actionType: notification.actionType ?? undefined,
actionData: notification.actionData ?? undefined,
createdAt: notification.createdAt.toISOString(),
});
}
}
continue // springe zum nächsten User
continue; // springe zum nächsten User
}
while (nextShareCode) {