Welcome back! So far, you have learned how to fetch and display a user’s reading shelf, update progress optimistically, edit shelf status, and validate forms. In this lesson, you will take the next step by building a user stats dashboard. This dashboard gives users a clear overview of their reading achievements, such as how many books they have on their shelf, how many they have completed, and their average reading progress.
A user stats dashboard is important because it helps users track their progress and stay motivated. By the end of this lesson, you will know how to fetch user stats from the backend, process the data, and display it in a visually appealing way using React components.
Our app already lets readers build a shelf, update progress with optimistic UI, edit statuses, and validate inputs with Zod + React Hook Form. The next leap is a dashboard-style overview that turns scattered data into actionable insight. A concise stats header—books on shelf, completed count, and average progress—gives users motivation, a sense of achievement, and a quick health check of their reading habits. In this lesson, you will fetch stats from the backend, normalize them for display, and present them with small, reusable React components that slot right into your existing MyShelfPage.
Explanation:
- The function takes a
userIdand fetches stats from the API. - The API returns
avgProgressPctas a number between 0 and 1. To make it easier to display as a percentage, the function multiplies it by 100. - The function returns a normalized
UserStatsobject, which is easier to use in your React components.
Example Output:
If the API returns:
The function will return:
The getUserStats helper encapsulates how we call the backend and shape the response for the UI. It shields components from low-level HTTP concerns and ensures the dashboard always works with a stable, predictable structure. By normalizing avgProgressPct from 0..1 to 0..100, we make percentage rendering trivial in the UI and avoid repeating conversion logic across components.
- Single responsibility: the function fetches from
api/users/:id/statsand returns aUserStatsobject ready for display. - Normalization built-in:
avgProgressPctis multiplied by 100 (with a safe fallback to0) to match UI expectations. - UI-friendly contract: components don’t need to understand backend quirks; they simply render numbers and percentages.
- Type safety: returning
UserStatskeeps the API well-typed across the app.
This separation of concerns makes stats usage consistent and reduces bugs caused by ad-hoc conversions. It also simplifies testing—mocks can focus on the normalized shape rather than backend specifics.
Once you have the stats, you need to display them. This is done using the StatsHeader (already covered) and ProgressBar components.
ProgressBar Component (src/components/ProgressBar.tsx):
The ProgressBar converts a percentage into an intuitive fill. It clamps the value to [0, 100], rounds for visual stability, and uses a single div for the fill so there’s minimal DOM overhead.
- Clamping protects UI: out-of-range values won’t overflow the bar.
- Simple styling: a background rail and a single fill element are easy to theme and animate later.
- ARIA label: communicates the exact percentage to assistive tech, improving accessibility.
Because it’s standalone and stateless, you can reuse ProgressBar anywhere you need a percentage visualization.
Now, let’s see how everything fits together on the main page. The MyShelfPage component fetches the user stats and shelf data, then displays them using the components you just saw.
The main page fetches two data sets: the shelf items and the user stats. Both use React Query with purposeful keys so caching and refetching are predictable.
- Two queries, two concerns:
["shelf", { status, sortBy, order }]isolates shelf variations, while isolates stats per user.
In this lesson, you learned how to build a user stats dashboard by:
- Fetching and normalizing user stats from the API
- Displaying stats using reusable React components
- Integrating the dashboard into the main shelf page with proper loading and error handling
This dashboard gives users a clear and motivating overview of their reading progress. Next, you will get a chance to practice these skills with hands-on exercises. You will fetch user stats, display them, and handle different states to make your app more interactive and user-friendly. Great work getting this far — let’s keep going!
