From f15b23a5bb754c94a948680f29c9f8f003013017 Mon Sep 17 00:00:00 2001 From: XiaoYhun Date: Thu, 27 Jul 2023 09:42:41 +0700 Subject: [PATCH] update logic of favorite tokens to adapt with common bases from api --- src/components/SearchModal/CurrencyList.tsx | 8 +- src/components/SearchModal/CurrencySearch.tsx | 48 ++++-------- src/state/user/actions.ts | 9 +-- src/state/user/hooks.tsx | 23 +++--- src/state/user/reducer.ts | 77 ++++++++++++++----- 5 files changed, 92 insertions(+), 73 deletions(-) diff --git a/src/components/SearchModal/CurrencyList.tsx b/src/components/SearchModal/CurrencyList.tsx index 43e39fdadf..eb9f04332e 100644 --- a/src/components/SearchModal/CurrencyList.tsx +++ b/src/components/SearchModal/CurrencyList.tsx @@ -136,13 +136,13 @@ export function CurrencyRow({ return false } - if (isTokenNative(currency, currency.chainId)) { - return !!favoriteTokens.includeNativeToken - } + // if (isTokenNative(currency, currency.chainId)) { + // return !!favoriteTokens.includeNativeToken + // } if (currency.isToken) { const addr = (currency as Token).address ?? '' - const addresses = favoriteTokens?.addresses ?? [] + const addresses = favoriteTokens ?? [] return !!addresses?.includes(addr) || !!addresses?.includes(addr.toLowerCase()) } diff --git a/src/components/SearchModal/CurrencySearch.tsx b/src/components/SearchModal/CurrencySearch.tsx index d7529a1f03..01784ccd6f 100644 --- a/src/components/SearchModal/CurrencySearch.tsx +++ b/src/components/SearchModal/CurrencySearch.tsx @@ -76,7 +76,7 @@ const ButtonClear = styled.div` gap: 5px; cursor: pointer; ` -const MAX_FAVORITE_PAIR = 12 +// const MAX_FAVORITE_PAIR = 12 interface CurrencySearchProps { isOpen: boolean @@ -169,6 +169,7 @@ export function CurrencySearch({ const tokenComparator = useTokenComparator(false, customChainId) const [commonTokens, setCommonTokens] = useState<(Token | Currency)[]>([]) + console.log('🚀 ~ file: CurrencySearch.tsx:172 ~ commonTokens:', commonTokens) const [loadingCommon, setLoadingCommon] = useState(true) const tokenImportsFiltered = useMemo(() => { @@ -254,32 +255,15 @@ export function CurrencySearch({ const handleClickFavorite = useCallback( (e: React.MouseEvent, currency: any) => { e.stopPropagation() - const address = currency?.wrapped?.address || currency.address if (!address) return - const currentList = favoriteTokens?.addresses || [] - const isAddFavorite = isTokenNative(currency, currency.chainId) - ? !favoriteTokens?.includeNativeToken - : !currentList.find(el => el === address) // else remove favorite - const curTotal = - currentList.filter(address => !!defaultTokens[address]).length + (favoriteTokens?.includeNativeToken ? 1 : 0) - if (isAddFavorite && curTotal === MAX_FAVORITE_PAIR) return - - if (isTokenNative(currency, currency.chainId)) { - toggleFavoriteToken({ - chainId, - isNative: true, - }) - return - } - toggleFavoriteToken({ chainId, address, }) }, - [chainId, favoriteTokens, toggleFavoriteToken, defaultTokens], + [chainId, toggleFavoriteToken], ) // menu ui @@ -292,20 +276,23 @@ export function CurrencySearch({ if (!Object.keys(defaultTokens).length) return setLoadingCommon(true) let result: (Token | Currency)[] = [] - if (favoriteTokens?.includeNativeToken) { - result.push(NativeCurrencies[chainId]) - } const addressesToFetch: string[] = [] - favoriteTokens?.addresses.forEach(address => { + + favoriteTokens?.forEach(address => { if (defaultTokens[address]) { result.push(defaultTokens[address]) return } addressesToFetch.push(address) }) + if (addressesToFetch.length) { const tokens = await fetchListTokenByAddresses(addressesToFetch, chainId) - result = result.concat(tokens) + result = result.concat( + tokens.sort((x, y) => { + return addressesToFetch.indexOf(x.wrapped.address) - addressesToFetch.indexOf(y.wrapped.address) + }), + ) } setCommonTokens(result) } catch (error) { @@ -393,14 +380,13 @@ export function CurrencySearch({ const removeImportedToken = useCallback( (token: Token) => { removeToken(chainId, token.address) - if (favoriteTokens?.addresses?.includes(token.address)) - // remove in favorite too - toggleFavoriteToken({ - chainId, - address: token.address, - }) + + toggleFavoriteToken({ + chainId, + address: token.address, + }) }, - [chainId, toggleFavoriteToken, removeToken, favoriteTokens?.addresses], + [chainId, toggleFavoriteToken, removeToken], ) const removeAllImportToken = () => { diff --git a/src/state/user/actions.ts b/src/state/user/actions.ts index 2ea854cb73..1a8a5cf9b1 100644 --- a/src/state/user/actions.ts +++ b/src/state/user/actions.ts @@ -49,12 +49,9 @@ export const toggleTopTrendingTokens = createAction('user/toggleTopTrendin export type ToggleFavoriteTokenPayload = { chainId: ChainId -} & ({ isNative?: false; address: string } | { isNative: true; address?: never }) -export const toggleFavoriteToken = createAction< - ToggleFavoriteTokenPayload & { - defaultCommonTokens: { addresses: string[]; includeNativeToken: boolean } - } ->('user/toggleFavoriteToken') + address: string +} +export const toggleFavoriteToken = createAction('user/toggleFavoriteToken') export const updateChainId = createAction('user/updateChainId') export const updateTokenAnalysisSettings = createAction('user/updateTokenAnalysisSettings') export const updateAcceptedTermVersion = createAction('user/updateAcceptedTermVersion') diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx index 31deddbddd..6a1946939d 100644 --- a/src/state/user/hooks.tsx +++ b/src/state/user/hooks.tsx @@ -396,27 +396,28 @@ export function useToggleTopTrendingTokens(): () => void { export const useUserFavoriteTokens = (chainId: ChainId) => { const dispatch = useDispatch() - const { favoriteTokensByChainId } = useSelector((state: AppState) => state.user) + const { favoriteTokensByChainIdv2: favoriteTokensByChainId } = useSelector((state: AppState) => state.user) const { commonTokens } = useKyberSwapConfig(chainId) const defaultTokens = useMemo(() => { - return { addresses: commonTokens || SUGGESTED_BASES[chainId || 1].map(e => e.address), includeNativeToken: true } + return commonTokens || SUGGESTED_BASES[chainId || 1].map(e => e.address) }, [commonTokens, chainId]) const favoriteTokens = useMemo(() => { - if (!chainId) return undefined - return favoriteTokensByChainId?.[chainId] || defaultTokens + if (!chainId || !defaultTokens) return undefined + const favoritedToken = favoriteTokensByChainId?.[chainId] + const favoritedTokenAddresses = favoritedToken + ? defaultTokens + .filter(address => favoritedToken[address] !== false) + .concat(Object.keys(favoritedToken).filter(address => favoritedToken[address])) + : [] + return [...new Set(favoritedTokenAddresses)] }, [chainId, favoriteTokensByChainId, defaultTokens]) const toggleFavoriteToken = useCallback( (payload: ToggleFavoriteTokenPayload) => { - dispatch( - toggleFavoriteTokenAction({ - ...payload, - defaultCommonTokens: defaultTokens, - }), - ) + dispatch(toggleFavoriteTokenAction(payload)) }, - [dispatch, defaultTokens], + [dispatch], ) return { favoriteTokens, toggleFavoriteToken } diff --git a/src/state/user/reducer.ts b/src/state/user/reducer.ts index 32ab948c0a..c5cab60448 100644 --- a/src/state/user/reducer.ts +++ b/src/state/user/reducer.ts @@ -100,7 +100,7 @@ interface UserState { kyberAIDisplaySettings: { [k: string]: boolean } - favoriteTokensByChainId: Partial< + favoriteTokensByChainId?: Partial< Record< ChainId, { @@ -109,6 +109,15 @@ interface UserState { } > > + // favoriteTokensByChainIdv2: Partial< + // Record< + // ChainId, + // { + // [address: string]: boolean + // } + // > + // > + favoriteTokensByChainIdv2: any readonly chainId: ChainId acceptedTermVersion: number | null viewMode: VIEW_MODE @@ -179,6 +188,7 @@ const initialState: UserState = { liquidationsOnCEX: true, }, favoriteTokensByChainId: {}, + favoriteTokensByChainIdv2: {}, chainId: ChainId.MAINNET, acceptedTermVersion: null, viewMode: VIEW_MODE.GRID, @@ -293,32 +303,57 @@ export default createReducer(initialState, builder => .addCase(toggleKyberAIBanner, state => { state.showKyberAIBanner = !state.showKyberAIBanner }) - .addCase(toggleFavoriteToken, (state, { payload: { chainId, isNative, address, defaultCommonTokens } }) => { - if (!state.favoriteTokensByChainId) { - state.favoriteTokensByChainId = {} + .addCase(toggleFavoriteToken, (state, { payload: { chainId, address } }) => { + if (!state.favoriteTokensByChainIdv2) { + state.favoriteTokensByChainIdv2 = {} } - let favoriteTokens = state.favoriteTokensByChainId[chainId] - if (!favoriteTokens) { - favoriteTokens = defaultCommonTokens - state.favoriteTokensByChainId[chainId] = favoriteTokens + // Migrate from old version to new version, prevent lost favorite tokens of user + if (state.favoriteTokensByChainId) { + state.favoriteTokensByChainIdv2 = Object.entries(state.favoriteTokensByChainId).reduce( + (acc, [chainId, obj]) => { + acc[chainId] = {} + obj.addresses.forEach(address => { + acc[chainId][address] = true + }) + return acc + }, + {} as any, + ) + state.favoriteTokensByChainId = undefined } - if (isNative) { - const previousValue = favoriteTokens.includeNativeToken - favoriteTokens.includeNativeToken = !previousValue - return + if (!state.favoriteTokensByChainIdv2[chainId]) { + state.favoriteTokensByChainIdv2[chainId] = {} } - if (address) { - // this is intentionally added, to remove compiler error - const index = favoriteTokens.addresses.findIndex(addr => addr === address) - if (index === -1) { - favoriteTokens.addresses.push(address) - return - } - favoriteTokens.addresses.splice(index, 1) - } + state.favoriteTokensByChainIdv2[chainId][address] = !state.favoriteTokensByChainIdv2[chainId][address] + + // if (!state.favoriteTokensByChainId) { + // state.favoriteTokensByChainId = {} + // } + + // let favoriteTokens = state.favoriteTokensByChainId[chainId] + // if (!favoriteTokens) { + // favoriteTokens = defaultCommonTokens + // state.favoriteTokensByChainId[chainId] = favoriteTokens + // } + + // if (isNative) { + // const previousValue = favoriteTokens.includeNativeToken + // favoriteTokens.includeNativeToken = !previousValue + // return + // } + + // if (address) { + // // this is intentionally added, to remove compiler error + // const index = favoriteTokens.addresses.findIndex(addr => addr === address) + // if (index === -1) { + // favoriteTokens.addresses.push(address) + // return + // } + // favoriteTokens.addresses.splice(index, 1) + // } }) .addCase(updateChainId, (state, { payload: chainId }) => { state.chainId = chainId