Repository navigation
fix(browse): per-tree RecentSongs store and Docker dev scripts (#87) - #88
tomast1337 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the frontend RecentSongs state management to use a per-tree Context-backed Zustand store, aiming to fix hydration flashes and pagination desync/race issues (issue #87), and also updates the local Docker Compose workflow to support compose up --wait with MinIO initialization.
Changes:
- Replaced the global
RecentSongsZustand store with a Context-per-tree store, adding explicit actions for pagination, category selection, and category fetching. - Updated the browse home page components to consume the new
recentItemsfeed model (song/ad/loading) and to explicitly trigger category loading. - Added Docker Compose healthchecks and new root scripts to support
docker compose up --waitplus a one-shot MinIO bucket/CORS initializer profile.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Adds Docker helper scripts for compose up/down/reset and MinIO init. |
| docker-compose.yml | Adds healthchecks and introduces a profile-based one-shot mc init service. |
| apps/frontend/src/modules/browse/components/client/context/RecentSongs.context.tsx | Replaces singleton store with Context store; introduces feed item model + abort-based concurrency. |
| apps/frontend/src/modules/browse/components/client/context/HomePage.context.tsx | Simplifies provider composition; removes legacy combined hook. |
| apps/frontend/src/modules/browse/components/client/CategoryButton.tsx | Switches to selector-based store access and explicitly fetches categories. |
| apps/frontend/src/modules/browse/components/HomePageComponent.tsx | Renders the new recentItems feed model and removes implicit loader hooks. |
| apps/frontend/src/app/(content)/page.tsx | Adjusts initial recent-song fetch limit. |
Comments suppressed due to low confidence (1)
docker-compose.yml:85
- The
mcservice definesentrypoint: ['/bin/sh','-c']but thecommandstring also starts with-c '...'. That results in the container running/bin/sh -c "-c '...'", which typically tries to execute a command literally named-cand will fail, preventing MinIO bucket/CORS initialization. Remove the extra leading-cfromcommand(or change the entrypoint to just/bin/sh) so the init script actually runs.
entrypoint: ['/bin/sh', '-c']
depends_on:
minio:
condition: service_healthy
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
command: >
-c '
while ! mc alias set minio http://minio:9000 minioadmin minioadmin; do
echo "Waiting for MinIO to be available..."
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const didLoad = await fetchRecentSongs(nextPage); | ||
| if (!didLoad) { | ||
| set((state) => ({ | ||
| recentItems: state.recentItems.filter( | ||
| (item) => item.type !== 'loading', | ||
| ), | ||
| })); |
There was a problem hiding this comment.
increasePageRecent treats any fetchRecentSongs failure the same, but fetchRecentSongs returns false both for real errors and for intentional aborts. If a user changes category while a “load more” request is in-flight, the aborted increasePageRecent path can run this cleanup and strip the new category’s loading placeholders (and potentially cause a brief empty/flash state). Consider distinguishing aborted vs failed (e.g., return a status enum or throw on abort) and/or only removing the specific placeholders appended by this call (track count/requestId and validate selectedCategory/page before mutating state).
…nd MinIO services, and update npm scripts for improved Docker management.
… pagination - Migrate singleton Zustand store to React Context to allow synchronous SSR hydration and prevent initial render flashes. - Fix pagination desynchronization by incrementing the page state only after a successful network response. - Remove redundant ID-based concurrency checks, relying strictly on AbortController for deterministic network cancellation. - Delete implicit `useRecentSongsCategoriesLoader` side-effect hook in favor of explicit component-level data fetching. Fixes #87
Reworks the
RecentSongsstate management on the home page to fix hydration mismatches and race conditions between concurrent requests, and improves the local Docker workflow.Closes #87.
Changes
Frontend: RecentSongs
create()store with a per-tree store created viacreateStoreand exposed throughRecentSongsProvider/useRecentSongsStore. The store is hydrated synchronously withinitialRecentSongs, which removes theuseEffectinitialization flash and the hydration mismatch.pagecounter now only advances after a successful response, instead of eagerly incrementing before the fetch completes.AbortController, so only the latest request can update state.useRecentSongsCategoriesLoaderauto-loader.CategoryButtonGroupnow callsfetchCategoriesexplicitly when no categories are loaded yet.BROWSER_SONGSin@nbw/config(recentAdCount,recentPageSize,recentFetchCount), and the home page usesrecentFetchCountinstead of the hardcodedlimit: 11with its TODOs.Docker / DX
docker-compose.yml, and disabled the maildev image healthcheck since it can report unhealthy and blockup --wait.mcbucket-setup container is now a one-shot service behind theminio-initprofile and waits for MinIO to be healthy.docker:up,docker:down,docker:reset,docker:reset:freshanddocker:minio-init.docker:upand the reset scripts run the bucket init after the services are healthy.Testing
bun run typecheckpasses.