Skip to content

Rare21ism/CSV-RUNNER-DASHBOARD

Repository files navigation

Runner Dashboard

A clean, interactive web app to upload running metrics from CSV files and visualize performance across multiple runners. Track total miles, averages, and individual progress with real-time charts.

What's Inside

This is a Next.js + React dashboard that lets you:

  • Upload CSV files with running data (date, person, miles)
  • See aggregate metrics and charts across all runners
  • Click to filter by individual runners
  • Toggle person data on/off in the overall chart
  • Load sample data to explore the UI quickly

Built with modern tools: TypeScript, Tailwind CSS, shadcn/ui components, and Recharts for visualization.

Assumptions & Design Decisions

CSV Format

  • We expect exactly 3 columns: date, person, miles run
  • Dates are parsed as ISO strings (e.g., 2025-01-01)
  • Miles are positive numbers; negative values are rejected
  • Empty rows and missing required fields are skipped with error messages

State Management

  • Using React Context (RunDataContext) instead of Redux/Zustand for simplicity
  • Data stays in memory; no persistence layer (fresh start each session)
  • Selected person filter resets when you clear data

UI/UX Choices

  • Header stays sticky at the top for quick access to controls
  • Metric cards are clickable to filter (felt more intuitive than separate filter UI)
  • Top Performer card is interactive—click it to see that runner's data
  • Chart toggles use small pill buttons (not checkboxes) for a modern feel
  • Sample CSV lives in /public for quick loading without a backend

Error Handling

  • Parse errors surface inline, not in a modal—easier to fix and retry
  • No toast notifications; errors appear below the upload card
  • Invalid rows skip silently with a summary error message

Prerequisites

  • Node.js — v18 or later (tested with v20)
  • npm — comes with Node
  • No database or environment variables needed

Setup

1. Install Dependencies

npm install

This installs:

  • next (React framework)
  • react & react-dom (UI library)
  • papaparse (CSV parsing)
  • recharts (charting)
  • tailwindcss (styling)
  • class-variance-authority & tailwind-merge (shadcn/ui utilities)

2. No Environment Variables

No .env file needed. The app runs entirely client-side.

3. No Database or Seeding

Data comes from CSV uploads or the sample file at /public/sample.csv.

Run & Verify

Start the Dev Server

npm run dev

Open http://localhost:3000 (or 3001 if 3000 is busy).

Quick Validation Steps

  1. Load Sample Data

    • Click the green "🎬 Load Sample" button
    • You should see 2 metrics cards populate with Alice & Bob's data
    • Charts appear below (Overall Miles per Day + individual runnerlines)
  2. Click a Metric Card

    • Click the "⭐ Top Performer" card → dashboard filters to that runner
    • Click "🏃 Total Miles" → clears the filter, shows all runners again
  3. Toggle Chart Lines

    • Above the Overall chart, see small pill buttons for each runner (Alice, Bob, etc.)
    • Click a pill to show/hide that runner's line on the chart
    • Useful when too many overlapping runners clutter the view
  4. Upload Your Own CSV

    • Click "📁 Choose file" and pick any CSV with columns: date, person, miles run
    • See results immediately or error messages if format is wrong
    • Example format:
      date,person,miles run
      2025-01-15,Alice,5.2
      2025-01-15,Bob,3.8
      2025-01-16,Alice,4.1
      
  5. Clear Data

    • Click red "🗑️ Clear" button → metrics, charts, and selections reset

Features & What Works

What's Implemented

  • CSV upload with real-time parsing and validation
  • Metric cards: Total Miles, Average, Top Performer, Max
  • Overall Miles per Day line chart (responsive, toggleable per person)
  • Individual runner charts (click a runner, see their log)
  • Sample CSV loader (one-click demo data)
  • Sticky header with branding
  • Dark/light card styling with gradients
  • Fully responsive layout (mobile, tablet, desktop)
  • TypeScript for type safety across components
  • shadcn/ui components for polished buttons and cards

⚠️ Known Limitations

  • No data persistence (refresh = data lost)
  • No export to CSV (one-way upload only)
  • Charts don't zoom or pan (Recharts limitation at this size)
  • No multi-file upload (one at a time)
  • No user accounts or saved sessions
  • No date range filtering (shows all data at once)

🚀 Future Ideas

  • Add date range picker to filter by week/month
  • Export filtered results as CSV
  • Compare two runners side-by-side
  • Store data in localStorage for persistence
  • Add drag-to-reorder chart lines
  • Weekly/monthly aggregate tabs
  • Dark mode toggle

Architecture & Code Structure

