Skip to content

fix: category selection #532

Merged
petar-omni merged 12 commits into
mainfrom
refactor-page-cta-flow
Jun 10, 2026
Merged

fix: category selection #532
petar-omni merged 12 commits into
mainfrom
refactor-page-cta-flow

Conversation

@petar-omni

@petar-omni petar-omni commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Refactor

    • Moved CTAs from an animated footer into page-level CTAs; footer outlet and its providers removed, layout sizing updated.
    • Tabs route matching updated so /positions also maps to the Manage tab.
  • New Features

    • Added a reusable Page CTA component and standardized CTA API across pages.
    • New Estimated Reward widget and support for displaying Price Per Share / Minimum Subscription labels.
  • Other

    • Yield categories reordered to: RWA, DeFi, Stake; translation text updated (e.g., "Redemption time").

@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 135a816

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b580447-494f-4d98-894a-c8548de2ab86

📥 Commits

Reviewing files that changed from the base of the PR and between 6be5b4b and 135a816.

📒 Files selected for processing (6)
  • packages/widget/src/components/atoms/token-icon/provider-icon/index.tsx
  • packages/widget/src/domain/types/yields.ts
  • packages/widget/src/pages-dashboard/position-details/components/position-details-actions.tsx
  • packages/widget/src/pages-dashboard/position-details/position-details-model.tsx
  • packages/widget/src/pages/details/activity-page/hooks/use-activity-filters.ts
  • packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
💤 Files with no reviewable changes (1)
  • packages/widget/src/domain/types/yields.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/widget/src/pages/details/activity-page/hooks/use-activity-filters.ts
  • packages/widget/src/components/atoms/token-icon/provider-icon/index.tsx
  • packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
  • packages/widget/src/pages-dashboard/position-details/components/position-details-actions.tsx

📝 Walkthrough

Walkthrough

Removes footer-outlet contexts/components; adds PageCta type and PageCtaButton; hooks/providers now return CTAs; pages render PageCtaButton; earn/dashboard selection gains category-awareness; price-per-share/min-stake formatters and reward UI consolidated; layout/animation and tests updated.

Changes

Footer Outlet Removal and PageCta Integration

