Repair the Weekly Operations Dashboard
The operations team uses this screen to spot a drop in conversion during the week. The existing data loader is intentionally delayed, and the UI must remain correct when the request is still in flight, when a filter removes every day, or when the request fails.
The provided loader succeeds initially, rejects the first refresh, and succeeds on the following retry. Keep that deterministic boundary so failure and recovery can be exercised locally.
Requirements
- Load the provided metrics through an effect and ignore a result after unmount or refresh.
- Store raw metrics and the selected filter as domain state; keep request lifecycle state separate.
- Derive visible rows, totals, and conversion rate.
- Keep all summaries consistent with the active filter.
- Show loading, failed-request, retry, and empty states.
Do not add a separate state value for visits, conversions, or conversion rate. The visible rows are the source for all three.
What to explain in your review
- Why must a refresh ignore the previous request’s result?
- Why is storing raw metrics and the selected filter safer than storing each summary?
- How should the empty state differ from a failed request?
Reference solution notes
The reference uses one effect per load attempt, an active guard in cleanup, and a retry counter to start a fresh request. It derives the filtered rows and all summaries during render. A valid alternative is an AbortController around a real fetch; the important behavior is that obsolete work cannot overwrite the current screen. Common mistakes include calculating totals from the unfiltered collection, hiding the loader while a refresh is pending, treating zero matches as an error, and updating state after unmount.