feat(widget): scope dashboard yield discovery by category#527
Conversation
Implement category-scoped-yield-discovery for dashboard earn. Replace the all-yield union load with network-scoped category probes. Add yield summary fetching and category-to-API-type helpers. Keep token switching, yield counts, and max rates scoped to the active category. Add focused tests for mappings, summary visibility, pagination, and token filtering.
|
📝 WalkthroughWalkthroughThis PR introduces a complete dashboard yield category filtering system that enables users to discover and select yield opportunities filtered by category (stake, defi, rwa). It adds API-driven type-to-category mappings, category-probing hooks, token-scoped filtering, updated state management, and UI components that reflect category-aware yield availability. ChangesDashboard Yield Category Filtering
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx (1)
538-544: 💤 Low valueConsider adding user feedback when yield lookup fails.
When
yieldIdis undefined (line 542), the function returns silently. IftokenListYieldsis still loading or the token unexpectedly has no yields for the active category, the user clicks a token and nothing happens.This may be intentional UX (tokens without yields should be visually disabled per the stack context), but if that gating ever fails, a defensive log or brief toast would help diagnose issues.
🤖 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 `@packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx` around lines 538 - 544, Add a defensive user feedback path when yield lookup fails: in the block that computes yieldId from tokenListYields.yieldIdsByToken using tokenString(tokenBalance.token), detect when yieldId is undefined and instead of returning silently, call a UI feedback function (e.g., showToast or processLogger.warn) explaining "No yields found for selected token" or "Yields still loading" and include contextual data (tokenString(tokenBalance.token)); then return early. Update the code around tokenListYields, yieldId, tokenString, tokenBalance, and selectDashboardTokenYield so successful lookups still call selectDashboardTokenYield({ token: tokenBalance.token, yieldId }) and failed lookups produce the toast/log for diagnostics.
🤖 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 `@packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts`:
- Around line 43-57: The probe currently fetches only a single page in the
dashboard category queries (see queries mapping in
use-dashboard-yield-catalog.ts using fetchYieldSummariesPage with
DEFAULT_YIELD_SUMMARIES_PAGE_LIMIT and getYieldSummariesQueryKey) which can
falsely mark a category as unavailable if visible yields are on later pages;
change the probe logic to page through results (or request an unbounded/large
limit if supported) until either a visible yield is found or no more pages
remain, and then base the visibility check and initial selection seeding on that
aggregated result instead of the single first page; ensure the same fix is
applied to both probe usages (the query mapping and the second probe at lines
~68-74) and preserve abort signal handling when iterating pages.
In `@packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx`:
- Around line 503-527: selectDashboardTokenYield currently calls
getYieldOpportunity(...).map(...).run() and ignores the Left path, causing
silent failures; modify the EitherAsync chain in selectDashboardTokenYield to
handle errors explicitly (use .ifLeft(), .bimap(), or .caseOf() before .run())
and dispatch a failure/clear-loading action (or log/show error) so the reducer
sees the error and UI state is cleared; ensure the same dispatch target
("dashboard/token-yield/select") success path remains unchanged and add a new
dispatch/action for the error case (or reuse an existing error/clear action) so
network/invalid-yield errors are surfaced.
---
Nitpick comments:
In `@packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx`:
- Around line 538-544: Add a defensive user feedback path when yield lookup
fails: in the block that computes yieldId from tokenListYields.yieldIdsByToken
using tokenString(tokenBalance.token), detect when yieldId is undefined and
instead of returning silently, call a UI feedback function (e.g., showToast or
processLogger.warn) explaining "No yields found for selected token" or "Yields
still loading" and include contextual data (tokenString(tokenBalance.token));
then return early. Update the code around tokenListYields, yieldId, tokenString,
tokenBalance, and selectDashboardTokenYield so successful lookups still call
selectDashboardTokenYield({ token: tokenBalance.token, yieldId }) and failed
lookups produce the toast/log for diagnostics.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e84fb7d2-df92-49f3-a48e-a3d89a1ea1eb
📒 Files selected for processing (13)
packages/widget/src/domain/types/yields.tspackages/widget/src/hooks/api/use-dashboard-yield-catalog.tspackages/widget/src/hooks/api/use-token-list-yields.tspackages/widget/src/hooks/api/use-yield-opportunity/get-yield-opportunity.tspackages/widget/src/hooks/api/use-yield-summaries.tspackages/widget/src/pages/details/earn-page/components/select-token-section/select-token-list-item.tsxpackages/widget/src/pages/details/earn-page/components/select-token-section/select-token.tsxpackages/widget/src/pages/details/earn-page/state/earn-page-context.tsxpackages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsxpackages/widget/src/pages/details/earn-page/state/types.tspackages/widget/tests/domain/dashboard-yield-category-types.test.tspackages/widget/tests/domain/token-list-yields.test.tspackages/widget/tests/domain/yield-summaries.test.ts
| queries: dashboardYieldCategories.map((category) => { | ||
| const params: YieldSummariesParams = { | ||
| network: network ?? undefined, | ||
| types: getApiYieldTypesForDashboardCategory(category), | ||
| sort: "rewardRateDesc", | ||
| limit: DEFAULT_YIELD_SUMMARIES_PAGE_LIMIT, | ||
| }; | ||
|
|
||
| return { | ||
| enabled: probeEnabled, | ||
| staleTime, | ||
| queryKey: getYieldSummariesQueryKey(params), | ||
| queryFn: ({ signal }: { signal: AbortSignal }) => | ||
| fetchYieldSummariesPage({ apiClient, params, signal }), | ||
| }; |
There was a problem hiding this comment.
Single-page probing can falsely mark categories as unavailable.
Line 55 fetches only one page (Line 48 limit), and Line 69 searches visibility only within that page. If visible yields start after the first page, the category is incorrectly hidden and no initial selection is seeded.
💡 Suggested fix
import {
DEFAULT_YIELD_SUMMARIES_PAGE_LIMIT,
+ fetchAllYieldSummaries,
fetchYieldSummariesPage,
getYieldSummariesQueryKey,
isVisibleYieldSummary,
type YieldSummariesParams,
} from "./use-yield-summaries";
@@
return {
enabled: probeEnabled,
staleTime,
- queryKey: getYieldSummariesQueryKey(params),
+ queryKey: getYieldSummariesQueryKey({ ...params, allPages: true }),
queryFn: ({ signal }: { signal: AbortSignal }) =>
- fetchYieldSummariesPage({ apiClient, params, signal }),
+ fetchAllYieldSummaries({ apiClient, params, signal }),
};
}),
});Also applies to: 68-74
🤖 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 `@packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts` around lines 43
- 57, The probe currently fetches only a single page in the dashboard category
queries (see queries mapping in use-dashboard-yield-catalog.ts using
fetchYieldSummariesPage with DEFAULT_YIELD_SUMMARIES_PAGE_LIMIT and
getYieldSummariesQueryKey) which can falsely mark a category as unavailable if
visible yields are on later pages; change the probe logic to page through
results (or request an unbounded/large limit if supported) until either a
visible yield is found or no more pages remain, and then base the visibility
check and initial selection seeding on that aggregated result instead of the
single first page; ensure the same fix is applied to both probe usages (the
query mapping and the second probe at lines ~68-74) and preserve abort signal
handling when iterating pages.
| const selectDashboardTokenYield = useCallback( | ||
| ({ | ||
| token, | ||
| yieldId, | ||
| }: { | ||
| token: TokenBalanceScanResponseDto["token"]; | ||
| yieldId: Yield["id"]; | ||
| }) => { | ||
| getYieldOpportunity({ | ||
| yieldId, | ||
| isLedgerLive, | ||
| apiClient, | ||
| queryClient, | ||
| }) | ||
| .map((yieldDto) => { | ||
| dispatch({ | ||
| type: "dashboard/token-yield/select", | ||
| data: { token, yieldDto }, | ||
| }); | ||
| return yieldDto; | ||
| }) | ||
| .run(); | ||
| }, | ||
| [apiClient, dispatch, isLedgerLive, queryClient] | ||
| ); |
There was a problem hiding this comment.
Silent failure when getYieldOpportunity rejects.
The EitherAsync chain calls .run() but only handles the success path via .map(). If getYieldOpportunity fails (network error, invalid yield), the promise resolves to a Left that is ignored—no dispatch occurs, no loading state clears, and the user sees no feedback.
Consider handling the error branch explicitly, e.g., via .ifLeft() before .run(), or using .caseOf() / .bimap() to surface failures to the user or at least reset any pending state.
🤖 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 `@packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx`
around lines 503 - 527, selectDashboardTokenYield currently calls
getYieldOpportunity(...).map(...).run() and ignores the Left path, causing
silent failures; modify the EitherAsync chain in selectDashboardTokenYield to
handle errors explicitly (use .ifLeft(), .bimap(), or .caseOf() before .run())
and dispatch a failure/clear-loading action (or log/show error) so the reducer
sees the error and UI state is cleared; ensure the same dispatch target
("dashboard/token-yield/select") success path remains unchanged and add a new
dispatch/action for the error case (or reuse an existing error/clear action) so
network/invalid-yield errors are surfaced.
| tokenYieldCountsByToken, | ||
| }: { | ||
| item: TokenBalanceScanResponseDto; | ||
| selectedDashboardYieldCategory: unknown; |
There was a problem hiding this comment.
unknown could be DashboardYieldCategory | null right?
Implement category-scoped-yield-discovery for dashboard earn.
Replace the all-yield union load with network-scoped category probes. Add yield summary fetching and category-to-API-type helpers. Keep token switching, yield counts, and max rates scoped to the active category.
Add focused tests for mappings, summary visibility, pagination, and token filtering.
Added
Description of new functionality, feature, or content that has been added in this pull request.
Changed
Description of the modifications made to existing functionality, feature, or content in this pull request. This could include changes to code, CI, documentation, etc.
Summary by CodeRabbit
Release Notes
New Features
Tests