Layer / File(s) Summary
All changes
packages/widget/src/**
Consolidated changes: delete footer-outlet context/component/styles and providers; add PageCta/PageCtaButton; migrate hooks/providers to compute and return cta objects; pages render PageCtaButton; refactor earn/dashboard category flows, add price-per-share and min-stake formatters, consolidate estimated-reward UI, adjust layout/animation, update hooks/api signatures and tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Philippoes
  • jdomingos
  • 0xYoki

Poem

🐰 I hopped through hooks and pages bright,

Swapped footer hooks for CTA light.
Hooks now hand the button near,
Pages render, crystal clear.
Hooray — the UI hops just right!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is completely empty. The required template specifies 'Added' and 'Changed' sections that should document the modifications, but no description content was provided by the author. Add a detailed pull request description following the template, documenting the major changes: removal of footer outlet infrastructure, introduction of PageCta component system, restructuring of yield category selection and dashboard yield catalog logic, and related refactoring across multiple pages and hooks.
Title check ❓ Inconclusive The title 'fix: category selection' is vague and does not clearly convey the primary changes in this comprehensive refactoring, which involves removing footer outlet infrastructure, introducing a PageCta component system, and restructuring yield category selection logic. Consider a more descriptive title that reflects the main architectural changes, such as 'refactor: replace footer outlet with page-level CTA system' or 'refactor: integrate PageCta component across pages and reorganize yield category selection'.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor-page-cta-flow

Comment @coderabbitai help to get the list of available commands and usage tips.

@aws-amplify-eu-central-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-532.d2ribjy8evqo6h.amplifyapp.com

@aws-amplify-eu-central-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-532.df4xyoi0xyeak.amplifyapp.com

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (8)
packages/widget/src/pages/review/hooks/use-pending-review.hook.ts (1)

151-158: ⚡ Quick win

Drop the CTA useMemo unless a consumer needs identity stability.

This object is derived from local state and translations only. Under the React Compiler guideline, prefer a plain PageCta here and keep memoization for boundaries that truly need stable identity.

As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: "React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity."

🤖 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/review/hooks/use-pending-review.hook.ts` around
lines 151 - 158, The CTA object is unnecessarily wrapped in useMemo; remove the
useMemo wrapper and return a plain PageCta object named cta constructed from
t("shared.confirm"), onClickRef.current, disabled: false, and isLoading:
actionPendingMutation.isPending so its identity is not artificially memoized;
update references to the existing cta variable (created where useMemo was) and
remove useMemo import if now unused.

Source: Coding guidelines

packages/widget/src/pages/complete/hooks/use-complete.hook.ts (1)

58-68: ⚡ Quick win

Drop the CTA useMemo unless a consumer needs identity stability.

This is just local render data in the supplied context. With React Compiler enabled, prefer a plain PageCta object here and only memoize at the boundary that actually depends on referential stability.

As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: "React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity."

🤖 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/complete/hooks/use-complete.hook.ts` around lines
58 - 68, The CTA is unnecessarily wrapped in useMemo (const cta =
useMemo<PageCta>(...)) despite being local render state; remove the useMemo and
return a plain PageCta object instead (preserve properties: disabled, isLoading,
label: t("complete.continue", { context: isLedgerLive ? "ledger" : undefined }),
onClick: () => onClickRef.current(), hide: !!activityReviewMatch) so consumers
that do need referential stability can be memoized at their boundary; update any
references to the cta variable to use the plain object and remove useMemo import
if now unused.

Source: Coding guidelines

packages/widget/src/pages-dashboard/position-details/components/position-details-actions.tsx (1)

85-114: ⚡ Quick win

Drop the CTA useMemo unless a consumer needs identity stability.

Here the value is immediately consumed as a render prop for PageCtaButton, so a plain PageCta object is the better fit under the React Compiler rule.

As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: "React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity."

🤖 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-dashboard/position-details/components/position-details-actions.tsx`
around lines 85 - 114, Remove the unnecessary useMemo and replace unstakeCta
with a plain PageCta value computed inline (still returning null when isLoading
is true) since identity stability isn't required by consumers; keep the same
fields (disabled: unstakeDisabled, isLoading: false, label:
t(...getExtendedYieldType(integrationData)), onClick: onUnstakeClick) and the
Maybe.fromRecord mapping logic or its equivalent so PageCtaButton receives
identical props but without wrapping in useMemo.

Source: Coding guidelines

packages/widget/src/pages/review/hooks/use-action-review.hook.ts (1)

146-154: ⚡ Quick win

Drop the CTA useMemo unless a consumer needs identity stability.

Nothing in the supplied context shows a boundary that requires this object to stay referentially stable. Prefer a plain PageCta value and memoize only where identity is actually observed.

As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: "React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity."

🤖 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/review/hooks/use-action-review.hook.ts` around
lines 146 - 154, The CTA object currently created with useMemo (const cta =
useMemo<PageCta>(...)) should be converted to a plain PageCta value since no
consumer requires referential identity; remove the useMemo call and return a
simple object for cta with the same properties (label:
t(`activity.review.${labelKey}`), onClick: () =>
navigate(`/activity/${path}/steps`), disabled: false, isLoading: false, hide:
actionOlderThan7Days), keeping the same referenced symbols (cta, PageCta,
labelKey, navigate, path, actionOlderThan7Days, t) so behavior is unchanged
while complying with the React Compiler guideline against unnecessary useMemo.

Source: Coding guidelines

packages/widget/src/pages/steps/hooks/use-steps.hook.ts (1)

175-186: ⚡ Quick win

Drop the CTA useMemo unless a consumer needs identity stability.

The new CTA is plain derived render state in the supplied code. Prefer returning a normal PageCta value here and reserve manual memoization for an actual identity-sensitive boundary.

As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: "React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity."

🤖 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/steps/hooks/use-steps.hook.ts` around lines 175 -
186, The CTA currently wrapped in useMemo (const cta = useMemo<PageCta>(...))
should be converted to a plain derived value: remove the useMemo import/usage
and return a direct PageCta (or null) based on txStates.length, preserving the
same shape (disabled, isLoading, label: t("shared.cancel"), onClick calling
onClickRef.current(), variant: "secondary") and keeping the PageCta type
annotation; this drops unnecessary identity memoization while retaining
onClickRef, txStates and t usage.

Source: Coding guidelines

packages/widget/src/pages/review/hooks/use-stake-review.hook.ts (1)

198-212: ⚡ Quick win

Prefer a plain CTA object here.

The hook already returns a fresh object on Line 231, so memoizing only cta does not buy semantic stability and just adds dependency bookkeeping. As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity.

🤖 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/review/hooks/use-stake-review.hook.ts` around lines
198 - 212, The cta is unnecessarily wrapped in useMemo; remove the useMemo call
and return a plain PageCta object instead — construct cta as { disabled:
kycGateIsBlocking, isLoading: enterMutation.isPending || yieldKycGate.isLoading,
label: t("shared.confirm"), onClick: () => onClickRef.current() } so you still
reference onClickRef, enterMutation, yieldKycGate, kycGateIsBlocking and t but
avoid memo/dependency bookkeeping; ensure the hook's returned value remains the
fresh object used later.

Source: Coding guidelines

packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx (1)

751-789: ⚡ Quick win

Drop the useMemo around this CTA.

EarnPageContext.Provider still receives a fresh value object below, so memoizing only cta does not provide the semantic stability the compiler guideline allows it for. A plain const cta = ... is simpler here. As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity.

🤖 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 751 - 789, Remove the useMemo wrapper around the cta variable and
replace it with a plain const cta = ... expression so the CTA is computed
directly (keep the same conditional structure and all referenced symbols:
buttonCTAText, buttonDisabled, isConnected, isLedgerLiveAccountPlaceholder,
externalProviders, appLoading, isFetching, yieldKycGate.isLoading, onClickRef,
connectClickRef, registerFooterButton, hasNotYieldsForToken, and t); this aligns
with the React Compiler guideline because EarnPageContext.Provider still creates
a fresh value object and there is no semantic identity requirement that needs
memoization.

Source: Coding guidelines

packages/widget/src/pages/review/hooks/use-unstake-review.hook.ts (1)

159-167: ⚡ Quick win

Prefer a plain CTA object here.

This hook also returns a new object below, so memoizing just cta does not create any semantic-stability guarantee for consumers. As per coding guidelines, packages/widget/src/**/*.{ts,tsx}: React Compiler is enabled. Do not add useMemo, useCallback, or React.memo only for render-performance optimization; prefer plain values/functions. Use manual memoization only when required for semantic stability, such as an external API dependency or context value identity.

