1
1
import { Trans , t } from '@lingui/macro'
2
2
import { memo , useCallback , useEffect , useMemo , useRef , useState } from 'react'
3
- import { Info } from 'react-feather'
3
+ import { Info , X } from 'react-feather'
4
+ import { useMedia } from 'react-use'
4
5
import AutoSizer from 'react-virtualized-auto-sizer'
5
6
import { VariableSizeList } from 'react-window'
6
7
import { Flex , Text } from 'rebass'
7
8
import styled , { CSSProperties } from 'styled-components'
8
9
10
+ import { ButtonOutlined , ButtonPrimary } from 'components/Button'
11
+ import InfoHelper from 'components/InfoHelper'
12
+ import Modal from 'components/Modal'
13
+ import Row , { RowBetween } from 'components/Row'
9
14
import Tab from 'components/WalletPopup/Transactions/Tab'
10
15
import { NUMBERS } from 'components/WalletPopup/Transactions/helper'
11
16
import useCancellingOrders , { CancellingOrderInfo } from 'components/swapv2/LimitOrder/useCancellingOrders'
12
17
import { useActiveWeb3React } from 'hooks'
13
18
import { fetchListTokenByAddresses , findCacheToken , useIsLoadedTokenDefault } from 'hooks/Tokens'
14
19
import { isSupportKyberDao } from 'hooks/kyberdao'
15
20
import useTheme from 'hooks/useTheme'
21
+ import { useAppDispatch } from 'state/hooks'
22
+ import { clearAllPendingTransactions } from 'state/transactions/actions'
16
23
import { useSortRecentTransactions } from 'state/transactions/hooks'
17
24
import {
18
25
TRANSACTION_GROUP ,
19
26
TransactionDetails ,
20
27
TransactionExtraInfo1Token ,
21
28
TransactionExtraInfo2Token ,
22
29
} from 'state/transactions/type'
30
+ import { MEDIA_WIDTHS } from 'theme'
23
31
24
32
import TransactionItem from './TransactionItem'
25
33
@@ -50,6 +58,28 @@ const Wrapper = styled.div`
50
58
gap: 12px;
51
59
`
52
60
61
+ const ClearTxButton = styled . div `
62
+ cursor: pointer;
63
+ color: ${ ( { theme } ) => theme . primary } ;
64
+ font-size: 14px;
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 5px;
68
+ `
69
+
70
+ const ClearTxWrapper = styled . div `
71
+ padding: 20px;
72
+ border-radius: 20px;
73
+ background-color: ${ ( { theme } ) => theme . tableHeader } ;
74
+ display: flex;
75
+ flex-direction: column;
76
+ align-items: center;
77
+ justify-content: center;
78
+ gap: 24px;
79
+ width: 100%;
80
+ color: ${ ( { theme } ) => theme . subText } ;
81
+ `
82
+
53
83
function RowItem ( {
54
84
index,
55
85
style,
@@ -107,24 +137,23 @@ function RowItem({
107
137
// This is intentional, we don't need to persist in localStorage
108
138
let storedActiveTab = ''
109
139
function ListTransaction ( { isMinimal } : { isMinimal : boolean } ) {
110
- const listTab = useMemo (
111
- ( ) => [
112
- { title : t `All` , value : '' } ,
113
- { title : t `Swaps` , value : TRANSACTION_GROUP . SWAP } ,
114
- { title : t `Liquidity` , value : TRANSACTION_GROUP . LIQUIDITY } ,
115
- { title : t `KyberDAO` , value : TRANSACTION_GROUP . KYBERDAO } ,
116
- { title : t `Others` , value : TRANSACTION_GROUP . OTHER } ,
117
- ] ,
118
- [ ] ,
119
- )
120
-
121
140
const transactions = useSortRecentTransactions ( false )
122
- const { chainId } = useActiveWeb3React ( )
123
- const [ activeTab , setActiveTab ] = useState < TRANSACTION_GROUP | string > ( storedActiveTab )
124
141
const theme = useTheme ( )
125
142
const cancellingOrderInfo = useCancellingOrders ( )
143
+ const dispatch = useAppDispatch ( )
144
+ const { chainId } = useActiveWeb3React ( )
145
+
146
+ const [ activeTab , setActiveTab ] = useState < TRANSACTION_GROUP | string > ( storedActiveTab )
147
+ const [ openClearTxModal , setOpenClearTxModal ] = useState ( false )
148
+ const upToExtraSmall = useMedia ( `(max-width: ${ MEDIA_WIDTHS . upToExtraSmall } px)` )
126
149
127
150
const listTokenAddress = useRef < string [ ] > ( [ ] )
151
+ const rowHeights = useRef < { [ key : string ] : number } > ( { } )
152
+ const listRef = useRef < any > ( null )
153
+
154
+ const total = listTokenAddress . current
155
+ const isLoadedTokenDefault = useIsLoadedTokenDefault ( )
156
+
128
157
const pushAddress = ( address : string ) => {
129
158
if ( address && ! listTokenAddress . current . includes ( address ) ) listTokenAddress . current . push ( address )
130
159
}
@@ -147,22 +176,34 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) {
147
176
return result
148
177
} , [ transactions , activeTab ] )
149
178
150
- const total = listTokenAddress . current
151
- const isLoadedTokenDefault = useIsLoadedTokenDefault ( )
152
- useEffect ( ( ) => {
153
- if ( ! isLoadedTokenDefault ) return
154
- const list : string [ ] = listTokenAddress . current . filter ( address => ! findCacheToken ( address ) )
155
- if ( list . length ) fetchListTokenByAddresses ( list , chainId ) . catch ( console . error )
156
- } , [ total , isLoadedTokenDefault , chainId ] )
179
+ const pendingTransactions = formatTransactions . filter ( tx => ! tx . receipt )
180
+
181
+ const listTab = useMemo (
182
+ ( ) => [
183
+ { title : t `All` , value : '' } ,
184
+ { title : t `Swaps` , value : TRANSACTION_GROUP . SWAP } ,
185
+ { title : t `Liquidity` , value : TRANSACTION_GROUP . LIQUIDITY } ,
186
+ { title : t `KyberDAO` , value : TRANSACTION_GROUP . KYBERDAO } ,
187
+ { title : t `Others` , value : TRANSACTION_GROUP . OTHER } ,
188
+ ] ,
189
+ [ ] ,
190
+ )
191
+
192
+ const filterTab = useMemo ( ( ) => {
193
+ return listTab . filter ( tab => {
194
+ if ( tab . value === TRANSACTION_GROUP . KYBERDAO ) {
195
+ return isSupportKyberDao ( chainId )
196
+ }
197
+ return true
198
+ } )
199
+ } , [ chainId , listTab ] )
157
200
158
201
const onRefChange = useCallback ( ( node : HTMLDivElement ) => {
159
202
if ( ! node ?. classList . contains ( 'scrollbar' ) ) {
160
203
node ?. classList . add ( 'scrollbar' )
161
204
}
162
205
} , [ ] )
163
206
164
- const rowHeights = useRef < { [ key : string ] : number } > ( { } )
165
- const listRef = useRef < any > ( null )
166
207
const setRowHeight = useCallback ( ( index : number , size : number ) => {
167
208
listRef . current ?. resetAfterIndex ( 0 )
168
209
rowHeights . current = { ...rowHeights . current , [ index ] : size }
@@ -172,59 +213,92 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) {
172
213
return rowHeights . current [ index ] || 100
173
214
}
174
215
216
+ const toggleClearTxModal = ( ) => setOpenClearTxModal ( prev => ! prev )
217
+ const onClearAllPendingTransactions = ( ) => {
218
+ dispatch ( clearAllPendingTransactions ( { chainId } ) )
219
+ toggleClearTxModal ( )
220
+ }
221
+
222
+ useEffect ( ( ) => {
223
+ if ( ! isLoadedTokenDefault ) return
224
+ const list : string [ ] = listTokenAddress . current . filter ( address => ! findCacheToken ( address ) )
225
+ if ( list . length ) fetchListTokenByAddresses ( list , chainId ) . catch ( console . error )
226
+ } , [ total , isLoadedTokenDefault , chainId ] )
227
+
175
228
useEffect ( ( ) => {
176
229
storedActiveTab = activeTab
177
230
} , [ activeTab ] )
178
231
179
- const filterTab = useMemo ( ( ) => {
180
- return listTab . filter ( tab => {
181
- if ( tab . value === TRANSACTION_GROUP . KYBERDAO ) {
182
- return isSupportKyberDao ( chainId )
183
- }
184
- return true
185
- } )
186
- } , [ chainId , listTab ] )
187
-
188
232
return (
189
- < Wrapper >
190
- < Tab < TRANSACTION_GROUP | string > activeTab = { activeTab } setActiveTab = { setActiveTab } tabs = { filterTab } />
191
- < ContentWrapper >
192
- { formatTransactions . length === 0 ? (
193
- < Flex flexDirection = "column" alignItems = "center" color = { theme . subText } sx = { { gap : 10 , marginTop : '20px' } } >
194
- < Info size = { 32 } />
195
- < Text fontSize = { '14px' } >
196
- < Trans > You have no Transaction History.</ Trans >
233
+ < >
234
+ < Modal isOpen = { openClearTxModal } onDismiss = { toggleClearTxModal } >
235
+ < ClearTxWrapper >
236
+ < RowBetween align = "start" >
237
+ < Text fontSize = { 20 } fontWeight = { 500 } color = { theme . text } >
238
+ { t `Clear All Pending Transactions` }
239
+ </ Text >
240
+ < X color = { theme . text } style = { { cursor : 'pointer' } } onClick = { toggleClearTxModal } />
241
+ </ RowBetween >
242
+ < Row gap = "12px" >
243
+ < Text fontSize = { 14 } color = { theme . text } lineHeight = "16px" >
244
+ { 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.` }
197
245
</ Text >
198
- </ Flex >
199
- ) : (
200
- < AutoSizer >
201
- { ( { height, width } ) => (
202
- < VariableSizeList
203
- height = { height }
204
- width = { width }
205
- itemSize = { getRowHeight }
206
- ref = { listRef }
207
- outerRef = { onRefChange }
208
- itemCount = { formatTransactions . length }
209
- itemData = { formatTransactions }
210
- >
211
- { ( { data, index, style } ) => (
212
- < RowItem
213
- isMinimal = { isMinimal }
214
- style = { style }
215
- transaction = { data [ index ] }
216
- index = { index }
217
- key = { data [ index ] . hash }
218
- setRowHeight = { setRowHeight }
219
- cancellingOrderInfo = { cancellingOrderInfo }
220
- />
221
- ) }
222
- </ VariableSizeList >
223
- ) }
224
- </ AutoSizer >
246
+ </ Row >
247
+ < Row gap = "16px" flexDirection = { upToExtraSmall ? 'column' : 'row' } >
248
+ < ButtonOutlined onClick = { toggleClearTxModal } > { t `Cancel` } </ ButtonOutlined >
249
+ < ButtonPrimary onClick = { onClearAllPendingTransactions } > { t `Clear All` } </ ButtonPrimary >
250
+ </ Row >
251
+ </ ClearTxWrapper >
252
+ </ Modal >
253
+ < Wrapper >
254
+ < Tab < TRANSACTION_GROUP | string > activeTab = { activeTab } setActiveTab = { setActiveTab } tabs = { filterTab } />
255
+ < ContentWrapper >
256
+ { formatTransactions . length === 0 ? (
257
+ < Flex flexDirection = "column" alignItems = "center" color = { theme . subText } sx = { { gap : 10 , marginTop : '20px' } } >
258
+ < Info size = { 32 } />
259
+ < Text fontSize = { '14px' } >
260
+ < Trans > You have no Transaction History.</ Trans >
261
+ </ Text >
262
+ </ Flex >
263
+ ) : (
264
+ < AutoSizer >
265
+ { ( { height, width } ) => (
266
+ < VariableSizeList
267
+ height = { height }
268
+ width = { width }
269
+ itemSize = { getRowHeight }
270
+ ref = { listRef }
271
+ outerRef = { onRefChange }
272
+ itemCount = { formatTransactions . length }
273
+ itemData = { formatTransactions }
274
+ >
275
+ { ( { data, index, style } ) => (
276
+ < RowItem
277
+ isMinimal = { isMinimal }
278
+ style = { style }
279
+ transaction = { data [ index ] }
280
+ index = { index }
281
+ key = { data [ index ] . hash }
282
+ setRowHeight = { setRowHeight }
283
+ cancellingOrderInfo = { cancellingOrderInfo }
284
+ />
285
+ ) }
286
+ </ VariableSizeList >
287
+ ) }
288
+ </ AutoSizer >
289
+ ) }
290
+ </ ContentWrapper >
291
+ { pendingTransactions . length !== 0 && (
292
+ < ClearTxButton >
293
+ < Text fontSize = { 14 } onClick = { toggleClearTxModal } > { t `Clear Pending Transactions` } </ Text >
294
+ < InfoHelper
295
+ color = { theme . primary }
296
+ text = { t `Manually clear this transaction from the pending list. This will not affect its on-chain status.` }
297
+ />
298
+ </ ClearTxButton >
225
299
) }
226
- </ ContentWrapper >
227
- </ Wrapper >
300
+ </ Wrapper >
301
+ </ >
228
302
)
229
303
}
230
304
0 commit comments