"use client"; import { Alert, Box, Button, Card, CardContent, Divider, MenuItem, Stack, TextField, Typography } from "@mui/material"; import { useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { ConfirmDialog } from "@/components/ConfirmDialog"; import { EmptyState } from "@/components/EmptyState"; import { PlayerForm, emptyPlayerForm, toPlayerForm } from "@/components/PlayerForm"; import { SectionCard } from "@/components/SectionCard"; import { StatusBadge } from "@/components/StatusBadge"; import { fetchJson } from "@/lib/client"; import { formatPlayerName } from "@/lib/utils"; import type { PitchingAppearanceRecord, PlayerInput, PlayerRecord } from "@/lib/types"; export function RosterClient() { const [players, setPlayers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [message, setMessage] = useState(null); const [editingPlayerId, setEditingPlayerId] = useState(null); const [playerPendingDelete, setPlayerPendingDelete] = useState(null); const [playerForm, setPlayerForm] = useState(emptyPlayerForm()); const [appearanceForm, setAppearanceForm] = useState({ playerId: "", gameDate: new Date().toISOString().slice(0, 10), pitchCount: 20, notes: "" }); const editingPlayer = useMemo( () => players.find((player) => player._id === editingPlayerId) ?? null, [editingPlayerId, players] ); async function loadPlayers() { setLoading(true); setError(null); try { const response = await fetchJson("/api/players"); setPlayers(response); if (response.length > 0 && !appearanceForm.playerId) { setAppearanceForm((current) => ({ ...current, playerId: response[0]._id })); } } catch (loadError) { setError(loadError instanceof Error ? loadError.message : "Failed to load roster."); } finally { setLoading(false); } } useEffect(() => { void loadPlayers(); }, []); useEffect(() => { if (editingPlayer) { setPlayerForm(toPlayerForm(editingPlayer)); } else { setPlayerForm(emptyPlayerForm()); } }, [editingPlayer]); async function submitPlayer() { try { const url = editingPlayerId ? `/api/players/${editingPlayerId}` : "/api/players"; const method = editingPlayerId ? "PATCH" : "POST"; await fetchJson(url, { method, body: JSON.stringify(playerForm) }); setMessage(editingPlayerId ? "Player updated." : "Player added."); setEditingPlayerId(null); setPlayerForm(emptyPlayerForm()); await loadPlayers(); } catch (submitError) { setError(submitError instanceof Error ? submitError.message : "Unable to save player."); } } async function deletePlayer(player: PlayerRecord) { try { await fetchJson(`/api/players/${player._id}`, { method: "DELETE" }); setMessage("Player removed."); setPlayerPendingDelete(null); await loadPlayers(); } catch (deleteError) { setError(deleteError instanceof Error ? deleteError.message : "Unable to delete player."); } } async function logAppearance() { try { await fetchJson("/api/pitching-appearances", { method: "POST", body: JSON.stringify(appearanceForm) }); setMessage("Pitching appearance recorded."); await loadPlayers(); } catch (submitError) { setError(submitError instanceof Error ? submitError.message : "Unable to save pitching appearance."); } } return ( setPlayerPendingDelete(null)} onConfirm={() => (playerPendingDelete ? void deletePlayer(playerPendingDelete) : undefined)} /> {message ? {message} : null} {error ? {error} : null} void submitPlayer()} submitLabel={editingPlayerId ? "Save Changes" : "Add Player"} /> setAppearanceForm((current) => ({ ...current, playerId: event.target.value }))} > {players.map((player) => ( {formatPlayerName(player.firstName, player.lastName)} ))} setAppearanceForm((current) => ({ ...current, gameDate: event.target.value }))} slotProps={{ inputLabel: { shrink: true } }} /> setAppearanceForm((current) => ({ ...current, pitchCount: Number(event.target.value) }))} /> setAppearanceForm((current) => ({ ...current, notes: event.target.value }))} sx={{ gridColumn: "1 / -1" }} /> {loading ? ( Loading roster... ) : players.length > 0 ? ( {players.map((player) => ( #{player.jerseyNumber} {formatPlayerName(player.firstName, player.lastName)} {player.primaryPosition} {player.secondaryPosition ? ` / ${player.secondaryPosition}` : ""} {player.tertiaryPosition ? ` / ${player.tertiaryPosition}` : ""} Bats/Throws {player.batsThrows} Status {player.isActive ? "Active" : "Inactive"} Pitching {player.pitcherAvailability.lastPitchedDate ? `${player.pitcherAvailability.lastPitchCount} pitches on ${player.pitcherAvailability.lastPitchedDate}` : "No history"} {player.notes ? ( {player.notes} ) : null} ))} ) : ( )} ); }