# GitHub Contribution Heatmap

> Fetch contribution data for a GitHub-style heatmap using **SWR**. The grid and components are already built — your job is to wire up data fetching with loading skeletons, error handling, and year navigation to bring the heatmap to life.

- Difficulty: intermediate
- Tags: useState, fetching, SWR
- Estimated time: 30 minutes
- Tests: 7
- Requires subscription: yes

## Overview

Fetch contribution data for a GitHub-style heatmap using **SWR**. The grid and components are already built — your job is to wire up data fetching with loading skeletons, error handling, and year navigation to bring the heatmap to life.


## Requirements

- Fetch contribution data from `https://example-heatmap?year={year}`.
- The API response shape depends on the status code:

  Success (200):
  ```typescript
  {
    total: number;
    contributions: {
      date: string;
      intensity: string;
      count: number;
    }
    [][];
  }
  ```

  Failure (500):
  ```typescript
  {
    error: string;
  }
  ```

- Display a loading skeleton while data is being fetched.
- Display an error skeleton when the request fails.
- Display the heatmap grid with contributions when data loads successfully.
- Allow switching between years (2023-2026) with interactive buttons.
- Highlight the currently selected year button.
- Calculate the offset so January 1st aligns with the correct weekday column.


## Notes

- `contributions` is a 2D array (weeks × days). You'll need to flatten it before passing to `HeatmapGrid`.
- The mock API has a random delay of 300-500ms and fails ~20% of requests.
- `Components` and `utils` are read-only — you'll find `Skeleton`, `SkeletonWithError`, `HeatmapGrid`, `Button`, and all layout helpers already available.
- The `offset` tells `HeatmapGrid` where January 1st falls in the first column of the grid.
- This challenge is designed to be solved with **[SWR](https://swr.vercel.app/)**. It handles loading state, error state, caching, and revalidation automatically when the key changes. In a real app nobody writes manual `useEffect` orchestration with `isLoading`, `error`, abort controllers, and cache invalidation for a fetch — libraries like SWR, TanStack Query, or RTK Query solve all of that out of the box.
- **You need a custom fetcher.** SWR won't know a request failed unless the fetcher throws. The pattern is always the same — check `res.ok`, parse the error body, and `throw new Error(...)`. This is universal across SWR, TanStack Query, and RTK Query; none of them do this for you.
- Pass the server's error message to `SkeletonWithError` so the user sees what went wrong.
- By the way, the data comes from **Linus Torvalds'** real GitHub contributions — every cell you see reflects actual commits, merges, and pull requests by the creator of Linux and Git. He almost doesn't rest. And you? Keep working.


## Tests

01. renders the app title
02. shows skeleton while loading
03. displays heatmap grid with contributions when data loads
04. shows skeleton with error when request fails
05. highlights 2026 as the selected year button
06. fetches new data when switching to a different year
07. aligns January 1st to the correct weekday for each year