🤖 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/review/hooks/use-unstake-review.hook.ts` around
lines 159 - 167, The cta currently uses useMemo (const cta =
useMemo<PageCta>(...)) which is unnecessary and prevents semantic-stability
guarantees because the hook already returns a new object later; replace the
useMemo with a plain PageCta object (const cta: PageCta = { label:
t("shared.confirm"), onClick: () => onClickRef.current(), disabled:
kycGateIsBlocking, isLoading: unstakeIsLoading || yieldKycGate.isLoading }) so
you return a regular value and preserve the same referenced symbols (cta,
PageCta, onClickRef, kycGateIsBlocking, unstakeIsLoading,
yieldKycGate.isLoading) without using useMemo/useCallback.

Source: Coding guidelines

🤖 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/pages/details/earn-page/state/earn-page-context.tsx`:
- Around line 476-480: onTokenBalanceSelect currently always dispatches { type:
"token/select" } which ignores dashboard context and can change
selectedDashboardYieldCategory; instead, read selectedDashboardYieldCategory
from state (or props) and when a dashboard category is active dispatch the
category-aware action (e.g. { type: "dashboard/token/select", data: { token:
tokenBalance.token, category: selectedDashboardYieldCategory } } or the existing
category-aware action your reducer expects) otherwise fall back to dispatching {
type: "token/select", data: tokenBalance.token }; update the
onTokenBalanceSelect useCallback to branch on selectedDashboardYieldCategory and
call the appropriate dispatch so token picks on dashboard flows preserve the
active category.

---

Nitpick comments:
In
`@packages/widget/src/pages-dashboard/position-details/components/position-details-actions.tsx`:
- Around line 85-114: Remove the unnecessary useMemo and replace unstakeCta with
a plain PageCta value computed inline (still returning null when isLoading is
true) since identity stability isn't required by consumers; keep the same fields
(disabled: unstakeDisabled, isLoading: false, label:
t(...getExtendedYieldType(integrationData)), onClick: onUnstakeClick) and the
Maybe.fromRecord mapping logic or its equivalent so PageCtaButton receives
identical props but without wrapping in useMemo.

