From 2263dc3aa515af5743ba2c10aa06ee208d52ce34 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Wed, 6 May 2026 16:37:58 +0000 Subject: [PATCH] Updating --- baseball/src/app/api/games/[id]/route.ts | 3 + baseball/src/app/api/games/route.ts | 14 ++ .../api/pitching-appearances/[id]/route.ts | 46 ++++ .../src/app/api/pitching-appearances/route.ts | 1 + baseball/src/app/api/players/route.ts | 23 +- baseball/src/app/games/history/page.tsx | 5 + baseball/src/app/pitching/page.tsx | 5 - baseball/src/components/AppShell.tsx | 6 +- baseball/src/components/GameHistoryClient.tsx | 209 ++++++++++++++++++ baseball/src/components/GameScoringClient.tsx | 148 +++++-------- .../src/components/PitchTrackingClient.tsx | 182 --------------- baseball/src/components/RosterClient.tsx | 151 ++++++++++++- baseball/src/lib/types.ts | 9 + baseball/src/lib/validators.ts | 3 +- baseball/src/models/Game.ts | 3 +- baseball/src/models/PitchingAppearance.ts | 2 + 16 files changed, 513 insertions(+), 297 deletions(-) create mode 100644 baseball/src/app/api/pitching-appearances/[id]/route.ts create mode 100644 baseball/src/app/games/history/page.tsx delete mode 100644 baseball/src/app/pitching/page.tsx create mode 100644 baseball/src/components/GameHistoryClient.tsx delete mode 100644 baseball/src/components/PitchTrackingClient.tsx diff --git a/baseball/src/app/api/games/[id]/route.ts b/baseball/src/app/api/games/[id]/route.ts index 2d03daa..c24a424 100644 --- a/baseball/src/app/api/games/[id]/route.ts +++ b/baseball/src/app/api/games/[id]/route.ts @@ -2,6 +2,7 @@ import { NextResponse } from "next/server"; import { handleApiError } from "@/app/api/_utils"; import { connectToDatabase } from "@/lib/db"; import { GameModel } from "@/models/Game"; +import { PitchingAppearanceModel } from "@/models/PitchingAppearance"; import { PlayerModel } from "@/models/Player"; export const runtime = "nodejs"; @@ -47,6 +48,8 @@ export async function DELETE(_request: Request, { params }: { params: Promise<{ }) ); + await PitchingAppearanceModel.deleteMany({ gameId: game._id }); + return NextResponse.json({ success: true }); } catch (error) { return handleApiError(error); diff --git a/baseball/src/app/api/games/route.ts b/baseball/src/app/api/games/route.ts index ed4449a..2672016 100644 --- a/baseball/src/app/api/games/route.ts +++ b/baseball/src/app/api/games/route.ts @@ -5,6 +5,7 @@ import { serialize } from "@/lib/serialize"; import { saveGameSchema } from "@/lib/validators"; import { GameModel } from "@/models/Game"; import { LineupModel } from "@/models/Lineup"; +import { PitchingAppearanceModel } from "@/models/PitchingAppearance"; import { PlayerModel } from "@/models/Player"; export const runtime = "nodejs"; @@ -81,6 +82,19 @@ export async function POST(request: Request) { }) ); + const pitchingEntries = payload.playerStats.filter((playerStat) => (playerStat.pitchCount ?? 0) > 0); + if (pitchingEntries.length > 0) { + await PitchingAppearanceModel.insertMany( + pitchingEntries.map((playerStat) => ({ + playerId: playerStat.playerId, + gameId: game._id, + gameDate, + pitchCount: playerStat.pitchCount, + notes: payload.opponent ? `Scored game vs ${payload.opponent}` : "Scored game" + })) + ); + } + return NextResponse.json(serialize(game.toObject()), { status: 201 }); } catch (error) { return handleApiError(error); diff --git a/baseball/src/app/api/pitching-appearances/[id]/route.ts b/baseball/src/app/api/pitching-appearances/[id]/route.ts new file mode 100644 index 0000000..7e45b75 --- /dev/null +++ b/baseball/src/app/api/pitching-appearances/[id]/route.ts @@ -0,0 +1,46 @@ +import { NextResponse } from "next/server"; +import { handleApiError } from "@/app/api/_utils"; +import { connectToDatabase } from "@/lib/db"; +import { serialize } from "@/lib/serialize"; +import { pitchingAppearanceSchema } from "@/lib/validators"; +import { PitchingAppearanceModel } from "@/models/PitchingAppearance"; + +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; + +export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) { + try { + await connectToDatabase(); + const { id } = await params; + const payload = pitchingAppearanceSchema.parse(await request.json()); + const appearance = await PitchingAppearanceModel.findByIdAndUpdate( + id, + { ...payload, gameDate: new Date(payload.gameDate) }, + { new: true, runValidators: true } + ).lean(); + + if (!appearance) { + return NextResponse.json({ error: "Pitching appearance not found." }, { status: 404 }); + } + + return NextResponse.json(serialize(appearance)); + } catch (error) { + return handleApiError(error); + } +} + +export async function DELETE(_request: Request, { params }: { params: Promise<{ id: string }> }) { + try { + await connectToDatabase(); + const { id } = await params; + const appearance = await PitchingAppearanceModel.findByIdAndDelete(id).lean(); + + if (!appearance) { + return NextResponse.json({ error: "Pitching appearance not found." }, { status: 404 }); + } + + return NextResponse.json({ success: true }); + } catch (error) { + return handleApiError(error); + } +} diff --git a/baseball/src/app/api/pitching-appearances/route.ts b/baseball/src/app/api/pitching-appearances/route.ts index b58f2b4..543385f 100644 --- a/baseball/src/app/api/pitching-appearances/route.ts +++ b/baseball/src/app/api/pitching-appearances/route.ts @@ -27,6 +27,7 @@ export async function POST(request: Request) { const payload = pitchingAppearanceSchema.parse(await request.json()); const appearance = await PitchingAppearanceModel.create({ ...payload, + gameId: null, gameDate: new Date(payload.gameDate) }); diff --git a/baseball/src/app/api/players/route.ts b/baseball/src/app/api/players/route.ts index 4ff7c0f..57ceb70 100644 --- a/baseball/src/app/api/players/route.ts +++ b/baseball/src/app/api/players/route.ts @@ -31,12 +31,33 @@ export async function GET(request: Request) { gameDate ); + const latestAppearanceMap = Object.fromEntries( + players.map((player) => { + const latestAppearance = appearances + .filter((appearance) => String(appearance.playerId) === String(player._id)) + .sort((a, b) => new Date(b.gameDate).getTime() - new Date(a.gameDate).getTime())[0]; + + return [ + String(player._id), + latestAppearance + ? { + appearanceId: String(latestAppearance._id), + gameDate: toDateOnly(latestAppearance.gameDate), + pitchCount: latestAppearance.pitchCount, + notes: latestAppearance.notes ?? "" + } + : null + ]; + }) + ); + return NextResponse.json( serialize( players.map((player) => ({ ...player, _id: String(player._id), - pitcherAvailability: availabilityMap[String(player._id)] + pitcherAvailability: availabilityMap[String(player._id)], + latestPitching: latestAppearanceMap[String(player._id)] })) ) ); diff --git a/baseball/src/app/games/history/page.tsx b/baseball/src/app/games/history/page.tsx new file mode 100644 index 0000000..a4392a5 --- /dev/null +++ b/baseball/src/app/games/history/page.tsx @@ -0,0 +1,5 @@ +import { GameHistoryClient } from "@/components/GameHistoryClient"; + +export default function GameHistoryPage() { + return ; +} diff --git a/baseball/src/app/pitching/page.tsx b/baseball/src/app/pitching/page.tsx deleted file mode 100644 index dd680fc..0000000 --- a/baseball/src/app/pitching/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { PitchTrackingClient } from "@/components/PitchTrackingClient"; - -export default function PitchTrackingPage() { - return ; -} diff --git a/baseball/src/components/AppShell.tsx b/baseball/src/components/AppShell.tsx index 774681a..e7f9bd2 100644 --- a/baseball/src/components/AppShell.tsx +++ b/baseball/src/components/AppShell.tsx @@ -1,6 +1,6 @@ "use client"; -import { BarChart3, ClipboardList, FileText, ShieldCheck, TimerReset, Trophy, Users } from "lucide-react"; +import { BarChart3, ClipboardList, FileClock, FileText, ShieldCheck, Trophy, Users } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { cn } from "@/lib/utils"; @@ -8,8 +8,8 @@ import { cn } from "@/lib/utils"; const navItems = [ { href: "/dashboard", label: "Dashboard", icon: BarChart3 }, { href: "/roster", label: "Roster", icon: Users }, - { href: "/pitching", label: "Pitch Tracking", icon: TimerReset }, { href: "/games", label: "Score Game", icon: FileText }, + { href: "/games/history", label: "Past Games", icon: FileClock }, { href: "/lineup", label: "Generate Lineup", icon: ClipboardList }, { href: "/settings", label: "Pitching Rules", icon: ShieldCheck } ]; @@ -48,7 +48,7 @@ export function AppShell({