feat: new token selector#6790
Conversation
…cent color mappings
| }) | ||
| } | ||
|
|
||
| interface EmptyStateFlagsParams { |
There was a problem hiding this comment.
Nitpick, one wise man taught me to sort entities in file. Types declarations should be in the beginning of the file.
| import { useRecentTokenSection } from '../containers/SelectTokenWidget/hooks/useRecentTokenSection' | ||
| import { SelectTokenContext } from '../types' | ||
|
|
||
| export interface TokenListData { |
There was a problem hiding this comment.
Nitpick, it's better to be consistent in namings. TokenListData -> TokenListContext, since we have SelectTokenContext and others
| maxItems?: number | ||
| } | ||
|
|
||
| export function useRecentTokensStorage({ |
There was a problem hiding this comment.
Would be great to extract side-effects from this hook.
In this hook we should only assemble and return RecentTokensStorageState (SRP).
Side-effects can go to a new updater.
| const tradeTypeInfo = tradeTypeInfoFromState ?? tradeTypeInfoFromUrl | ||
| const tradeType = tradeTypeInfo?.tradeType | ||
| // Advanced trades lock the target chain so price guarantees stay valid while the widget is open. | ||
| const shouldLockTargetChain = tradeType === TradeType.LIMIT_ORDER || tradeType === TradeType.ADVANCED_ORDERS |
There was a problem hiding this comment.
Nitpick, I don't really like using tradeType in modules/tokenLists.
Would be cleaner, if we add another flag to SelectTokenWidgetState and only set it as true in limit and advanced widgets.
| export function useOnSelectChain(): OnSelectChainHandler { | ||
| const updateSelectTokenWidget = useUpdateSelectTokenWidgetState() | ||
| const widgetState = useSelectTokenWidgetState() | ||
| const shouldForceOpen = |
There was a problem hiding this comment.
| const isBridgingEnabled = useIsBridgingEnabled() | ||
| const isBridgingEnabled = useIsBridgingEnabled() // Reads from Jotai atom | ||
| const availableChains = useAvailableChains() | ||
| const isAdvancedTradeType = tradeType === TradeType.LIMIT_ORDER || tradeType === TradeType.ADVANCED_ORDERS |
There was a problem hiding this comment.
| /** | ||
| * Registry mapping view names to their custom flow configurations. | ||
| */ | ||
| export type CustomFlowsRegistry = { |
| const chainsPanelTitle = | ||
| field === Field.INPUT ? t`From network` : field === Field.OUTPUT ? t`To network` : t`Select network` | ||
|
|
||
| return { disableErc20, tokenListCategoryState, modalTitle, chainsPanelTitle } |
|
|
||
| const shouldSwitch = | ||
| field === Field.INPUT && | ||
| (tradeType === TradeType.LIMIT_ORDER || tradeType === TradeType.ADVANCED_ORDERS) && |
There was a problem hiding this comment.
Commented similar thing before
| }) | ||
| const importTokenCallback = useAddUserToken() | ||
|
|
||
| return { addCustomTokenLists, importTokenCallback } |
| updateSelectTokenWidget({ selectedPoolAddress: undefined }) | ||
| }, [updateSelectTokenWidget]) | ||
|
|
||
| return { openPoolPage, closePoolPage } |
| const openManageWidget = useCallback(() => updateModalUI({ isManageWidgetOpen: true }), [updateModalUI]) | ||
| const closeManageWidget = useCallback(() => updateModalUI({ isManageWidgetOpen: false }), [updateModalUI]) | ||
|
|
||
| return { isManageWidgetOpen, openManageWidget, closeManageWidget } |
|
|
||
| if (!isManageWidgetOpen) return null | ||
|
|
||
| return { |
|
|
||
| if (!widgetState.selectedPoolAddress) return null | ||
|
|
||
| return { |
There was a problem hiding this comment.
useMemo
I'm commenting it everywhere just to not forget about it
| const onSelectChain = useOnSelectChain() | ||
| const isBridgeFeatureEnabled = useIsBridgingEnabled() | ||
|
|
||
| const shouldDisableForYield = tradeType === TradeType.YIELD && !ENABLE_YIELD_CHAIN_PANEL |
There was a problem hiding this comment.
It's better to add a flag to SelectTokenWidgetState instead of using tradeType here
There was a problem hiding this comment.
there are multiple cases of usage tradeType in widget, not only for TradeType.YIELD type
I can replace it by few flags, at least 3
| isManageWidgetOpen: false, | ||
| } | ||
|
|
||
| export const { atom: selectTokenModalUIAtom, updateAtom: updateSelectTokenModalUIAtom } = atomWithPartialUpdate( |
There was a problem hiding this comment.
Nitpick, we used to call such directories state instead of atom
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/cowswap-frontend/src/locales/en-US.po`:
- Around line 1755-1757: Replace the inconsistent "Receiver" copy with the
existing "Recipient" wording across the locale and component usage: update the
translation entry in apps/cowswap-frontend/src/locales/en-US.po where msgid
"Receiver" / msgstr "Receiver" and any duplicate entries (also noted around the
second occurrence) to use "Recipient"; then update the component that references
this string (apps/cowswap-frontend/src/common/pure/ReceiverInfo/index.tsx) to
use the "Recipient" key/text so the UI consistently shows "Recipient" instead of
"Receiver" (and similarly change any "to receiver" phrasing to "to recipient").
In
`@apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.ts`:
- Around line 5-8: The doc is wrong: the localStorage read happens at module
load, not on first atom read; either update the comment above
recentTokensStorageAtom to state it is initialized at module import, or change
the implementation so the read is lazy — e.g., move the localStorage read into
the atom's default initializer (or a selector/getter used by
recentTokensStorageAtom) so that getRecentTokensFromStorage() (or the
localStorage access currently at module scope) runs only when the atom is first
read; update the comment to match whichever approach you choose and reference
recentTokensStorageAtom and the current storage-read helper name in the change.
♻️ Duplicate comments (4)
apps/cowswap-frontend/src/locales/en-US.po (4)
666-669: Plural edge case for “View all … networks”.This was already raised earlier; still applies if
{totalChains}can be 1.Also applies to: 1954-1957
3256-3259: Network vs chain terminology consistency in availability/route messages.Previously flagged copy consistency issue; still applies.
Also applies to: 4619-4622, 5021-5023, 5519-5521
6185-6187: “Clear” label for recents could be more explicit.Previously flagged suggestion (e.g., “Clear recents”).
2383-2386: Hyphenation for “Cross‑chain swap”.Previously flagged; still applies if this entry is kept.
🧹 Nitpick comments (3)
apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsx (3)
96-114: Test logic is valid but could be more explicit about what's being tested.This test verifies chain isolation, but since
allTokensis empty, the result would be empty even if the chain matched (because hydration requires a matching token inallTokens). Consider adding a token toallTokensfor the GNOSIS_CHAIN to make the test more explicit about testing chain filtering rather than the hydration/matching logic.That said, the current test still passes and achieves its goal of verifying no cross-chain leakage at the storage level.
💡 Optional: Make the test more explicit
it('does not return tokens from other chains', () => { + const gnosisToken = createTestToken(SupportedChainId.GNOSIS_CHAIN, ADDRESS_1, 'TKN') + setStoredTokens({ [SupportedChainId.GNOSIS_CHAIN]: [createStoredToken(SupportedChainId.GNOSIS_CHAIN, ADDRESS_1, 'TKN')], }) const store = createStoreWithLocalStorage() const wrapper = createTestWrapper(store) const { result } = renderHook( () => useRecentTokens({ - allTokens: [], + allTokens: [gnosisToken], favoriteTokens: [], activeChainId: SupportedChainId.MAINNET, }), { wrapper }, ) expect(result.current.recentTokens).toEqual([]) })
220-249: Consider verifying token order when testing maxItems limit.The test correctly verifies that only 2 tokens are returned when
maxItems: 2, but it doesn't verify which tokens are kept. For "recent tokens" functionality, the order typically matters (most recently added should be retained). Consider adding an assertion to verify the expected tokens are present.💡 Optional: Verify which tokens are retained
const { result } = renderHook( () => useRecentTokens({ allTokens: tokens, favoriteTokens: [], activeChainId: SupportedChainId.MAINNET, maxItems: 2, }), { wrapper }, ) expect(result.current.recentTokens).toHaveLength(2) + // Verify that the most recent tokens are kept (assuming T1, T2 are stored first) + const returnedSymbols = result.current.recentTokens.map(t => t.symbol) + expect(returnedSymbols).toEqual(['T1', 'T2']) // or ['T2', 'T3'] depending on ordering semantics })
51-250: Good foundational test coverage.The test suite covers the core functionality well. For even more robust coverage, consider adding tests for:
- Chain switching behavior: Re-rendering with a different
activeChainIdand verifying tokens update accordingly- localStorage persistence: Verifying that
addRecentTokenactually persists to localStorage (not just Jotai state)- Duplicate handling: Adding the same token twice and verifying it doesn't create duplicates (or moves to front if that's the expected behavior)
These are optional enhancements that can be deferred if time-constrained.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/cowswap-frontend/src/locales/en-US.poapps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsxapps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.tsapps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.tsapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsxapps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.ts
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-08-08T13:55:17.528Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6125
File: libs/tokens/src/state/tokens/allTokensAtom.ts:78-78
Timestamp: 2025-08-08T13:55:17.528Z
Learning: In libs/tokens/src/state/tokens/allTokensAtom.ts (TypeScript/Jotai), the team prefers to wait for token lists to initialize (listsStatesListAtom non-empty) before returning tokens. No fallback to favorites/user-added/native tokens should be used when listsStatesList is empty.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.tsapps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.tsapps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsxapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsx
📚 Learning: 2025-08-08T13:56:18.009Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6125
File: libs/tokens/src/updaters/TokensListsUpdater/index.tsx:29-31
Timestamp: 2025-08-08T13:56:18.009Z
Learning: In libs/tokens/src/updaters/TokensListsUpdater/index.tsx, the project’s current Jotai version requires using `unstable_getOnInit` (not `getOnInit`) in atomWithStorage options; keep `{ unstable_getOnInit: true }` until Jotai is upgraded.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.tsapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsxapps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx
📚 Learning: 2025-08-12T06:33:19.348Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6137
File: libs/tokens/src/state/tokens/allTokensAtom.ts:34-65
Timestamp: 2025-08-12T06:33:19.348Z
Learning: In libs/tokens/src/state/tokens/allTokensAtom.ts, the parseTokenInfo() function returns a new instance of TokenInfo each time, making it safe to mutate properties like lpTokenProvider on the returned object without side effects.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsx
📚 Learning: 2025-12-30T18:49:03.377Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6770
File: apps/cowswap-frontend/src/modules/tokensList/hooks/useAddListImport.ts:27-31
Timestamp: 2025-12-30T18:49:03.377Z
Learning: In apps/cowswap-frontend/src/modules/tokensList/hooks/useAddListImport.ts, when restrictedLists.isLoaded is false or geoStatus.isLoading is true, the code intentionally proceeds with the import immediately without blocking. This allows imports to proceed during loading states, deferring consent checks to trade time when necessary data isn't yet available.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.tsapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsxapps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-09-19T11:38:59.206Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6232
File: apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx:199-200
Timestamp: 2025-09-19T11:38:59.206Z
Learning: The makeBuildClickEvent function in apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx takes five parameters: defaultChainId, contextLabel, mode, isSwapMode, and chainsCount. The chainsCount parameter is used to determine the CrossChain flag in analytics events.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.tsapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsxapps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-08-12T06:33:19.348Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6137
File: libs/tokens/src/state/tokens/allTokensAtom.ts:34-65
Timestamp: 2025-08-12T06:33:19.348Z
Learning: In libs/tokens/src/utils/parseTokenInfo.ts, the parseTokenInfo() function returns a new instance of TokenInfo using object spread syntax ({ ...token, ... }), making it safe to mutate properties like lpTokenProvider on the returned object without side effects.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.tsapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsx
📚 Learning: 2025-03-25T10:03:35.157Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5532
File: libs/common-hooks/src/useOnScroll.tsx:22-38
Timestamp: 2025-03-25T10:03:35.157Z
Learning: In React useEffect hooks, refs (RefObjects) should generally be included in dependency arrays even though changes to ref.current don't trigger effects. This is because the ref object itself could change between renders (especially in custom hooks where refs are passed as parameters), and it follows React's best practice of including all external values used in the effect.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.ts
📚 Learning: 2025-10-10T20:28:16.565Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsxapps/cowswap-frontend/src/modules/tokensList/index.tsapps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.tsapps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsxapps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsxapps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-09-25T08:48:53.495Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:58-60
Timestamp: 2025-09-25T08:48:53.495Z
Learning: In the cowswap-frontend codebase, when writing SWR tests, the team prefers maximum test isolation by using `provider: () => new Map()` in SWRConfig wrappers, even if it recreates cache on every render, to ensure tests don't share any state.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsx
📚 Learning: 2025-09-25T08:49:32.256Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:62-67
Timestamp: 2025-09-25T08:49:32.256Z
Learning: In the cowswap-frontend codebase, when testing hooks that use multiple bridge providers, both providers are always properly mocked as complete jest.Mocked<BridgeProvider<BridgeQuoteResult>> objects with all required methods stubbed, ensuring no undefined returns that could break the hook logic.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsxapps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsx
📚 Learning: 2025-07-24T16:42:53.154Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6009
File: apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/HighFeeWarningTooltipContent.tsx:23-33
Timestamp: 2025-07-24T16:42:53.154Z
Learning: In apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/HighFeeWarningTooltipContent.tsx, the use of toFixed(2) for percentage formatting in tooltip content is intentional and differs from the banner message formatting that uses toSignificant(2, undefined, Rounding.ROUND_DOWN). This formatting difference serves different UX purposes and should not be flagged as inconsistent.
Applied to files:
apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsxapps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-06-25T07:28:32.570Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5881
File: apps/cowswap-frontend/src/modules/cowShed/containers/ProxyRecipient/index.tsx:68-72
Timestamp: 2025-06-25T07:28:32.570Z
Learning: In the ProxyRecipient component (apps/cowswap-frontend/src/modules/cowShed/containers/ProxyRecipient/index.tsx), throwing an error when recipient address doesn't match proxy address is intentional design choice to prevent proceeding with incorrect data and ensure data integrity.
Applied to files:
apps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-02-20T15:59:33.749Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5443
File: apps/cowswap-frontend/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx:71-71
Timestamp: 2025-02-20T15:59:33.749Z
Learning: The swap module in apps/cowswap-frontend/src/modules/swap/ is marked for deletion in PR `#5444` as part of the swap widget unification effort.
Applied to files:
apps/cowswap-frontend/src/locales/en-US.po
🧬 Code graph analysis (6)
apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.ts (1)
apps/cowswap-frontend/src/modules/tokensList/utils/recentTokensStorage.ts (3)
StoredRecentTokensByChain(19-19)readStoredTokens(66-92)RECENT_TOKENS_LIMIT(4-4)
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.ts (6)
libs/common-const/src/types.ts (1)
TokenWithLogo(6-36)apps/cowswap-frontend/src/modules/tokensList/types.ts (1)
SelectTokenContext(13-24)libs/wallet/src/api/hooks.ts (1)
useWalletInfo(24-26)apps/cowswap-frontend/src/modules/tokensList/hooks/useTokensToSelect.ts (1)
useTokensToSelect(24-64)apps/cowswap-frontend/src/modules/tokensList/hooks/useSelectTokenContext.ts (1)
useSelectTokenContext(16-45)libs/common-utils/src/isInjectedWidget.ts (1)
isInjectedWidget(5-14)
apps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.ts (1)
apps/cowswap-frontend/src/modules/tokensList/containers/SelectTokenWidget/atoms/index.ts (1)
atom(19-21)
apps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsx (3)
apps/cowswap-frontend/src/modules/tokensList/index.ts (1)
RecentTokensStorageUpdater(16-16)apps/cowswap-frontend/src/modules/tokensList/state/recentTokensStorageAtom.ts (1)
recentTokensStorageAtom(9-9)apps/cowswap-frontend/src/modules/tokensList/utils/recentTokensStorage.ts (2)
persistStoredTokens(94-104)StoredRecentTokensByChain(19-19)
apps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsx (5)
apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListViewState.ts (1)
useTokenListViewState(5-7)apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.ts (1)
useTokenListContext(40-74)libs/ui/src/pure/Loader/index.tsx (1)
Loader(32-43)apps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsx (1)
TokenSearchResults(13-76)apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsx (1)
TokensVirtualList(24-68)
apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsx (5)
libs/common-const/src/types.ts (1)
TokenWithLogo(6-36)apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.ts (1)
useTokenListContext(40-74)apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/tokensVirtualListUtils.ts (2)
sortTokensByBalance(13-33)buildVirtualRows(43-72)apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/types.ts (1)
TokensVirtualRow(3-6)apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/TokensVirtualRowRenderer.tsx (1)
TokensVirtualRowRenderer(15-35)
⏰ 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). (2)
- GitHub Check: Setup
- GitHub Check: Cypress
🔇 Additional comments (14)
apps/cowswap-frontend/src/modules/tokensList/state/tokenListViewAtom.ts (1)
1-21: Looks good: minimal, focused UI state atom.Cleanly scoped to local UI state and consistent with the existing
atomWithPartialUpdatepattern.apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokens.test.tsx (3)
1-17: LGTM!Imports are well-organized with clear separation between external packages and internal modules. All imported items appear to be used in the test file.
19-49: Well-structured test utilities.The helper functions provide good abstraction for test setup. The pattern of creating a fresh Jotai store per test with
createStoreWithLocalStorage()ensures proper test isolation. ThebeforeEachcleanup of localStorage (line 53) prevents state leakage between tests.
116-218: LGTM!Good test coverage for:
- Filtering favorite tokens from recent tokens list (with proper case-insensitive address comparison)
- Adding tokens via
addRecentToken- Guard against adding favorite tokens to recent list
- Clearing tokens for the active chain
Proper use of
act()for all state mutations ensures React state updates are flushed before assertions.apps/cowswap-frontend/src/modules/tokensList/updaters/RecentTokensStorageUpdater.tsx (1)
15-53: LGTM — persistence + favorite cleanup look well-contained.apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx (1)
36-121: LGTM — updater wiring is consistent with existing pattern.apps/cowswap-frontend/src/modules/tokensList/hooks/useRecentTokensStorage.test.tsx (1)
57-303: LGTM — solid coverage for storage, ordering, and chain isolation.apps/cowswap-frontend/src/modules/tokensList/index.ts (1)
2-30: LGTM — export surface additions are clear and additive.apps/cowswap-frontend/src/locales/en-US.po (2)
282-286: LGTM: new token‑selector labels and search/selection strings.Copy reads cleanly and matches expected UI context.
Also applies to: 304-306, 646-648, 872-874, 884-887, 1006-1008, 1441-1443, 2136-2138, 2607-2610, 3925-3927, 4409-4412, 4571-4574, 5110-5112, 5268-5271, 5401-5403, 5592-5597
1292-1293: No additional feedback on these obsolete (#~) entries.Also applies to: 2180-2183, 3658-3661, 4384-4387, 6263-6265
apps/cowswap-frontend/src/modules/tokensList/containers/TokenSearchResults/index.tsx (1)
13-58: Nice hook-based refactor and Enter handling.The single-match Enter path now updates recent tokens before selection, and the bridge filtering logic stays clean.
apps/cowswap-frontend/src/modules/tokensList/pure/TokensContent/index.tsx (1)
12-68: Pinned-recents filtering looks solid.The Set-based pinning removes recent tokens from the main list while preserving favorites for balance sorting. Clean and readable.
apps/cowswap-frontend/src/modules/tokensList/pure/TokensVirtualList/index.tsx (1)
17-66: Virtual row pipeline looks good.The sorted-tokens +
buildVirtualRowsflow and chain-keyedVirtualListreset behavior fit the refactor well.apps/cowswap-frontend/src/modules/tokensList/hooks/useTokenListContext.ts (1)
40-72: No action needed—the code already handles undefined chain IDs safely.The
activeChainIdparameter is optional throughout the chain, and the implementation already accounts for this:
- Recent tokens are stored using
token.chainId(from the selected token), notactiveChainIduseHydratedRecentTokenssafely returns an empty array ifactiveChainIdis undefinedclearRecentTokenschecksif (activeChainId)before clearingNo fallback or additional guards are required.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
SelectTokenWidget Architecture
Summary
Refactored the SelectTokenWidget with a modular, slot-based architecture for improved maintainability and extensibility.
Each UI section (Header, Search, TokenList, etc.) is a "slot" with a pure component and connected wrapper - source
Component Hierarchy
Directory Structure
Data Flow
Custom Flows System
External modules can inject custom UI flows via
customFlowsprop:Example usage (RWA consent flow):
To test
PREVIEW LINK: https://swap-dev-git-feat-token-selector-15-cowswap-dev.vercel.app/
Everything should work as for current token selector but with new UI/UX -> token list/search/bridging/network switching
Summary by CodeRabbit
Release Notes
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.