A frontend app for exploring ChatGPT iOS user reviews from the Appfigures exercise API.
Tested in Chrome (latest).
npm install
cp .env.example .env
npm startOpen the URL shown in the terminal (default http://localhost:5173).
Run tests: npm run test:run
- Search — type a keyword; results update after a 300ms debounce. Use browser Back to restore the previous query.
- Rating — change the star filter; the URL updates. Back returns to the prior rating/search state.
- Deep link — open
/?q=crash&rating=3; filters and results load from the URL. - Load more — append the next page; date sections grow without resetting earlier results.
- Error + Retry — block the network in DevTools, trigger a fetch, then click Retry after restoring connectivity.
| Variable | Description |
|---|---|
VITE_REVIEWS_API_URL |
Reviews API endpoint (see .env.example) |
Keep the exercise URL private. Do not commit .env or publish the proxy URL.
| Command | Description |
|---|---|
npm start |
Start dev server |
npm run build |
Typecheck + production build |
npm run preview |
Preview production build |
npm run test |
Vitest watch mode |
npm run test:run |
Vitest single run |
npm run lint |
ESLint |
npm run typecheck |
TypeScript check |
URL (q, rating) → useReviewFilters → useReviews → fetchReviews
↓
groupReviewsByDate → ReviewList
- API layer: native
fetch+ normalization at the boundary (normalizeReview) - Routing: react-router-dom v7 (
createBrowserRouter) - Styling: CSS Modules
- Date grouping: applied to the currently loaded review subset (pagination appends into existing buckets)
- URL history: search typing updates the URL with
replace; a history entry ispushed on debounce commit (300ms), input blur, or rating change. The first keystroke after a committed search alsopushes so Back restores the previous filter state.
- Native
fetchinstead of a data library — one endpoint, straightforward pagination, andAbortControllerfor in-flight cancellation. Keeps the exercise scope small. - URL as source of truth for filters —
qandratinglive in search params so links are shareable and browser history works as expected. - Client-side date grouping — buckets follow the PDF rules (
Today,Yesterday, week/month sections, thenMMM yyyy). Grouping runs on loaded reviews only, so Load more extends existing sections. - Frozen
referenceDatein tests — date buckets are deterministic; avoids flaky tests around midnight/week boundaries. - Rating kept in URL despite API behavior — the proxy accepts
ratingbut does not filter by stars in practice (see below). The UI still sends it so the filter state and shareable URLs stay consistent.
The exercise proxy accepts q and rating query params, but rating is not applied server-side in practice — responses can include mixed star values. The UI still sends rating and keeps it in the URL so filters and shareable links stay in sync.
Unit tests cover URL parsing (areFiltersEqual, isStartingSearchDraft), date grouping with a frozen TEST_REFERENCE_DATE, API URL building/normalization, formatting helpers, and review card rendering.
npm run test:runSelf-contained Vite project. After npm install, copy .env.example to .env and run npm start. The exercise API URL is configured via environment variable only.