Skip to content

Conversation

@premiumjibles
Copy link
Collaborator

@premiumjibles premiumjibles commented Aug 22, 2025

Description

Polish the action card flow for swaps where it moves from Awaiting Approval -> Awaiting Swap -> Pending -> Complete/Failed.

Removes the dedicated approval action card as that's incorporated in the one card.

Issue (if applicable)

closes #10351

Risk

Low-medium risk, only affects the action cards for swaps

High Risk PRs Require 2 approvals

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Test swaps on both native and non-native wallets

  • Test swaps that require and don't require approvals

  • Test swaps that require permit

  • Test bailing out of a swap before executing/approving. Card should stay but starting a new swap should wipe it out.

  • All swaps should be successful but should show the additional statuses of "awaiting approval" (if required) and "awaiting swap". No dedicated approval card should show but you should be able to see approval tx by expanding card as soon as approval is done

Engineering

☝️

Operations

☝️

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

https://jam.dev/c/f3987d13-b268-449a-8592-46df1b6eb330

Summary by CodeRabbit

  • New Features

    • Action Center adds “Awaiting Approval” and “Awaiting Swap” statuses with orange icons/tags and localized messages.
    • Swap cards show clearer titles for approval/execution phases and collapse when an approval or swap transaction exists.
    • Broader, automatic syncing keeps swap actions up to date across all swaps for more accurate status display.
  • Bug Fixes

    • Prevents idle/non-active swaps from showing “Awaiting” states.
    • Streamlines allowance approval flow to reduce noisy, redundant notifications.

@premiumjibles premiumjibles requested a review from a team as a code owner August 22, 2025 23:36
@premiumjibles premiumjibles marked this pull request as draft August 22, 2025 23:36
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 22, 2025

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

📥 Commits

Reviewing files that changed from the base of the PR and between b36ec7a and 12083d3.

📒 Files selected for processing (3)
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx (4 hunks)
  • src/state/slices/actionSlice/selectors.ts (1 hunks)
  • src/state/slices/actionSlice/types.ts (1 hunks)
 _________________________________________________________________
< You know what they call CodeRabbit in Paris? Royale with Debug. >
 -----------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
📝 Walkthrough

Walkthrough

Adds AwaitingApproval/AwaitingSwap statuses across types, icons, tags, translations, and SwapActionCard titles. Refactors useSwapActionSubscriber to sync swap actions for all swaps from confirmedTradeExecution, upserting/updating status and approval metadata. Simplifies useAllowanceApproval by removing Action Center/toast side effects, recording txHash and completion only. Broadens SwapActionCard collapsibility.

Changes

Cohort / File(s) Summary
I18n: new status keys
src/assets/translations/en/main.json
Adds actionCenter.status.awaitingApproval/awaitingSwap and actionCenter.swap.awaitingApproval/awaitingSwap strings.
Action status UI (icon/tag)
src/components/.../ActionCenter/components/ActionStatusIcon.tsx, src/components/.../ActionCenter/components/ActionStatusTag.tsx
Maps AwaitingApproval/AwaitingSwap to orange icon/tag; uses new translation keys.
Swap card UX
src/components/.../ActionCenter/components/SwapActionCard.tsx, src/components/.../ActionCenter/ActionCenter.tsx
Titles for AwaitingApproval/AwaitingSwap; isCollapsable true if swap txLink or allowanceApproval txHash exists.
Subscriber refactor
src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
Derives ActionStatus via mapping (incl. ArbitrumBridge case), iterates all swaps, upserts/updates actions, sources approval metadata from confirmedTradeExecution, removes action param from swapStatusHandler path.
Action types
src/state/slices/actionSlice/types.ts
Adds ActionStatus.AwaitingApproval and ActionStatus.AwaitingSwap.
Allowance approval hook
src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
Removes Action Center/toast UI side effects; on success sets txHash, awaits receipt, marks approval complete; keeps error toast; updates imports.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant TC as TradeConfirm (useAllowanceApproval)
  participant BC as Blockchain
  participant ST as Store (Redux)
  participant SUB as useSwapActionSubscriber
  participant UI as Action Center UI

  U->>TC: Initiate swap
  alt Approval required
    TC->>BC: Submit allowance tx
    TC->>ST: setAllowanceApprovalTxPending
    BC-->>TC: txHash
    TC->>ST: setAllowanceApprovalTxHash
    TC->>BC: wait for receipt
    BC-->>TC: receipt
    TC->>ST: setAllowanceApprovalTxComplete
  end

  loop Poll/sync
    SUB->>ST: read swaps + confirmedTradeExecution
    SUB->>SUB: Map to ActionStatus (AwaitingApproval / AwaitingSwap / Pending / ...)
    SUB->>ST: Upsert/update SwapAction with status + approval metadata
  end

  ST-->>UI: Action updates
  UI-->>U: Show status tag/icon and title
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
Remove dedicated approval card; show approval via swap action card [#10351]
Swap action card stages: Awaiting approval → Awaiting swap → Pending → Failed/Complete [#10351]
Create/show swap card earlier with approval tx link [#10351]
If user bails in awaiting stages and begins new swap, set previous card to Idle [#10351] Idle fallback mentioned in issue; code adds new statuses and sync, but explicit Idle reset on new swap isn’t evident.

Assessment against linked issues: Out-of-scope changes

  • None found.

Possibly related PRs

Suggested reviewers

  • gomesalexandre
  • NeOMakinG

Poem

A rabbit taps code with a gentle hop,
Two new states in the carrot shop. 🥕
Awaiting nod, awaiting swap—
Cards now bloom before they pop.
Toasts go quiet, flows align;
Actions sync in perfect time.
Thump-thump—deploy. All fine.

Tip

CodeRabbit can use your project's `biome` configuration to improve the quality of JS/TS/CSS/JSON code reviews.

Add a configuration file to your project to customize how CodeRabbit runs biome.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10209_swap_action_approvals

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@premiumjibles premiumjibles force-pushed the 10209_swap_action_approvals branch 3 times, most recently from 123c678 to a78597d Compare August 26, 2025 01:36
@premiumjibles premiumjibles force-pushed the 10209_swap_action_approvals branch 3 times, most recently from fd5f66f to 993cddd Compare August 26, 2025 02:50
@premiumjibles premiumjibles marked this pull request as ready for review August 26, 2025 02:58
@premiumjibles premiumjibles force-pushed the 10209_swap_action_approvals branch from 993cddd to b36ec7a Compare August 26, 2025 02:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx (1)

45-45: Fix: Possible crash when swap is undefined

swap.swapperName is dereferenced without a null check, while swap can be undefined (computed from store and used with optional chaining elsewhere). This will throw on initial renders or transient states.

Apply one of these diffs (keeping useMemo is preferred per our hooks guidelines):

-  const isArbitrumBridge = useMemo(() => swap.swapperName === SwapperName.ArbitrumBridge, [swap])
+  const isArbitrumBridge = useMemo(
+    () => swap?.swapperName === SwapperName.ArbitrumBridge,
+    [swap?.swapperName],
+  )

Alternatively (if you relax the memo requirement):

-  const isArbitrumBridge = useMemo(() => swap.swapperName === SwapperName.ArbitrumBridge, [swap])
+  const isArbitrumBridge = swap?.swapperName === SwapperName.ArbitrumBridge
🧹 Nitpick comments (4)
src/assets/translations/en/main.json (1)

3067-3069: Add a “swap.initiated” message to match Initiated status (used for Arbitrum bridge special-case).

SwapActionCard may need a description string for Initiated. Add a key for consistency with other statuses.

Apply this diff near the existing swap messages:

   "swap": {
     "processing": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} is being processed.",
     "complete": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} is complete.",
     "failed": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} has failed.",
+    "initiated": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} has been initiated.",
     "streaming": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} is streaming.",
     "awaitingApproval": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} is awaiting approval.",
     "awaitingSwap": "Your swap of %{sellAmountAndSymbol} to %{buyAmountAndSymbol} is awaiting execution."
   },
src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (1)

97-117: Guard viem receipt wait with try/catch and mark failure on errors/timeouts.

If waitForTransactionReceipt throws, we’ll have set the txHash but never mark the step failed, leaving UI stuck. Wrap in try/catch and dispatch failure + toast on error; optionally add a timeout to avoid indefinite waits.

Apply this diff:

-      const publicClient = assertGetViemClient(tradeQuoteStep.sellAsset.chainId)
-      await publicClient.waitForTransactionReceipt({ hash: txHash as Hash })
-
-      dispatch(
-        tradeQuoteSlice.actions.setAllowanceApprovalTxComplete({
-          hopIndex,
-          id: confirmedTradeId,
-        }),
-      )
+      try {
+        const publicClient = assertGetViemClient(tradeQuoteStep.sellAsset.chainId)
+        await publicClient.waitForTransactionReceipt({
+          hash: txHash as Hash,
+          // consider: confirmations: 1, timeout: 300000
+        })
+        dispatch(
+          tradeQuoteSlice.actions.setAllowanceApprovalTxComplete({
+            hopIndex,
+            id: confirmedTradeId,
+          }),
+        )
+      } catch (e) {
+        dispatch(
+          tradeQuoteSlice.actions.setAllowanceApprovalTxFailed({
+            hopIndex,
+            id: confirmedTradeId,
+          }),
+        )
+        showErrorToast(e)
+      }
src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx (1)

121-182: Sync effect is correct; consider a light optimization to avoid unnecessary upserts.

Current logic only upserts when status changes — good. If allowanceApproval metadata changes without a status change, we won’t update the action. If you want the txHash to surface immediately in the card (e.g., collapsible state), also upsert when allowanceApproval.txHash transitions from undefined → defined.

Example tweak inside the else-if branch:

-      } else if (isSwapAction(existingAction) && existingAction.status !== targetStatus) {
+      } else if (
+        isSwapAction(existingAction) &&
+        (existingAction.status !== targetStatus ||
+          existingAction.swapMetadata.allowanceApproval?.txHash !== approvalMetadata?.txHash)
+      ) {
src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx (1)

48-50: Consider auto-opening for actionable Awaiting states*

Opening only on Pending might hide the actionable “Awaiting Approval/Swap” steps by default. Consider expanding for these statuses to reduce friction.

Example:

   const { isOpen, onToggle } = useDisclosure({
-    defaultIsOpen:
-      action.status === ActionStatus.Pending && Boolean(swap?.isStreaming || swap?.txLink),
+    defaultIsOpen:
+      [ActionStatus.Pending, ActionStatus.AwaitingApproval, ActionStatus.AwaitingSwap].includes(
+        action.status,
+      ) &&
+      Boolean(
+        swap?.isStreaming ||
+          swap?.txLink ||
+          action.swapMetadata?.allowanceApproval?.txHash,
+      ),
   })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 71cb99c and b36ec7a.

📒 Files selected for processing (8)
  • src/assets/translations/en/main.json (2 hunks)
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx (1 hunks)
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx (1 hunks)
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx (1 hunks)
  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx (1 hunks)
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (1 hunks)
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx (4 hunks)
  • src/state/slices/actionSlice/types.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern

**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...

Files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/state/slices/actionSlice/types.ts
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.tsx: ALWAYS wrap components in error boundaries
ALWAYS provide user-friendly fallback components in error boundaries
ALWAYS log errors for debugging in error boundaries
ALWAYS use useErrorToast hook for displaying errors
ALWAYS provide translated error messages in error toasts
ALWAYS handle different error types appropriately in error toasts
Missing error boundaries in React components is an anti-pattern

**/*.tsx: ALWAYS use PascalCase for React component names
ALWAYS use descriptive names that indicate the component's purpose
ALWAYS match the component name to the file name
Flag components without PascalCase
Flag default exports for components

Files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case

Files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/state/slices/actionSlice/types.ts
  • src/assets/translations/en/main.json
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{tsx,jsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary
ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components
NEVER use default exports for components
KEEP component files under 200 lines when possible
BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
USE local state for component-level state
LIFT state up when needed across multiple components
USE Context for avoiding prop drilling
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly
ALWAYS provide user-friendly error messages
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components
ALWAYS use React.lazy for code splitting
Components receiving props are wrapped with memo

Files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

USE Redux only for global state shared across multiple places

Files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
  • src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/state/slices/actionSlice/types.ts
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/use*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/use*.{ts,tsx}: ALWAYS use use prefix for custom hooks
ALWAYS use descriptive names that indicate the hook's purpose
ALWAYS use camelCase after the use prefix for custom hooks

Files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
🧠 Learnings (15)
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Avoid side effects in swap logic within swapper implementation files.

Applied to files:

  • src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx
  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-08T14:59:40.422Z
Learnt from: NeOMakinG
PR: shapeshift/web#10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.

Applied to files:

  • src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx
📚 Learning: 2025-08-22T12:59:01.210Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.

Applied to files:

  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
📚 Learning: 2025-08-22T12:58:26.590Z
Learnt from: NeOMakinG
PR: shapeshift/web#10323
File: src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx:108-111
Timestamp: 2025-08-22T12:58:26.590Z
Learning: In the RFOX GenericTransactionDisplayType flow in src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx, the txHash is always guaranteed to be present according to NeOMakinG, so defensive null checks for txLink are not needed in this context.

Applied to files:

  • src/components/Layout/Header/ActionCenter/ActionCenter.tsx
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Leverage shared utilities (e.g., executeEvmTransaction, checkEvmSwapStatus) in swapper implementations when applicable.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-22T15:07:18.021Z
Learnt from: kaladinlight
PR: shapeshift/web#10326
File: src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx:37-41
Timestamp: 2025-08-22T15:07:18.021Z
Learning: In src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx, kaladinlight prefers not to await the upsertBasePortfolio call in the Base chain handling block, indicating intentional fire-and-forget behavior for Base portfolio upserts in the THORChain LP completion flow.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/src/swappers/*/{*.ts,endpoints.ts} : Include comments explaining swap logic in swapper implementation files.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-03T22:09:37.542Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-08-03T22:09:37.542Z
Learning: Applies to **/swapper/**/*.{ts,tsx} : ALWAYS use TradeQuoteError enum for error codes in swapper errors

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-07-24T09:43:11.699Z
Learnt from: CR
PR: shapeshift/web#0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-07-24T09:43:11.699Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) in all swapper-related files.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-04T15:36:25.122Z
Learnt from: NeOMakinG
PR: shapeshift/web#10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T15:36:25.122Z
Learning: In swap transaction handling, buy transaction hashes should always use the swapper's explorer (stepSource) because they are known by the swapper immediately upon swap execution. The conditional logic for using default explorers applies primarily to sell transactions which need to be detected/indexed by external systems like Thorchain or ViewBlock.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
PR: shapeshift/web#10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
📚 Learning: 2025-08-08T11:40:55.734Z
Learnt from: NeOMakinG
PR: shapeshift/web#10234
File: src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx:41-41
Timestamp: 2025-08-08T11:40:55.734Z
Learning: In MultiHopTrade confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx and related hooks), there is only one active trade per flow. Because of this, persistent (module/Redux) dedupe for QuotesReceived in useTrackTradeQuotes is not necessary; the existing ref-based dedupe is acceptable.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-07-29T15:04:28.083Z
Learnt from: NeOMakinG
PR: shapeshift/web#10139
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx:109-115
Timestamp: 2025-07-29T15:04:28.083Z
Learning: In src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx, the component is used under an umbrella that 100% of the time contains the quote, making the type assertion `activeTradeQuote?.steps[currentHopIndex] as TradeQuoteStep` safe. Adding conditional returns before hooks would violate React's Rules of Hooks.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
PR: shapeshift/web#10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-11T09:46:41.060Z
Learnt from: gomesalexandre
PR: shapeshift/web#10219
File: src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx:167-172
Timestamp: 2025-08-11T09:46:41.060Z
Learning: In the shapeshift/web repository, the display cache logic for trade quotes (using `selectUserAvailableTradeQuotes` and `selectUserUnavailableTradeQuotes`) is intentionally kept the same between `TradeInput.tsx` and `TradeQuotes.tsx` components. The `hasQuotes` computation in `TradeInput.tsx` uses these display cache selectors by design, matching the pattern used in `TradeQuotes.tsx`.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
🧬 Code graph analysis (1)
src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx (7)
packages/swapper/src/types.ts (1)
  • Swap (384-407)
packages/caip/src/constants.ts (1)
  • ethChainId (60-60)
src/state/store.ts (2)
  • useAppSelector (143-143)
  • store (137-137)
src/state/slices/tradeQuoteSlice/selectors.ts (1)
  • selectConfirmedTradeExecution (540-547)
src/state/slices/actionSlice/selectors.ts (1)
  • selectSwapActionBySwapId (123-137)
src/state/slices/actionSlice/actionSlice.ts (1)
  • actionSlice (11-39)
src/state/slices/actionSlice/types.ts (1)
  • isSwapAction (168-172)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Call / Static
🔇 Additional comments (13)
src/state/slices/actionSlice/types.ts (1)

30-31: All clear: downstream selectors use strict status === ActionStatus.Pending checks, so the new AwaitingApproval and AwaitingSwap values won’t be counted. No changes needed.

src/assets/translations/en/main.json (1)

3052-3055: Status translations added — consistent with new enum values.

Keys and casing match ActionStatus. No issues.

src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (1)

8-9: Type-only import split is fine.

Import changes are correct and keep types tree-shakeable. No issues.

src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx (4)

46-51: Direct mapping table is clear and aligns with enum semantics.

The SwapStatus → ActionStatus mapping is straightforward and maintainable.


399-410: Polling queries limited to Pending swaps — matches desired flow.

Query keys include swap id and sellTxHash, and enabled gating prevents unnecessary polling for Awaiting* states. Looks good.


53-88: Initiated state handling confirmed; no further UI updates required

Verified explicit handling for ActionStatus.Initiated in:

  • SwapActionCard.tsx (returns actionCenter.bridge.initiated)
  • SwapNotification.tsx (returns actionCenter.bridge.initiated)
  • ActionStatusTag.tsx (renders a tag for ActionStatus.Initiated)
  • ActionStatusIcon.tsx (includes a case for ActionStatus.Initiated)
  • en/main.json translations (maps "initiated": "Initiated")

All concerns around UI coverage for the Initiated state are addressed.


184-185: No external swapStatusHandler callers found—safe to proceed

I’ve searched the entire repo and confirmed that swapStatusHandler is only declared and used within useSwapActionSubscriber.tsx (at lines 183, 408, and 414). There are no other invocations elsewhere, so no additional call sites need updating.

src/components/Layout/Header/ActionCenter/ActionCenter.tsx (1)

79-81: Collapsibility now considers allowance approval txHash — good UX improvement.

This makes the card collapsible as soon as the approval hash exists, even before the swap txLink is known.

src/components/Layout/Header/ActionCenter/components/ActionStatusIcon.tsx (1)

53-59: LGTM: Awaiting statuses render with an orange GenericTx icon*

The visual treatment and grouping of both statuses are consistent with the rest of the switch and with ActionStatusTag.

src/components/Layout/Header/ActionCenter/components/SwapActionCard.tsx (3)

122-126: Guard against undefined components prop

swapNotificationTranslationComponents returns undefined when swap is falsy. Most translation components handle this, but confirm the implementation tolerates components={undefined}. If not, default to {}.

You can make this change proactively:

-  const description = useMemo(() => {
-    return (
-      <Text fontSize='sm' translation={title} components={swapNotificationTranslationComponents} />
-    )
-  }, [title, swapNotificationTranslationComponents])
+  const description = useMemo(() => {
+    return (
+      <Text
+        fontSize='sm'
+        translation={title}
+        components={swapNotificationTranslationComponents ?? {}}
+      />
+    )
+  }, [title, swapNotificationTranslationComponents])

144-156: Confirm error boundary coverage at the Action Center level

Per our TSX guidelines, components should be wrapped by an error boundary in production. If ActionCard or a parent wrapper already provides this, we’re good; otherwise, consider adding one at the Action Center container level to avoid per-item boundaries.


104-105: Missing translation keys in non-English locales for AwaitingApproval/AwaitingSwap

Our verification shows that only the English locale defines the four new keys:

  • actionCenter.swap.awaitingApproval
  • actionCenter.swap.awaitingSwap
  • actionCenter.status.awaitingApproval
  • actionCenter.status.awaitingSwap

All other src/assets/translations/<locale>/main.json files (de, es, fr, id, ja, ko, pt, ru, tr, uk, zh) are missing one or more of these entries. As a result, users in those locales will fall back (or see missing text) instead of the intended translations.

Please add the missing keys (with appropriate translations) to each main.json. For example:

• In src/assets/translations/de/main.json:

+  "actionCenter": {
+    "swap": {
+      "awaitingApproval": "Deine Swap von %{sellAmountAndSymbol} zu %{buyAmountAndSymbol} wartet auf Genehmigung.",
+      "awaitingSwap": "Deine Swap von %{sellAmountAndSymbol} zu %{buyAmountAndSymbol} wartet auf Ausführung."
+    },
+    "status": {
+      "awaitingApproval": "Wartet auf Genehmigung",
+      "awaitingSwap": "Wartet auf Swap"
+    }
+  }

(Repeat for each locale.)

After updating, please re-run:

for file in src/assets/translations/*/main.json; do
  jq -e '
    .actionCenter.swap.awaitingApproval
    and .actionCenter.swap.awaitingSwap
    and .actionCenter.status.awaitingApproval
    and .actionCenter.status.awaitingSwap
  ' "$file" && echo "$file: OK" || echo "$file: Missing keys"
done

to confirm all translation files include the new entries.

⛔ Skipped due to learnings
Learnt from: 0xApotheosis
PR: shapeshift/web#10073
File: src/components/Layout/Header/ActionCenter/components/Details/ClaimDetails.tsx:10-11
Timestamp: 2025-07-24T21:05:13.642Z
Learning: In the ShapeShift web repository, translation workflow follows a two-step process: 1) First PR adds only English translations to src/assets/translations/en/main.json, 2) Globalization team handles follow-up PRs to add keys to remaining language files (de, es, fr, id, ja, ko, pt, ru, tr, uk, zh). Don't suggest verifying all locale files simultaneously during initial feature PRs.
Learnt from: premiumjibles
PR: shapeshift/web#10291
File: src/assets/translations/en/main.json:216-218
Timestamp: 2025-08-17T23:39:00.407Z
Learning: In the shapeshift/web project, translations for non-English locales are handled as a separate follow-up process by language experts, not as part of the initial PR that adds English keys to src/assets/translations/en/main.json.
src/components/Layout/Header/ActionCenter/components/ActionStatusTag.tsx (1)

78-89: LGTM: Orange tags for AwaitingApproval/AwaitingSwap

Consistent color scheme and translation keys; matches the icon semantics and the new flow.

Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

https://jam.dev/c/22db1ded-813d-4311-8d8b-8d351458b890

Looks super sexy, only one thing looking weird to me:

If you start a swap, then leave to do something else and never do it back again, you will always have a "waiting for swap" action card until you do another swap, can be done as a follow up but at some point we might want to consider a swap abandoned, we would need to find the perfect heuristics/way to do that

@premiumjibles
Copy link
Collaborator Author

@NeOMakinG actioned swap status change and rename here d9543b2

@premiumjibles premiumjibles enabled auto-merge (squash) August 27, 2025 23:01
@premiumjibles premiumjibles merged commit 5ee4a8e into develop Aug 27, 2025
3 of 4 checks passed
@premiumjibles premiumjibles deleted the 10209_swap_action_approvals branch August 27, 2025 23:09
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.

Clean up the swap action card flow and remove dedicated approval card

2 participants