feat(leaderboard): add seller leaderboard with category filter and realtime#36
feat(leaderboard): add seller leaderboard with category filter and realtime#36davedumto wants to merge 2 commits into
Conversation
…altime (Regen-Bazaar#15) Adds a Top Sellers section to the impact leaderboard. Aggregates active purchases by organization, ranks by revenue then projects sold, and supports filtering by project category. Subscribes to the `purchases` table via Supabase realtime so the board refreshes when new sales land. - New service `sellerLeaderboardService` (`fetchSellerLeaderboard`, `fetchSellerCategories`, `subscribeToPurchaseChanges`). - New `SellerLeaderboard` component with loading / error / empty states and a manual refresh affordance alongside the realtime subscription. Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds a seller leaderboard feature to the marketplace. A new service aggregates purchase data by seller with metrics (projects sold, buyer count, total revenue), supports category filtering, and streams real-time updates. A React component fetches and displays this data in a ranked table with manual refresh and category selection. The component integrates into the existing leaderboard page. ChangesSeller Leaderboard Feature
Sequence DiagramsequenceDiagram
participant Component as SellerLeaderboard
participant Service as sellerLeaderboardService
participant Supabase
Component->>Service: fetchSellerCategories()
Service->>Supabase: query projects (non-null category)
Supabase-->>Service: category rows
Service-->>Component: sorted category array
Component->>Service: fetchSellerLeaderboard(filters)
Service->>Supabase: query purchases with project and organization details
Supabase-->>Service: joined purchase rows
Service->>Service: aggregate by organization, compute metrics
Service-->>Component: sorted SellerLeaderboardEntry array
Component->>Service: subscribeToPurchaseChanges(onChange)
Service->>Supabase: create realtime channel (postgres_changes)
Supabase-->>Service: channel subscription active
Service-->>Component: unsubscribe function
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/lib/sellerLeaderboardService.ts (1)
139-154: 💤 Low valueConsider handling subscription errors.
The realtime subscription doesn't handle connection errors or subscription failures. Supabase's
.subscribe()accepts a callback for status changes that can report errors.♻️ Optional improvement to handle subscription status
export const subscribeToPurchaseChanges = ( - onChange: () => void + onChange: () => void, + onError?: (error: Error) => void ): (() => void) => { const channel = supabase .channel('seller-leaderboard:purchases') .on( 'postgres_changes', { event: '*', schema: 'public', table: 'purchases' }, onChange ) - .subscribe() + .subscribe((status, err) => { + if (status === 'CHANNEL_ERROR' && onError && err) { + onError(err) + } + }) return () => { void supabase.removeChannel(channel) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/sellerLeaderboardService.ts` around lines 139 - 154, The subscribeToPurchaseChanges function currently calls .subscribe() without handling status callbacks; update it to pass a status callback to .subscribe() (or to .on(...) if using that overload) that checks for subscription errors/rejections and connection status, logs or surfaces errors via your logger (or an onError callback), and ensures onChange only runs for actual data events; also ensure the returned teardown still removes the created channel variable if the subscription failed. Target symbols: subscribeToPurchaseChanges, channel, and the .subscribe() call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/SellerLeaderboard.tsx`:
- Around line 39-52: The load function (useCallback load) can suffer a race
where earlier fetchSellerLeaderboard responses overwrite later ones; modify load
to ignore stale responses by using an AbortController or a request-version
token: create an AbortController (or increment a local requestId counter stored
in a ref) each time load starts, pass the controller.signal to
fetchSellerLeaderboard (or capture the current requestId) and on response only
call setEntries/setError if the request wasn't aborted and the requestId matches
the latestRef; also ensure any real-time event handler that calls load triggers
the same mechanism so inflight requests are cancelled or ignored (apply the same
pattern to the other load-like function at lines 68-77).
---
Nitpick comments:
In `@src/lib/sellerLeaderboardService.ts`:
- Around line 139-154: The subscribeToPurchaseChanges function currently calls
.subscribe() without handling status callbacks; update it to pass a status
callback to .subscribe() (or to .on(...) if using that overload) that checks for
subscription errors/rejections and connection status, logs or surfaces errors
via your logger (or an onError callback), and ensures onChange only runs for
actual data events; also ensure the returned teardown still removes the created
channel variable if the subscription failed. Target symbols:
subscribeToPurchaseChanges, channel, and the .subscribe() call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5567bc6d-081d-461e-ac1c-be17c90d03d9
📒 Files selected for processing (3)
src/app/leaderboard/page.tsxsrc/components/SellerLeaderboard.tsxsrc/lib/sellerLeaderboardService.ts
Track the in-flight request via a ref counter so that responses from older load() calls (triggered by category changes or realtime events arriving while a previous load is pending) don't overwrite the latest state. Addresses CodeRabbit review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
purchases, ranked by revenue (tie-break: projects sold), and joined to their organization for display.projects.categoryvalues; `all` returns sellers across every category.DoD coverage
Notes / follow-ups
Closes
closes #15
Test plan
Summary by CodeRabbit