components/
├── Header.tsx                 # Sticky nav with logo & settings button
├── CsvUploader.tsx            # File input + error display
├── MetricsCards.tsx           # 4 stat cards (total, avg, top, max)
├── OverallChart.tsx           # Line chart with toggleable runner series
├── PersonChart.tsx            # Individual runner's time series
├── PersonList.tsx             # Runner selector buttons
└── ui/
    ├── button.tsx             # shadcn Button component
    └── card.tsx               # shadcn Card + sub-components

lib/
├── csv/
│   └── parse.ts               # CSV parsing + validation logic
├── metrics/
│   └── calc.ts                # Math: totals, averages, aggregates
└── utils.ts                   # Helper: cn() for Tailwind merging

context/
└── RunDataContext.tsx         # React Context: rows, selectedPerson state

app/
├── layout.tsx                 # Root layout
├── globals.css                # Global Tailwind directives
├── page.tsx                   # Dashboard page component
└── page.module.css            # (if any page-specific styles)

public/
└── sample.csv                 # Demo data (2 sample rows)

State Flow

  1. CsvUploader → parses file → calls setRows() via context
  2. MetricsCards → reads rows from context → computes stats → displays cards
  3. OverallChart → reads rows → builds per-person time series → user toggles visibility
  4. PersonList → reads rows + selectedPerson → shows runner buttons
  5. PersonChart → filters rows by selectedPerson → shows individual chart

No prop drilling; everything flows through RunDataContext.

Key Functions

  • parseCsv(file) → Promise resolving to { rows, errors }
  • computeMetrics(rows){ total, avg, min, max }
  • aggregateByDate(rows) → array of { date, miles } per day
  • useRunData() → returns context value or throws error if outside provider

Accessibility & UI

Focus & Keyboard Navigation

  • All buttons have visible focus rings (ring-2 ring-blue-500)
  • Tab order follows visual flow: Header → Upload → Metrics → Charts → Runners
  • Buttons are large enough to tap on mobile (min 44px)

Labels & Semantics

  • Form inputs have associated <label> elements
  • Error messages use role="alert" attributes (implied by error container)
  • Chart titles use <h2> and <h3> tags, not divs

Color Contrast

  • Text on white: gray-900 (9:1 ratio, WCAG AAA)
  • Text on colored cards: ensure 7:1+ ratio with gradients
  • Error messages: red-800 on red-50 background (clear distinction)

Spacing & Typography

  • Base spacing uses Tailwind's 4px grid (gap-4 = 1rem)
  • Metric card icons are large (text-2xl) and centered
  • Chart labels are 12-14px, readable without zoom
  • Line height on body text: 1.5 (comfortable reading)

Mobile Responsiveness

  • Metrics: 1 column on mobile, 2 on tablet, 4 on desktop
  • Charts: full width, height adjusts for small screens
  • Header nav hidden on mobile, shown on tablet+
  • Upload card stacks vertically on small screens

Theming with shadcn/ui

  • Button variants: default (blue), destructive (red), outline (bordered), ghost (minimal)
  • Card styling: subtle borders, light shadows, no heavy gradients on text
  • Icons via emoji (accessible, no alt text needed)

Dark Mode Ready

  • All colors defined in Tailwind config
  • Cards use dark: variants for dark theme (future feature)
  • Text contrast tested against both light and dark backgrounds

Browser Support

Tested & working on:

  • Chrome 90+
  • Firefox 88+
  • Safari 15+
  • Edge 90+

Mobile: iOS Safari 15+, Chrome Android 90+

Development Tips

Adding a New Component

  1. Create in components/ (or components/ui/ for reusables)
  2. Use TypeScript interfaces for props
  3. Import from @/components/ (alias works thanks to tsconfig)

Modifying CSV Schema

Edit REQUIRED_HEADERS in lib/csv/parse.ts and update validation logic.

Changing Chart Colors

Edit PERSON_COLORS in components/OverallChart.tsx.

Building for Production

npm run build
npm start

Builds a static-optimized Next.js app ready for deployment.

Troubleshooting

"Port 3000 is in use"

  • Next.js auto-switches to 3001. If you want a specific port:
    npm run dev -- -p 3003

CSV Upload Shows No Errors But No Data Appears

  • Check the CSV headers match exactly: date, person, miles run (case-sensitive)
  • Ensure dates are valid ISO format or parseable by new Date()

Chart Not Showing

  • Make sure at least one valid row of data was loaded
  • Check browser DevTools for console errors

Buttons Look Wrong

  • Clear browser cache and hard-refresh (Ctrl+Shift+R on Windows, Cmd+Shift+R on Mac)

License & Attribution

Built as a learning project. Feel free to fork, modify, and use however you like.


About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors