Skip to content

fix: category selection #532

Open
petar-omni wants to merge 3 commits into
mainfrom
refactor-page-cta-flow
Open

fix: category selection #532
petar-omni wants to merge 3 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 CTA handling from a shared animated footer into page-level CTAs rendered throughout the app for clearer, consistent actions.
    • Removed footer-outlet providers and internal footer registration logic.
    • Simplified dashboard/animation layout sizing to exclude footer height.
  • New Features

    • Added a reusable Page CTA component and API for pages to surface actions inline.
  • Other

    • Reordered yield categories to: RWA, DeFi, Stake.

@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5f2d2d1

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: 0dec35f9-acad-4443-96c0-cce5778cb98d

📥 Commits

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

📒 Files selected for processing (6)
  • packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts
  • packages/widget/src/pages-dashboard/position-details/components/position-details-stake-actions.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/tests/pages-dashboard/position-details-action-tabs.test.tsx
  • packages/widget/tests/use-cases/select-opportunity.test.tsx
💤 Files with no reviewable changes (1)
  • packages/widget/tests/pages-dashboard/position-details-action-tabs.test.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
  • packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts
  • packages/widget/src/pages-dashboard/position-details/components/position-details-stake-actions.tsx

📝 Walkthrough

Walkthrough

This PR removes the footer-outlet registration system and replaces it with a PageCta type and PageCtaButton; CTA objects are returned from hooks and contexts and rendered directly by pages. Earn-page selection/state and position-details initialization were refactored to align with the new CTA flow.

Changes

Footer Outlet Removal and PageCta Integration

Layer / File(s) Summary
Remove footer-outlet infrastructure
packages/widget/src/pages/components/footer-outlet/*, packages/widget/src/pages-dashboard/overview/index.tsx, packages/widget/src/pages-dashboard/position-details/index.tsx, packages/widget/src/Widget.tsx
Delete footer-outlet context, component, and styles; remove FooterOutlet imports/renders; remove AnimatedFooterContent import/render from Widget.
Introduce PageCta type and PageCtaButton component
packages/widget/src/pages/components/page-cta.tsx
Add new PageCta type and PageCtaButton component that conditionally renders a footer-styled button wired to CTA state.
Update provider tree to remove footer contexts
packages/widget/src/providers/index.tsx
Remove FooterHeightProvider and FooterButtonProvider from Providers; nest content directly under HeaderHeightProvider.
Refactor complete and pending review hooks to return CTA
packages/widget/src/pages/complete/hooks/use-complete.hook.ts, packages/widget/src/pages/review/hooks/use-pending-review.hook.ts
Hooks now construct and return memoized PageCta objects instead of calling useRegisterFooterButton.
Refactor review action/stake/unstake hooks to return CTA
packages/widget/src/pages/review/hooks/*
useActionReview, useStakeReview, useUnstakeActionReview now build and return cta: PageCta instead of registering footer buttons.
Refactor useSteps hook to return CTA
packages/widget/src/pages/steps/hooks/use-steps.hook.ts
useSteps now returns a cta for the cancel action rather than registering a footer button.
Update complete page components to render PageCtaButton
packages/widget/src/pages/complete/state/index.tsx, packages/widget/src/pages/complete/pages/common.page.tsx, packages/widget/src/pages-dashboard/activity/activity-details.page.tsx
Add cta to complete context type and render PageCtaButton in complete pages.
Update review page components to render PageCtaButton
packages/widget/src/pages/review/pages/*
ReviewPage props include cta: PageCta; review pages obtain cta from hooks/context and render PageCtaButton.
Update StepsPage to render PageCtaButton
packages/widget/src/pages/steps/pages/common.page.tsx
Extract cta from useSteps and render PageCtaButton.
Update earn page state types for CTA and new action
packages/widget/src/pages/details/earn-page/state/types.ts
Add PageCta import; extend EarnPageContextType with cta; add PositionDetailsStakeInitializeAction and include it in Actions.
Add positionDetails/stake/initialize action handler to reducer
packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx
Reducer now handles positionDetails/stake/initialize, conditionally re-initializing state when token or stake id differs.
Refactor EarnPageContextProvider to simplify selection and add CTA
packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx
Remove async select-dashboard logic; simplify token/category selection dispatches; compute cta via useMemo and include in provider value; stop passing network: null.
Update earn page components to render PageCtaButton
packages/widget/src/pages-dashboard/overview/earn-page/index.tsx, packages/widget/src/pages/details/earn-page/earn.page.tsx
Extract cta from useEarnPageContext and render PageCtaButton.
Refactor position details actions to use PageCtaButton
packages/widget/src/pages-dashboard/position-details/components/*
Construct PageCta objects instead of registering footer buttons; render PageCtaButton; dispatch positionDetails/stake/initialize where appropriate.
Supporting updates
packages/widget/src/hooks/api/use-dashboard-yield-catalog.ts, packages/widget/src/domain/types/yields.ts, packages/widget/src/navigation/containers/animation-page.tsx, packages/widget/src/navigation/containers/animation-layout.tsx, packages/widget/src/pages-dashboard/common/components/tabs/index.tsx
Narrow useDashboardYieldCatalog props (remove network param); reorder dashboardYieldCategories; add dashboardLayoutStyle to AnimationPage; remove footerHeight from AnimationLayout height calculation; treat /positions as manage tab.
Remove obsolete test and adjust MSW mock
packages/widget/tests/pages-dashboard/position-details-action-tabs.test.tsx, packages/widget/tests/use-cases/select-opportunity.test.tsx
Delete unit test for initialization helper; shorten MSW enabled-networks response in select-opportunity tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Philippoes
  • 0xYoki
  • dnehl

Poem

🐇 I hopped through hooks and pages bright,

Swapped footer traps 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, failing to provide any context about the changes, objectives, or impact of the substantial refactoring work. Add a detailed description covering the main changes (footer outlet removal, CTA component migration, state management updates) and the rationale for this refactoring.
Title check ❓ Inconclusive The title 'fix: category selection' is vague and does not clearly convey the main scope of changes, which involve a comprehensive refactoring of CTA (call-to-action) flow from footer outlets to page-level components. Consider using a more descriptive title that captures the primary refactoring effort, such as 'refactor: migrate CTA flow from footer outlets to page components' or 'refactor: consolidate page CTA handling'
✅ 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

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.

2 participants