In `@packages/widget/src/pages/complete/hooks/use-complete.hook.ts`:
- Around line 58-68: The CTA is unnecessarily wrapped in useMemo (const cta =
useMemo<PageCta>(...)) despite being local render state; remove the useMemo and
return a plain PageCta object instead (preserve properties: disabled, isLoading,
label: t("complete.continue", { context: isLedgerLive ? "ledger" : undefined }),
onClick: () => onClickRef.current(), hide: !!activityReviewMatch) so consumers
that do need referential stability can be memoized at their boundary; update any
references to the cta variable to use the plain object and remove useMemo import
if now unused.

In `@packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx`:
- Around line 751-789: Remove the useMemo wrapper around the cta variable and
replace it with a plain const cta = ... expression so the CTA is computed
directly (keep the same conditional structure and all referenced symbols:
buttonCTAText, buttonDisabled, isConnected, isLedgerLiveAccountPlaceholder,
externalProviders, appLoading, isFetching, yieldKycGate.isLoading, onClickRef,
connectClickRef, registerFooterButton, hasNotYieldsForToken, and t); this aligns
with the React Compiler guideline because EarnPageContext.Provider still creates
a fresh value object and there is no semantic identity requirement that needs
memoization.

In `@packages/widget/src/pages/review/hooks/use-action-review.hook.ts`:
- Around line 146-154: The CTA object currently created with useMemo (const cta
= useMemo<PageCta>(...)) should be converted to a plain PageCta value since no
consumer requires referential identity; remove the useMemo call and return a
simple object for cta with the same properties (label:
t(`activity.review.${labelKey}`), onClick: () =>
navigate(`/activity/${path}/steps`), disabled: false, isLoading: false, hide:
actionOlderThan7Days), keeping the same referenced symbols (cta, PageCta,
labelKey, navigate, path, actionOlderThan7Days, t) so behavior is unchanged
while complying with the React Compiler guideline against unnecessary useMemo.

In `@packages/widget/src/pages/review/hooks/use-pending-review.hook.ts`:
- Around line 151-158: The CTA object is unnecessarily wrapped in useMemo;
remove the useMemo wrapper and return a plain PageCta object named cta
constructed from t("shared.confirm"), onClickRef.current, disabled: false, and
isLoading: actionPendingMutation.isPending so its identity is not artificially
memoized; update references to the existing cta variable (created where useMemo
was) and remove useMemo import if now unused.

In `@packages/widget/src/pages/review/hooks/use-stake-review.hook.ts`:
- Around line 198-212: The cta is unnecessarily wrapped in useMemo; remove the
useMemo call and return a plain PageCta object instead — construct cta as {
disabled: kycGateIsBlocking, isLoading: enterMutation.isPending ||
yieldKycGate.isLoading, label: t("shared.confirm"), onClick: () =>
onClickRef.current() } so you still reference onClickRef, enterMutation,
yieldKycGate, kycGateIsBlocking and t but avoid memo/dependency bookkeeping;
ensure the hook's returned value remains the fresh object used later.

In `@packages/widget/src/pages/review/hooks/use-unstake-review.hook.ts`:
- Around line 159-167: The cta currently uses useMemo (const cta =
useMemo<PageCta>(...)) which is unnecessary and prevents semantic-stability
guarantees because the hook already returns a new object later; replace the
useMemo with a plain PageCta object (const cta: PageCta = { label:
t("shared.confirm"), onClick: () => onClickRef.current(), disabled:
kycGateIsBlocking, isLoading: unstakeIsLoading || yieldKycGate.isLoading }) so
you return a regular value and preserve the same referenced symbols (cta,
PageCta, onClickRef, kycGateIsBlocking, unstakeIsLoading,
yieldKycGate.isLoading) without using useMemo/useCallback.

In `@packages/widget/src/pages/steps/hooks/use-steps.hook.ts`:
- Around line 175-186: The CTA currently wrapped in useMemo (const cta =
useMemo<PageCta>(...)) should be converted to a plain derived value: remove the
useMemo import/usage and return a direct PageCta (or null) based on
txStates.length, preserving the same shape (disabled, isLoading, label:
t("shared.cancel"), onClick calling onClickRef.current(), variant: "secondary")
and keeping the PageCta type annotation; this drops unnecessary identity
memoization while retaining onClickRef, txStates and t usage.
🪄 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: 6c685530-9601-45ef-aa14-02bc6b706101

📥 Commits

Reviewing files that changed from the base of the PR and between 2468076 and 3be9f08.

📒 Files selected for processing (37)
  • packages/widget/src/Widget.tsx
  • packages/widget/src/domain/types/yields.ts
  • packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts
  • packages/widget/src/navigation/containers/animation-layout.tsx
  • packages/widget/src/navigation/containers/animation-page.tsx
  • packages/widget/src/pages-dashboard/activity/activity-details.page.tsx
  • packages/widget/src/pages-dashboard/common/components/footer-outlet/index.tsx
  • packages/widget/src/pages-dashboard/common/components/tabs/index.tsx
  • packages/widget/src/pages-dashboard/overview/earn-page/index.tsx
  • packages/widget/src/pages-dashboard/overview/index.tsx
  • packages/widget/src/pages-dashboard/position-details/components/position-details-actions.tsx
  • packages/widget/src/pages-dashboard/position-details/components/position-details-stake-actions.tsx
  • packages/widget/src/pages-dashboard/position-details/index.tsx
  • packages/widget/src/pages/complete/hooks/use-complete.hook.ts
  • packages/widget/src/pages/complete/pages/common.page.tsx
  • packages/widget/src/pages/complete/state/index.tsx
  • packages/widget/src/pages/components/footer-outlet/context.ts
  • packages/widget/src/pages/components/footer-outlet/index.tsx
  • packages/widget/src/pages/components/footer-outlet/styles.css.ts
  • packages/widget/src/pages/components/page-cta.tsx
  • packages/widget/src/pages/details/earn-page/earn.page.tsx
  • packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx
  • packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
  • packages/widget/src/pages/details/earn-page/state/types.ts
  • packages/widget/src/pages/review/hooks/use-action-review.hook.ts
  • packages/widget/src/pages/review/hooks/use-pending-review.hook.ts
  • packages/widget/src/pages/review/hooks/use-stake-review.hook.ts
  • packages/widget/src/pages/review/hooks/use-unstake-review.hook.ts
  • packages/widget/src/pages/review/pages/action-review.page.tsx
  • packages/widget/src/pages/review/pages/common-page/common.page.tsx
  • packages/widget/src/pages/review/pages/pending-review.page.tsx
  • packages/widget/src/pages/review/pages/stake-review.page.tsx
  • packages/widget/src/pages/review/pages/unstake-review.page.tsx
  • packages/widget/src/pages/steps/hooks/use-steps.hook.ts
  • packages/widget/src/pages/steps/pages/common.page.tsx
  • packages/widget/src/providers/index.tsx
  • packages/widget/tests/pages-dashboard/position-details-action-tabs.test.tsx
💤 Files with no reviewable changes (8)
  • packages/widget/src/pages/components/footer-outlet/index.tsx
  • packages/widget/src/Widget.tsx
  • packages/widget/src/pages/components/footer-outlet/context.ts
  • packages/widget/src/pages-dashboard/overview/index.tsx
  • packages/widget/src/pages/components/footer-outlet/styles.css.ts
  • packages/widget/src/pages-dashboard/position-details/index.tsx
  • packages/widget/src/pages-dashboard/common/components/footer-outlet/index.tsx
  • packages/widget/tests/pages-dashboard/position-details-action-tabs.test.tsx

