Add gameday TeamSnap loading state

This commit is contained in:
Codex
2026-04-23 12:34:12 -05:00
parent a26a611d3b
commit d6630e1879
2 changed files with 62 additions and 11 deletions

View File

@@ -60,6 +60,8 @@ export function GamedayPage() {
const [playerFilterMenuOpen, setPlayerFilterMenuOpen] = useState(false); const [playerFilterMenuOpen, setPlayerFilterMenuOpen] = useState(false);
const playerFilterMenuRef = useRef<HTMLDivElement | null>(null); const playerFilterMenuRef = useRef<HTMLDivElement | null>(null);
const teamId = walkup.selectedTeamId; const teamId = walkup.selectedTeamId;
const resolvedSelectedGameId =
selectedGameId || searchParams.get("gameId") || (walkup.nextGame ? String(walkup.nextGame.id) : "");
const { const {
activeKey: playingClipKey, activeKey: playingClipKey,
activeDetails: nowPlaying, activeDetails: nowPlaying,
@@ -111,25 +113,25 @@ export function GamedayPage() {
}, [playerFilterMenuOpen]); }, [playerFilterMenuOpen]);
const assignmentsQuery = useQuery({ const assignmentsQuery = useQuery({
queryKey: ["assignments", selectedGameId], queryKey: ["assignments", resolvedSelectedGameId],
queryFn: () => api.listAssignments(selectedGameId), queryFn: () => api.listAssignments(resolvedSelectedGameId),
enabled: Boolean(selectedGameId), enabled: Boolean(resolvedSelectedGameId),
retry: 0, retry: 0,
}); });
const preparedGame = selectedGameId ? loadPreparedGame(selectedGameId) : null; const preparedGame = resolvedSelectedGameId ? loadPreparedGame(resolvedSelectedGameId) : null;
const assignmentList = assignmentsQuery.data ?? preparedGame?.assignments ?? []; const assignmentList = assignmentsQuery.data ?? preparedGame?.assignments ?? [];
const eventLineupQuery = useQuery({ const eventLineupQuery = useQuery({
queryKey: ["teamsnap", "eventLineup", teamId, selectedGameId], queryKey: ["teamsnap", "eventLineup", teamId, resolvedSelectedGameId],
queryFn: () => teamsnapClient.loadEventLineupData(teamId, selectedGameId), queryFn: () => teamsnapClient.loadEventLineupData(teamId, resolvedSelectedGameId),
enabled: Boolean(teamId && selectedGameId), enabled: Boolean(teamId && resolvedSelectedGameId),
}); });
const availabilityQuery = useQuery({ const availabilityQuery = useQuery({
queryKey: ["teamsnap", "availabilities", teamId, selectedGameId], queryKey: ["teamsnap", "availabilities", teamId, resolvedSelectedGameId],
queryFn: () => teamsnapClient.loadAvailabilities(teamId, selectedGameId), queryFn: () => teamsnapClient.loadAvailabilities(teamId, resolvedSelectedGameId),
enabled: Boolean(teamId && selectedGameId), enabled: Boolean(teamId && resolvedSelectedGameId),
}); });
const orderedMembers = useMemo( const orderedMembers = useMemo(
@@ -147,7 +149,12 @@ export function GamedayPage() {
? orderedMembers ? orderedMembers
: orderedMembers.filter((member) => (playerFilter === "players" ? isPlayerMember(member) : !isPlayerMember(member))); : orderedMembers.filter((member) => (playerFilter === "players" ? isPlayerMember(member) : !isPlayerMember(member)));
const selectedGame = walkup.games.find((game) => String(game.id) === selectedGameId) ?? null; const selectedGame = walkup.games.find((game) => String(game.id) === resolvedSelectedGameId) ?? null;
const isLoadingTeamSnapData =
walkup.teamsQuery.isLoading ||
walkup.membersQuery.isLoading ||
walkup.eventsQuery.isLoading ||
(Boolean(teamId && resolvedSelectedGameId) && (eventLineupQuery.isLoading || availabilityQuery.isLoading));
function selectGame(gameId: string) { function selectGame(gameId: string) {
setSelectedGameId(gameId); setSelectedGameId(gameId);
@@ -168,6 +175,21 @@ export function GamedayPage() {
); );
} }
if (isLoadingTeamSnapData) {
return (
<section className="page-grid gameday-page">
<div className="panel gameday-loading-panel" role="status" aria-live="polite">
<div className="gameday-loading-spinner spinner-border text-primary" aria-hidden="true" />
<div className="gameday-loading-copy">
<span className="gameday-loading-label">Waiting for TeamSnap</span>
<strong>Loading gameday data</strong>
<span className="muted">Teams, games, roster data, and lineup details are being fetched.</span>
</div>
</div>
</section>
);
}
return ( return (
<section className="page-grid gameday-page"> <section className="page-grid gameday-page">
{isPlaybackPlaying && nowPlaying ? ( {isPlaybackPlaying && nowPlaying ? (

View File

@@ -279,6 +279,35 @@ select {
margin-top: 0; margin-top: 0;
} }
.gameday-loading-panel {
min-height: min(42vh, 24rem);
display: grid;
place-items: center;
gap: 1rem;
text-align: center;
padding: 2rem 1.5rem;
}
.gameday-loading-spinner {
width: 3rem;
height: 3rem;
border-width: 0.28rem;
}
.gameday-loading-copy {
display: grid;
gap: 0.35rem;
max-width: 24rem;
}
.gameday-loading-label {
color: var(--accent);
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.stack { .stack {
display: grid; display: grid;
gap: 0.75rem; gap: 0.75rem;