From e2a7eec22122bb953344763995ff84d964f58fbb Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Fri, 22 Nov 2024 15:28:58 +0700 Subject: [PATCH] Feat/remove tx and remove localization (#2561) --- src/components/Menu/index.tsx | 21 +- .../WalletPopup/Transactions/index.tsx | 212 ++++++++++++------ src/components/WalletPopup/WalletView.tsx | 4 +- src/state/transactions/actions.ts | 4 + src/state/transactions/reducer.ts | 9 + src/state/user/hooks.tsx | 6 +- 6 files changed, 162 insertions(+), 94 deletions(-) diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index e6b57a5f7b..f9cdea3c50 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -14,7 +14,6 @@ import { ReactComponent as LightIcon } from 'assets/svg/light.svg' import { ReactComponent as RoadMapIcon } from 'assets/svg/roadmap.svg' import { ButtonEmpty, ButtonPrimary } from 'components/Button' import { AutoColumn } from 'components/Column' -import ArrowRight from 'components/Icons/ArrowRight' import CampaignIcon from 'components/Icons/CampaignIcon' import Faucet from 'components/Icons/Faucet' import Icon from 'components/Icons/Icon' @@ -28,7 +27,6 @@ import Toggle from 'components/Toggle' import { TutorialIds } from 'components/Tutorial/TutorialSwap/constant' import { ENV_LEVEL, TAG } from 'constants/env' import { AGGREGATOR_ANALYTICS_URL, APP_PATHS, TERM_FILES_PATH } from 'constants/index' -import { getLocaleLabel } from 'constants/locales' import { FAUCET_NETWORKS } from 'constants/networks' import { ENV_TYPE } from 'constants/type' import { useActiveWeb3React } from 'hooks' @@ -39,7 +37,7 @@ import { PROFILE_MANAGE_ROUTES } from 'pages/NotificationCenter/const' import { ApplicationModal } from 'state/application/actions' import { useModalOpen, useToggleModal } from 'state/application/hooks' import { useTutorialSwapGuide } from 'state/tutorial/hooks' -import { useHolidayMode, useUserLocale } from 'state/user/hooks' +import { useHolidayMode } from 'state/user/hooks' import { ExternalLink, MEDIA_WIDTHS } from 'theme' import { isChristmasTime } from 'utils' @@ -207,7 +205,6 @@ export default function Menu() { const [holidayMode, toggleHolidayMode] = useHolidayMode() const [isSelectingLanguage, setIsSelectingLanguage] = useState(false) - const userLocale = useUserLocale() const location = useLocation() const { mixpanelHandler } = useMixpanel() @@ -523,22 +520,6 @@ export default function Menu() { Notification Center - { - setIsSelectingLanguage(true) - handlePreferenceClickMixpanel('Language') - }} - > - Language - - {getLocaleLabel(userLocale, true)}   - - - diff --git a/src/components/WalletPopup/Transactions/index.tsx b/src/components/WalletPopup/Transactions/index.tsx index d7cb6969ad..93b897c657 100644 --- a/src/components/WalletPopup/Transactions/index.tsx +++ b/src/components/WalletPopup/Transactions/index.tsx @@ -1,11 +1,16 @@ import { Trans, t } from '@lingui/macro' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { Info } from 'react-feather' +import { Info, X } from 'react-feather' +import { useMedia } from 'react-use' import AutoSizer from 'react-virtualized-auto-sizer' import { VariableSizeList } from 'react-window' import { Flex, Text } from 'rebass' import styled, { CSSProperties } from 'styled-components' +import { ButtonOutlined, ButtonPrimary } from 'components/Button' +import InfoHelper from 'components/InfoHelper' +import Modal from 'components/Modal' +import Row, { RowBetween } from 'components/Row' import Tab from 'components/WalletPopup/Transactions/Tab' import { NUMBERS } from 'components/WalletPopup/Transactions/helper' import useCancellingOrders, { CancellingOrderInfo } from 'components/swapv2/LimitOrder/useCancellingOrders' @@ -13,6 +18,8 @@ import { useActiveWeb3React } from 'hooks' import { fetchListTokenByAddresses, findCacheToken, useIsLoadedTokenDefault } from 'hooks/Tokens' import { isSupportKyberDao } from 'hooks/kyberdao' import useTheme from 'hooks/useTheme' +import { useAppDispatch } from 'state/hooks' +import { clearAllPendingTransactions } from 'state/transactions/actions' import { useSortRecentTransactions } from 'state/transactions/hooks' import { TRANSACTION_GROUP, @@ -20,6 +27,7 @@ import { TransactionExtraInfo1Token, TransactionExtraInfo2Token, } from 'state/transactions/type' +import { MEDIA_WIDTHS } from 'theme' import TransactionItem from './TransactionItem' @@ -50,6 +58,28 @@ const Wrapper = styled.div` gap: 12px; ` +const ClearTxButton = styled.div` + cursor: pointer; + color: ${({ theme }) => theme.primary}; + font-size: 14px; + display: flex; + align-items: center; + gap: 5px; +` + +const ClearTxWrapper = styled.div` + padding: 20px; + border-radius: 20px; + background-color: ${({ theme }) => theme.tableHeader}; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 24px; + width: 100%; + color: ${({ theme }) => theme.subText}; +` + function RowItem({ index, style, @@ -107,24 +137,23 @@ function RowItem({ // This is intentional, we don't need to persist in localStorage let storedActiveTab = '' function ListTransaction({ isMinimal }: { isMinimal: boolean }) { - const listTab = useMemo( - () => [ - { title: t`All`, value: '' }, - { title: t`Swaps`, value: TRANSACTION_GROUP.SWAP }, - { title: t`Liquidity`, value: TRANSACTION_GROUP.LIQUIDITY }, - { title: t`KyberDAO`, value: TRANSACTION_GROUP.KYBERDAO }, - { title: t`Others`, value: TRANSACTION_GROUP.OTHER }, - ], - [], - ) - const transactions = useSortRecentTransactions(false) - const { chainId } = useActiveWeb3React() - const [activeTab, setActiveTab] = useState(storedActiveTab) const theme = useTheme() const cancellingOrderInfo = useCancellingOrders() + const dispatch = useAppDispatch() + const { chainId } = useActiveWeb3React() + + const [activeTab, setActiveTab] = useState(storedActiveTab) + const [openClearTxModal, setOpenClearTxModal] = useState(false) + const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`) const listTokenAddress = useRef([]) + const rowHeights = useRef<{ [key: string]: number }>({}) + const listRef = useRef(null) + + const total = listTokenAddress.current + const isLoadedTokenDefault = useIsLoadedTokenDefault() + const pushAddress = (address: string) => { if (address && !listTokenAddress.current.includes(address)) listTokenAddress.current.push(address) } @@ -147,13 +176,27 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) { return result }, [transactions, activeTab]) - const total = listTokenAddress.current - const isLoadedTokenDefault = useIsLoadedTokenDefault() - useEffect(() => { - if (!isLoadedTokenDefault) return - const list: string[] = listTokenAddress.current.filter(address => !findCacheToken(address)) - if (list.length) fetchListTokenByAddresses(list, chainId).catch(console.error) - }, [total, isLoadedTokenDefault, chainId]) + const pendingTransactions = formatTransactions.filter(tx => !tx.receipt) + + const listTab = useMemo( + () => [ + { title: t`All`, value: '' }, + { title: t`Swaps`, value: TRANSACTION_GROUP.SWAP }, + { title: t`Liquidity`, value: TRANSACTION_GROUP.LIQUIDITY }, + { title: t`KyberDAO`, value: TRANSACTION_GROUP.KYBERDAO }, + { title: t`Others`, value: TRANSACTION_GROUP.OTHER }, + ], + [], + ) + + const filterTab = useMemo(() => { + return listTab.filter(tab => { + if (tab.value === TRANSACTION_GROUP.KYBERDAO) { + return isSupportKyberDao(chainId) + } + return true + }) + }, [chainId, listTab]) const onRefChange = useCallback((node: HTMLDivElement) => { if (!node?.classList.contains('scrollbar')) { @@ -161,8 +204,6 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) { } }, []) - const rowHeights = useRef<{ [key: string]: number }>({}) - const listRef = useRef(null) const setRowHeight = useCallback((index: number, size: number) => { listRef.current?.resetAfterIndex(0) rowHeights.current = { ...rowHeights.current, [index]: size } @@ -172,59 +213,92 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) { return rowHeights.current[index] || 100 } + const toggleClearTxModal = () => setOpenClearTxModal(prev => !prev) + const onClearAllPendingTransactions = () => { + dispatch(clearAllPendingTransactions({ chainId })) + toggleClearTxModal() + } + + useEffect(() => { + if (!isLoadedTokenDefault) return + const list: string[] = listTokenAddress.current.filter(address => !findCacheToken(address)) + if (list.length) fetchListTokenByAddresses(list, chainId).catch(console.error) + }, [total, isLoadedTokenDefault, chainId]) + useEffect(() => { storedActiveTab = activeTab }, [activeTab]) - const filterTab = useMemo(() => { - return listTab.filter(tab => { - if (tab.value === TRANSACTION_GROUP.KYBERDAO) { - return isSupportKyberDao(chainId) - } - return true - }) - }, [chainId, listTab]) - return ( - - activeTab={activeTab} setActiveTab={setActiveTab} tabs={filterTab} /> - - {formatTransactions.length === 0 ? ( - - - - You have no Transaction History. + <> + + + + + {t`Clear All Pending Transactions`} + + + + + + {t`Are you sure you want to clear all pending transactions? This will remove them from your list but will not affect their status on-chain.`} - - ) : ( - - {({ height, width }) => ( - - {({ data, index, style }) => ( - - )} - - )} - + + + {t`Cancel`} + {t`Clear All`} + + + + + activeTab={activeTab} setActiveTab={setActiveTab} tabs={filterTab} /> + + {formatTransactions.length === 0 ? ( + + + + You have no Transaction History. + + + ) : ( + + {({ height, width }) => ( + + {({ data, index, style }) => ( + + )} + + )} + + )} + + {pendingTransactions.length !== 0 && ( + + {t`Clear Pending Transactions`} + + )} - - + + ) } diff --git a/src/components/WalletPopup/WalletView.tsx b/src/components/WalletPopup/WalletView.tsx index 3c7d27ffdc..751b77a38d 100644 --- a/src/components/WalletPopup/WalletView.tsx +++ b/src/components/WalletPopup/WalletView.tsx @@ -55,7 +55,8 @@ const Wrapper = styled.div.attrs(props => ({ 'data-blur': props.$blur, }))` width: 100%; - height: 100%; + /* height: 100%; */ + height: unset; padding-top: 0px; display: flex; @@ -77,7 +78,6 @@ const Wrapper = styled.div.attrs(props => ({ ${({ theme }) => theme.mediaWidth.upToMedium` padding-bottom: 0; - height: unset; `}; ` diff --git a/src/state/transactions/actions.ts b/src/state/transactions/actions.ts index 2ffe73cd77..f2992ecf51 100644 --- a/src/state/transactions/actions.ts +++ b/src/state/transactions/actions.ts @@ -7,6 +7,10 @@ export const addTransaction = createAction('transactions/add export const clearAllTransactions = createAction<{ chainId: ChainId }>('transactions/clearAllTransactions') +export const clearAllPendingTransactions = createAction<{ chainId: ChainId }>( + 'transactions/clearAllPendingTransactions', +) + export const finalizeTransaction = createAction<{ chainId: ChainId hash: string diff --git a/src/state/transactions/reducer.ts b/src/state/transactions/reducer.ts index e5c871acfd..60ab3641a6 100644 --- a/src/state/transactions/reducer.ts +++ b/src/state/transactions/reducer.ts @@ -7,6 +7,7 @@ import { getTransactionGroupByType } from 'utils/transaction' import { addTransaction, checkedTransaction, + clearAllPendingTransactions, clearAllTransactions, finalizeTransaction, modifyTransaction, @@ -65,6 +66,14 @@ export default createReducer(initialState, builder => if (!transactions[chainId]) return transactions[chainId] = {} }) + .addCase(clearAllPendingTransactions, (transactions, { payload: { chainId } }) => { + if (!transactions[chainId]) return + const pendingTxHash: string[] = [] + Object.keys(transactions[chainId] || {}).forEach(txHash => { + if (!transactions[chainId]?.[txHash]?.find(tx => tx.receipt)) pendingTxHash.push(txHash) + }) + pendingTxHash.forEach(txHash => delete transactions[chainId]?.[txHash]) + }) .addCase(checkedTransaction, (transactions, { payload: { chainId, hash, blockNumber } }) => { const tx = findTx(transactions[chainId], hash) if (!tx) return diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx index d9da7cb86b..eaf2540777 100644 --- a/src/state/user/hooks.tsx +++ b/src/state/user/hooks.tsx @@ -3,7 +3,7 @@ import { useCallback, useMemo } from 'react' import { useDispatch, useSelector } from 'react-redux' import { INITIAL_ALLOWED_SLIPPAGE, TERM_FILES_PATH } from 'constants/index' -import { LOCALE_INFO, SupportedLocale } from 'constants/locales' +import { SupportedLocale } from 'constants/locales' import { GAS_TOKENS } from 'constants/tokens' import { useActiveWeb3React } from 'hooks' import { useAllTokens } from 'hooks/Tokens' @@ -81,8 +81,8 @@ function deserializeToken(serializedToken: SerializedToken): Token { } export function useUserLocale(): SupportedLocale | null { - const userLocale = useAppSelector(state => state.user.userLocale) - if (Object.keys(LOCALE_INFO).includes(userLocale)) return userLocale + // const userLocale = useAppSelector(state => state.user.userLocale) + // if (Object.keys(LOCALE_INFO).includes(userLocale)) return userLocale return 'en-US' }