Comment on lines 476 to 480
const onTokenBalanceSelect = useCallback(
async (tokenBalance: TokenBalanceScanResponseDto) => {
const category = dashboardVariant ? selectedDashboardYieldCategory : null;

if (!category) {
dispatch({ type: "token/select", data: tokenBalance.token });
return;
}

const selectionRequestId = dashboardTokenSelectionRequestRef.current + 1;
dashboardTokenSelectionRequestRef.current = selectionRequestId;
dispatch({ type: "token-only/select", data: tokenBalance.token });

const tokenYield = await getDashboardTokenYield({
category,
tokenBalance,
}).catch((error) => {
console.log(error);
return null;
});

if (
selectionRequestId !== dashboardTokenSelectionRequestRef.current ||
!tokenYield
) {
return;
}

selectDashboardTokenYield({
token: tokenBalance.token,
yieldDto: tokenYield.yieldDto,
yieldId: tokenYield.yieldId,
});
},
[
dashboardVariant,
dispatch,
getDashboardTokenYield,
selectedDashboardYieldCategory,
selectDashboardTokenYield,
]
(tokenBalance: TokenBalanceScanResponseDto) =>
dispatch({ type: "token/select", data: tokenBalance.token }),
[dispatch]
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep token picks category-aware on dashboard flows.

This now routes every token click through "token/select". That reducer path recomputes the initial yield from the token alone, so picking a token while the user is on rwa or defi can auto-select a yield from another category and immediately change selectedDashboardYieldCategory to that new yield's category. Route dashboard token picks through the category-aware selection path when a dashboard category is active.

🤖 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 476 - 480, onTokenBalanceSelect currently always dispatches { type:
"token/select" } which ignores dashboard context and can change
selectedDashboardYieldCategory; instead, read selectedDashboardYieldCategory
from state (or props) and when a dashboard category is active dispatch the
category-aware action (e.g. { type: "dashboard/token/select", data: { token:
tokenBalance.token, category: selectedDashboardYieldCategory } } or the existing
category-aware action your reducer expects) otherwise fall back to dispatching {
type: "token/select", data: tokenBalance.token }; update the
onTokenBalanceSelect useCallback to branch on selectedDashboardYieldCategory and
call the appropriate dispatch so token picks on dashboard flows preserve the
active category.

Move stake initialization into the earn page reducer.
Skip catalog probes while wallet connection is pending.
@petar-omni petar-omni force-pushed the refactor-page-cta-flow branch from 3be9f08 to 5f2d2d1 Compare June 9, 2026 22:02

@raiseerco raiseerco left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments!

selectedDashboardYieldCategory,
selectDashboardTokenYield,
]
(tokenBalance: TokenBalanceScanResponseDto) =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possible dashboard regression? token selection no longer preserves the active category and can fall back to a yield from a different tab

