Simplify home and profile pages
This commit is contained in:
4
PLAN.md
4
PLAN.md
@@ -14,6 +14,10 @@
|
||||
- Installable React PWA shell with offline-ready game prep scaffolding.
|
||||
- Docker-based local development stack.
|
||||
|
||||
## Completed UI Cleanup
|
||||
- Home page now acts as a lightweight landing page with direct links to Library and Gameday.
|
||||
- Removed the old game-list-heavy dashboard content that was not useful as a landing surface.
|
||||
|
||||
## Storage Status
|
||||
- Backend media persists in the `backend-media` named Docker volume.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Walkup is a baseball walk-up song app with a React PWA frontend and a FastAPI ba
|
||||
- The app uses React Router for navigation and TanStack Query for server state.
|
||||
- TeamSnap data is loaded through the official JavaScript SDK from the browser after the backend provides an access token.
|
||||
- The UI includes player, gameday, and library views for clip management and gameday playback.
|
||||
- The home page is a lightweight landing page that orients users and links to the Library and Gameday views.
|
||||
- The app is shipped as a PWA with install and offline-prep behavior.
|
||||
|
||||
## Backend
|
||||
|
||||
@@ -1,20 +1,45 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { useWalkupContext } from "../hooks/useWalkupContext";
|
||||
import { formatGameDate, formatGameTitle, formatMemberName } from "../lib/teamsnapHelpers";
|
||||
|
||||
export function DashboardPage() {
|
||||
const navigate = useNavigate();
|
||||
const walkup = useWalkupContext();
|
||||
|
||||
if (!walkup.isTeamSnap) {
|
||||
return (
|
||||
<section className="container-fluid py-4">
|
||||
<div className="card bg-dark text-white border-0 shadow-sm">
|
||||
<div className="card-body p-4 p-lg-5">
|
||||
<p className="text-uppercase small text-info-emphasis mb-2">Player flow</p>
|
||||
<h1 className="h2">Sign in with TeamSnap to resolve your player and team context.</h1>
|
||||
<p className="mb-0 text-white-50">The player dashboard depends on your TeamSnap user, roster membership, and upcoming games.</p>
|
||||
<section className="container-fluid py-4 d-grid gap-4">
|
||||
<div className="row g-4">
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="card shadow-sm h-100">
|
||||
<div className="card-body d-grid gap-3">
|
||||
<p className="text-uppercase small text-body-secondary mb-0">Library</p>
|
||||
<h2 className="h4 mb-0">Manage walkup clips</h2>
|
||||
<p className="text-body-secondary mb-0">
|
||||
Upload audio, trim clips, reorder them, and pin them to players before game day.
|
||||
</p>
|
||||
<div>
|
||||
<Link to="/library" className="btn btn-primary">
|
||||
Open Library
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="card shadow-sm h-100">
|
||||
<div className="card-body d-grid gap-3">
|
||||
<p className="text-uppercase small text-body-secondary mb-0">Gameday</p>
|
||||
<h2 className="h4 mb-0">Run the game-day view</h2>
|
||||
<p className="text-body-secondary mb-0">
|
||||
Review lineups, check availability, and play the right walkup clips during the game.
|
||||
</p>
|
||||
<div>
|
||||
<Link to="/gameday" className="btn btn-primary">
|
||||
Open Gameday
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -23,61 +48,36 @@ export function DashboardPage() {
|
||||
|
||||
return (
|
||||
<section className="container-fluid py-4 d-grid gap-4">
|
||||
<div className="card bg-dark text-white border-0 shadow-sm">
|
||||
<div className="card-body p-4 p-lg-5">
|
||||
<p className="text-uppercase small text-info-emphasis mb-2">Player dashboard</p>
|
||||
<h1 className="h2">{walkup.nextGame ? formatGameTitle(walkup.nextGame) : "No upcoming game found yet."}</h1>
|
||||
<p className="mb-0 text-white-50">
|
||||
{walkup.currentPlayer
|
||||
? `${formatMemberName(walkup.currentPlayer)} is ready for the selected team.`
|
||||
: "Your TeamSnap user is connected, but no matching player record was found on the selected team."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-4">
|
||||
<div className="col-12 col-xl-6">
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="card shadow-sm h-100">
|
||||
<div className="card-body d-grid gap-3">
|
||||
<h2 className="h4 mb-0">Next game</h2>
|
||||
{walkup.nextGame ? (
|
||||
<>
|
||||
<strong className="fs-5">{formatGameTitle(walkup.nextGame)}</strong>
|
||||
<div className="text-body-secondary">{formatGameDate(walkup.nextGame)}</div>
|
||||
{walkup.nextGame.locationName ? <div className="text-body-secondary">{walkup.nextGame.locationName}</div> : null}
|
||||
<div className="d-flex flex-wrap gap-2">
|
||||
<button type="button" className="btn btn-primary" onClick={() => navigate("/library")}>
|
||||
Add walkup clip
|
||||
</button>
|
||||
<p className="text-uppercase small text-body-secondary mb-0">Library</p>
|
||||
<h2 className="h4 mb-0">Manage walkup clips</h2>
|
||||
<p className="text-body-secondary mb-0">
|
||||
Upload audio, trim clips, reorder them, and pin them to players before game day.
|
||||
</p>
|
||||
<div>
|
||||
<Link to="/library" className="btn btn-primary">
|
||||
Open Library
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="text-body-secondary">No upcoming games were returned for this team.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-xl-6">
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="card shadow-sm h-100">
|
||||
<div className="card-body d-grid gap-3">
|
||||
<h2 className="h4 mb-0">Upcoming games</h2>
|
||||
<div className="list-group">
|
||||
{walkup.eventsQuery.isLoading ? <div className="text-body-secondary">Loading games...</div> : null}
|
||||
{walkup.games.slice(0, 8).map((game) => (
|
||||
<div
|
||||
key={String(game.id)}
|
||||
className="list-group-item d-flex justify-content-between align-items-center text-start"
|
||||
>
|
||||
<div>
|
||||
<strong>{formatGameTitle(game)}</strong>
|
||||
<div className="text-body-secondary">{formatGameDate(game)}</div>
|
||||
</div>
|
||||
<span className="badge rounded-pill text-bg-warning">{String(game.id) === String(walkup.nextGame?.id) ? "Next" : "Browse"}</span>
|
||||
<p className="text-uppercase small text-body-secondary mb-0">Gameday</p>
|
||||
<h2 className="h4 mb-0">Run the game-day view</h2>
|
||||
<p className="text-body-secondary mb-0">
|
||||
Review lineups, check availability, and play the right walkup clips during the game.
|
||||
</p>
|
||||
<div>
|
||||
<Link to="/gameday" className="btn btn-primary">
|
||||
Open Gameday
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
{!walkup.eventsQuery.isLoading && !walkup.games.length ? (
|
||||
<div className="text-body-secondary">No games were returned for the selected team.</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,16 +25,6 @@ export function ProfilePage() {
|
||||
|
||||
return (
|
||||
<section className="container-fluid py-4 d-grid gap-4">
|
||||
<div className="card bg-dark text-white border-0 shadow-sm">
|
||||
<div className="card-body p-4 p-lg-5">
|
||||
<p className="text-uppercase small text-info-emphasis mb-2">Profile</p>
|
||||
<h1 className="h2 mb-3">{walkup.hasSelectedTeam ? formatTeamLabel(walkup.selectedTeam) : "Choose your team"}</h1>
|
||||
<p className="mb-0 text-white-50">
|
||||
Session details and the selected team live here. The team choice is stored on this device and reused on the
|
||||
next visit.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-4">
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="card shadow-sm h-100">
|
||||
|
||||
Reference in New Issue
Block a user