@@ -684,12 +491,14 @@ export const EarnPageContextProvider = ({
setSelectedDashboardYieldCategoryFallback(category);

const target =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here: switching back to a category now restores its initial seed instead of the last token/yield previously selected in that tab

Move dashboard yield category into earn page reducer state and filter
first-eligible-yield by category when initializing stakes. Remove unused
token-list-yields helpers and fetchAllYieldSummaries pagination.
ProviderIcon used providerIcon for the main image and mainUrl for the
network badge. Use mainUrl for the token logo and providerIcon for the
badge when present. Add min-width on earn-page via provider images to
prevent layout overflow.
Show pricePerShareState.price in earn and position detail rows when the
yield provides it. Rename cooldown copy to redemption time in EN and FR.
Some yields expose reward metadata through outputToken rather than
rewardRate components. Include it so reward badges and meta info
render correctly for those yields.
Philippoes
Philippoes previously approved these changes Jun 10, 2026
Use "Minimum subscription" instead of "Min stake" for RWA yields in
earn and position details. Stretch the earn details panel to fill
available height so long detail lists scroll within the panel.
The stake/enter confirmation screen showed an "Estimated rewards"
heading with no yearly or monthly values. Reuse the shared earn-page
reward amounts on review so users see the same projections before
confirming.
Use absolute positioning for the earn details scroll container so content
scrolls independently of the page footer CTA. Remove redundant bottom
margins from PageContainer and PageCtaButton.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx (1)

120-154: ⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Dashboard category selection always resets to the catalog's initial seed.

When the user switches dashboard categories (line 121-123), the reducer uses dashboardYieldCatalog.initialSelectionByCategory.get(action.data) to pick the token and yield. This means switching back to a category always restores the catalog's initial seed for that category, not the user's last selection within that category.

For example:

  1. User is on "rwa" tab, selects tokenA → yieldX
  2. User switches to "defi" tab
  3. User switches back to "rwa" tab → resets to the catalog seed, losing tokenA/yieldX selection

If you want to preserve per-category selections across tab switches, consider tracking lastSelectionByCategory in state and using that instead of the catalog seed.

🤖 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-state-context.tsx`
around lines 120 - 154, The reducer currently always uses
dashboardYieldCatalog.initialSelectionByCategory.get(action.data) which forces
the catalog seed on category switches; modify the logic in the
"dashboard/yield-category/select" case to first look up a per-category last
selection stored in state (e.g. state.lastSelectionByCategory.get(action.data))
and fall back to dashboardYieldCatalog.initialSelectionByCategory only if no
last selection exists, and ensure you add/initialize a lastSelectionByCategory
Map in the state shape and update it whenever onYieldSelectState (or wherever
selections change) is called so selections are persisted per category instead of
resetting to the catalog seed; keep the existing equality checks (selectedToken,
selectedStakeId) and use Maybe semantic as before.
🧹 Nitpick comments (1)
packages/widget/src/pages/review/pages/common-page/components/review-top-section.tsx (1)

82-89: 💤 Low value

Consider using .alt() instead of ?? for Maybe fallback.

The prop estimatedRewardAmounts is typed as Maybe<{...}>, so when it's Maybe.empty() the ?? Maybe.empty() fallback will never trigger (since Maybe.empty() is truthy). For idiomatic purify-ts usage, use .alt(Maybe.empty()) or rely on the optional prop:

-            {(estimatedRewardAmounts ?? Maybe.empty())
+            {estimatedRewardAmounts
               .map((amounts) => (
🤖 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/review/pages/common-page/components/review-top-section.tsx`
around lines 82 - 89, The code uses a truthy JavaScript nullish fallback
(estimatedRewardAmounts ?? Maybe.empty()) which never runs because Maybe.empty()
is truthy; replace that expression with the purify-ts alternative operator so
the Maybe fallback works — e.g. use estimatedRewardAmounts.alt(Maybe.empty()).
Leave the subsequent .map(...) and .extractNullable() calls unchanged so the
mapping and extraction on the Maybe returned by .alt() behave correctly.
🤖 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/pages/details/earn-page/state/earn-page-state-context.tsx`:
- Around line 87-116: The token/select reducer currently recomputes
selectedDashboardYieldCategory from the returned yieldDto (via
getDashboardYieldCategory) which allows token selection to change the active
dashboard tab; to fix, stop overwriting the current category or ensure yields
are pre-filtered by it: either (A) keep selectedDashboardYieldCategory:
state.selectedDashboardYieldCategory in the .map that builds State so the
existing dashboard tab is preserved, or (B) modify the getInitYield flow to
filter eligible yields by state.selectedDashboardYieldCategory before
auto-selecting a yield (so getInitYield/onYieldSelectState return a yieldDto
that already respects the dashboard category). Reference symbols: token/select
reducer, getInitYield, getDashboardYieldCategory, onYieldSelectState,
state.selectedDashboardYieldCategory.

---

Outside diff comments:
In
`@packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx`:
- Around line 120-154: The reducer currently always uses
dashboardYieldCatalog.initialSelectionByCategory.get(action.data) which forces
the catalog seed on category switches; modify the logic in the
"dashboard/yield-category/select" case to first look up a per-category last
selection stored in state (e.g. state.lastSelectionByCategory.get(action.data))
and fall back to dashboardYieldCatalog.initialSelectionByCategory only if no
last selection exists, and ensure you add/initialize a lastSelectionByCategory
Map in the state shape and update it whenever onYieldSelectState (or wherever
selections change) is called so selections are persisted per category instead of
resetting to the catalog seed; keep the existing equality checks (selectedToken,
selectedStakeId) and use Maybe semantic as before.

---

Nitpick comments:
In
`@packages/widget/src/pages/review/pages/common-page/components/review-top-section.tsx`:
- Around line 82-89: The code uses a truthy JavaScript nullish fallback
(estimatedRewardAmounts ?? Maybe.empty()) which never runs because Maybe.empty()
is truthy; replace that expression with the purify-ts alternative operator so
the Maybe fallback works — e.g. use estimatedRewardAmounts.alt(Maybe.empty()).
Leave the subsequent .map(...) and .extractNullable() calls unchanged so the
mapping and extraction on the Maybe returned by .alt() behave correctly.
🪄 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: 168f6923-a830-4b23-a737-e7396a0eaea1

📥 Commits

Reviewing files that changed from the base of the PR and between 5f2d2d1 and 6be5b4b.

📒 Files selected for processing (31)
  • packages/widget/src/components/atoms/token-icon/provider-icon/index.tsx
  • packages/widget/src/components/molecules/estimated-reward-amounts/index.tsx
  • packages/widget/src/domain/types/yields.ts
  • packages/widget/src/hooks/api/use-multi-yields.ts
  • packages/widget/src/hooks/api/use-token-list-yields.ts
  • packages/widget/src/hooks/api/use-yield-summaries.ts
  • packages/widget/src/pages-dashboard/overview/earn-details/earn-details-formatters.ts
  • packages/widget/src/pages-dashboard/overview/earn-details/earn-details-model.tsx
  • packages/widget/src/pages-dashboard/overview/earn-details/styles.css.ts
  • packages/widget/src/pages-dashboard/position-details/position-details-model.tsx
  • packages/widget/src/pages/components/page-container.tsx
  • packages/widget/src/pages/components/page-cta.tsx
  • packages/widget/src/pages/details/activity-page/hooks/use-activity-filters.ts
  • packages/widget/src/pages/details/earn-page/components/select-yield-section/select-yield-reward-details.tsx
  • packages/widget/src/pages/details/earn-page/components/select-yield-section/styles.css.ts
  • packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx
  • packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
  • packages/widget/src/pages/details/earn-page/state/types.ts
  • packages/widget/src/pages/details/earn-page/state/use-get-init-yield.ts
  • packages/widget/src/pages/details/earn-page/state/use-init-yield.ts
  • packages/widget/src/pages/review/hooks/use-stake-review.hook.ts
  • packages/widget/src/pages/review/pages/common-page/common.page.tsx
  • packages/widget/src/pages/review/pages/common-page/components/review-top-section.tsx
  • packages/widget/src/pages/review/pages/stake-review.page.tsx
  • packages/widget/src/translation/English/translations.json
  • packages/widget/src/translation/French/translations.json
  • packages/widget/tests/domain/token-list-yields.test.ts
  • packages/widget/tests/domain/yield-summaries.test.ts
  • packages/widget/tests/pages-dashboard/earn-details-model.test.tsx
  • packages/widget/tests/pages-dashboard/position-details-model.test.tsx
  • packages/widget/tests/use-cases/staking-flow/staking-flow.test.tsx
💤 Files with no reviewable changes (5)
  • packages/widget/src/pages/components/page-container.tsx
  • packages/widget/src/hooks/api/use-token-list-yields.ts
  • packages/widget/tests/domain/token-list-yields.test.ts
  • packages/widget/tests/domain/yield-summaries.test.ts
  • packages/widget/src/hooks/api/use-yield-summaries.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/widget/tests/use-cases/staking-flow/staking-flow.test.tsx
  • packages/widget/src/translation/French/translations.json
  • packages/widget/src/translation/English/translations.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/widget/src/pages/review/pages/stake-review.page.tsx
  • packages/widget/src/pages/components/page-cta.tsx
  • packages/widget/src/pages/review/hooks/use-stake-review.hook.ts
  • packages/widget/src/pages/review/pages/common-page/common.page.tsx
  • packages/widget/src/pages/details/earn-page/state/types.ts

@petar-omni petar-omni force-pushed the refactor-page-cta-flow branch from 6be5b4b to 1f77fe2 Compare June 10, 2026 09:42
Activity filter pills were hidden unless loaded actions spanned two or more
dashboard categories. Show All plus the matching category filters whenever at
least one categorized activity is loaded.
@petar-omni petar-omni force-pushed the refactor-page-cta-flow branch from 1f77fe2 to ef989a3 Compare June 10, 2026 09:45
@petar-omni petar-omni requested a review from Philippoes June 10, 2026 09:55

@xhakti xhakti left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dnehl dnehl left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing else spotted.

@petar-omni petar-omni merged commit a75057b into main Jun 10, 2026
8 checks passed
@petar-omni petar-omni deleted the refactor-page-cta-flow branch June 10, 2026 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants