Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
17e3dce6
Commit
17e3dce6
authored
Jan 11, 2023
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
token transfer socket
parent
99735f0f
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
414 additions
and
179 deletions
+414
-179
buildUrl.ts
lib/api/buildUrl.ts
+1
-1
useApiFetch.tsx
lib/api/useApiFetch.tsx
+1
-1
types.ts
lib/socket/types.ts
+3
-0
AddressTokenTransfers.tsx
ui/address/AddressTokenTransfers.tsx
+208
-9
TokenTransfer.tsx
ui/shared/TokenTransfer/TokenTransfer.tsx
+0
-149
TokenTransferList.pw.tsx
ui/shared/TokenTransfer/TokenTransferList.pw.tsx
+41
-0
TokenTransferList.tsx
ui/shared/TokenTransfer/TokenTransferList.tsx
+2
-2
TokenTransferTable.pw.tsx
ui/shared/TokenTransfer/TokenTransferTable.pw.tsx
+41
-0
TokenTransferTable.tsx
ui/shared/TokenTransfer/TokenTransferTable.tsx
+25
-4
TokenTransfer.pw.tsx_default_with-tx-info-mobile-1.png
...__/TokenTransfer.pw.tsx_default_with-tx-info-mobile-1.png
+0
-0
TokenTransfer.pw.tsx_default_without-tx-info-mobile-1.png
...TokenTransfer.pw.tsx_default_without-tx-info-mobile-1.png
+0
-0
TokenTransferList.pw.tsx_default_with-tx-info-1.png
...ots__/TokenTransferList.pw.tsx_default_with-tx-info-1.png
+0
-0
TokenTransferList.pw.tsx_default_without-tx-info-1.png
...__/TokenTransferList.pw.tsx_default_without-tx-info-1.png
+0
-0
TokenTransferTable.pw.tsx_default_with-tx-info-1.png
...ts__/TokenTransferTable.pw.tsx_default_with-tx-info-1.png
+0
-0
TokenTransferTable.pw.tsx_default_without-tx-info-1.png
..._/TokenTransferTable.pw.tsx_default_without-tx-info-1.png
+0
-0
TxTokenTransfer.tsx
ui/tx/TxTokenTransfer.tsx
+92
-13
No files found.
lib/api/buildUrl.ts
View file @
17e3dce6
...
@@ -8,7 +8,7 @@ import type { ApiResource, ResourceName } from './resources';
...
@@ -8,7 +8,7 @@ import type { ApiResource, ResourceName } from './resources';
export
default
function
buildUrl
(
export
default
function
buildUrl
(
_resource
:
ApiResource
|
ResourceName
,
_resource
:
ApiResource
|
ResourceName
,
pathParams
?:
Record
<
string
,
string
|
undefined
>
,
pathParams
?:
Record
<
string
,
string
|
undefined
>
,
queryParams
?:
Record
<
string
,
string
|
number
|
undefined
>
,
queryParams
?:
Record
<
string
,
string
|
Array
<
string
>
|
number
|
undefined
>
,
)
{
)
{
// FIXME
// FIXME
// 1. I was not able to figure out how to send CORS with credentials from localhost
// 1. I was not able to figure out how to send CORS with credentials from localhost
...
...
lib/api/useApiFetch.tsx
View file @
17e3dce6
...
@@ -10,7 +10,7 @@ import type { ApiResource } from './resources';
...
@@ -10,7 +10,7 @@ import type { ApiResource } from './resources';
export
interface
Params
{
export
interface
Params
{
pathParams
?:
Record
<
string
,
string
|
undefined
>
;
pathParams
?:
Record
<
string
,
string
|
undefined
>
;
queryParams
?:
Record
<
string
,
string
|
number
|
undefined
>
;
queryParams
?:
Record
<
string
,
string
|
Array
<
string
>
|
number
|
undefined
>
;
fetchParams
?:
Pick
<
FetchParams
,
'
body
'
|
'
method
'
|
'
signal
'
>
;
fetchParams
?:
Pick
<
FetchParams
,
'
body
'
|
'
method
'
|
'
signal
'
>
;
}
}
...
...
lib/socket/types.ts
View file @
17e3dce6
...
@@ -2,6 +2,7 @@ import type { Channel } from 'phoenix';
...
@@ -2,6 +2,7 @@ import type { Channel } from 'phoenix';
import
type
{
AddressCoinBalanceHistoryItem
}
from
'
types/api/address
'
;
import
type
{
AddressCoinBalanceHistoryItem
}
from
'
types/api/address
'
;
import
type
{
NewBlockSocketResponse
}
from
'
types/api/block
'
;
import
type
{
NewBlockSocketResponse
}
from
'
types/api/block
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
type
{
Transaction
}
from
'
types/api/transaction
'
;
import
type
{
Transaction
}
from
'
types/api/transaction
'
;
export
type
SocketMessageParams
=
SocketMessage
.
NewBlock
|
export
type
SocketMessageParams
=
SocketMessage
.
NewBlock
|
...
@@ -16,6 +17,7 @@ SocketMessage.AddressTokenBalance |
...
@@ -16,6 +17,7 @@ SocketMessage.AddressTokenBalance |
SocketMessage
.
AddressCoinBalance
|
SocketMessage
.
AddressCoinBalance
|
SocketMessage
.
AddressTxs
|
SocketMessage
.
AddressTxs
|
SocketMessage
.
AddressTxsPending
|
SocketMessage
.
AddressTxsPending
|
SocketMessage
.
AddressTokenTransfer
|
SocketMessage
.
Unknown
;
SocketMessage
.
Unknown
;
interface
SocketMessageParamsGeneric
<
Event
extends
string
|
undefined
,
Payload
extends
object
|
unknown
>
{
interface
SocketMessageParamsGeneric
<
Event
extends
string
|
undefined
,
Payload
extends
object
|
unknown
>
{
...
@@ -39,5 +41,6 @@ export namespace SocketMessage {
...
@@ -39,5 +41,6 @@ export namespace SocketMessage {
export
type
AddressCoinBalance
=
SocketMessageParamsGeneric
<
'
coin_balance
'
,
{
coin_balance
:
AddressCoinBalanceHistoryItem
}
>
;
export
type
AddressCoinBalance
=
SocketMessageParamsGeneric
<
'
coin_balance
'
,
{
coin_balance
:
AddressCoinBalanceHistoryItem
}
>
;
export
type
AddressTxs
=
SocketMessageParamsGeneric
<
'
transaction
'
,
{
transaction
:
Transaction
}
>
;
export
type
AddressTxs
=
SocketMessageParamsGeneric
<
'
transaction
'
,
{
transaction
:
Transaction
}
>
;
export
type
AddressTxsPending
=
SocketMessageParamsGeneric
<
'
pending_transaction
'
,
{
transaction
:
Transaction
}
>
;
export
type
AddressTxsPending
=
SocketMessageParamsGeneric
<
'
pending_transaction
'
,
{
transaction
:
Transaction
}
>
;
export
type
AddressTokenTransfer
=
SocketMessageParamsGeneric
<
'
token_transfer
'
,
{
token_transfer
:
TokenTransfer
}
>
;
export
type
Unknown
=
SocketMessageParamsGeneric
<
undefined
,
unknown
>
;
export
type
Unknown
=
SocketMessageParamsGeneric
<
undefined
,
unknown
>
;
}
}
ui/address/AddressTokenTransfers.tsx
View file @
17e3dce6
import
{
Hide
,
Show
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
TokenTransfer
from
'
ui/shared/TokenTransfer/TokenTransfer
'
;
import
type
{
SocketMessage
}
from
'
lib/socket/types
'
;
import
{
AddressFromToFilterValues
}
from
'
types/api/address
'
;
import
type
{
AddressFromToFilter
,
AddressTokenTransferResponse
}
from
'
types/api/address
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
getFilterValueFromQuery
from
'
lib/getFilterValueFromQuery
'
;
import
getFilterValuesFromQuery
from
'
lib/getFilterValuesFromQuery
'
;
import
useQueryWithPages
from
'
lib/hooks/useQueryWithPages
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
useSocketChannel
from
'
lib/socket/useSocketChannel
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
EmptySearchResult
from
'
ui/apps/EmptySearchResult
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
SkeletonList
from
'
ui/shared/skeletons/SkeletonList
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
{
TOKEN_TYPE
,
flattenTotal
}
from
'
ui/shared/TokenTransfer/helpers
'
;
import
TokenTransferFilter
from
'
ui/shared/TokenTransfer/TokenTransferFilter
'
;
import
TokenTransferList
from
'
ui/shared/TokenTransfer/TokenTransferList
'
;
import
TokenTransferTable
from
'
ui/shared/TokenTransfer/TokenTransferTable
'
;
import
TxsNewItemNotice
from
'
ui/txs/TxsNewItemNotice
'
;
type
Filters
=
{
type
:
Array
<
TokenType
>
;
filter
:
AddressFromToFilter
|
undefined
;
}
const
TOKEN_TYPES
=
TOKEN_TYPE
.
map
(
i
=>
i
.
id
);
const
getTokenFilterValue
=
(
getFilterValuesFromQuery
<
TokenType
>
).
bind
(
null
,
TOKEN_TYPES
);
const
getAddressFilterValue
=
(
getFilterValueFromQuery
<
AddressFromToFilter
>
).
bind
(
null
,
AddressFromToFilterValues
);
const
OVERLOAD_COUNT
=
75
;
const
matchFilters
=
(
filters
:
Filters
,
tokenTransfer
:
TokenTransfer
,
address
?:
string
)
=>
{
if
(
filters
.
filter
)
{
if
(
filters
.
filter
===
'
from
'
&&
tokenTransfer
.
from
.
hash
!==
address
)
{
return
false
;
}
if
(
filters
.
filter
===
'
to
'
&&
tokenTransfer
.
to
.
hash
!==
address
)
{
return
false
;
}
}
if
(
filters
.
type
&&
filters
.
type
.
length
)
{
if
(
!
filters
.
type
.
includes
(
tokenTransfer
.
token
.
type
))
{
return
false
;
}
}
return
true
;
};
const
AddressTokenTransfers
=
({
scrollRef
}:
{
scrollRef
?:
React
.
RefObject
<
HTMLDivElement
>
})
=>
{
const
AddressTokenTransfers
=
({
scrollRef
}:
{
scrollRef
?:
React
.
RefObject
<
HTMLDivElement
>
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
const
queryClient
=
useQueryClient
();
const
currentAddress
=
router
.
query
.
id
?.
toString
();
const
[
socketAlert
,
setSocketAlert
]
=
React
.
useState
(
''
);
const
[
newItemsCount
,
setNewItemsCount
]
=
React
.
useState
(
0
);
const
[
filters
,
setFilters
]
=
React
.
useState
<
Filters
>
(
{
type
:
getTokenFilterValue
(
router
.
query
.
type
)
||
[],
filter
:
getAddressFilterValue
(
router
.
query
.
filter
)
},
);
const
{
isError
,
isLoading
,
data
,
pagination
,
onFilterChange
,
isPaginationVisible
}
=
useQueryWithPages
({
resourceName
:
'
address_token_transfers
'
,
pathParams
:
{
id
:
currentAddress
},
filters
:
filters
,
scrollRef
,
});
const
handleTypeFilterChange
=
React
.
useCallback
((
nextValue
:
Array
<
TokenType
>
)
=>
{
onFilterChange
({
...
filters
,
type
:
nextValue
});
setFilters
((
prevState
)
=>
({
...
prevState
,
type
:
nextValue
}));
},
[
filters
,
onFilterChange
]);
const
handleAddressFilterChange
=
React
.
useCallback
((
nextValue
:
string
)
=>
{
const
filterVal
=
getAddressFilterValue
(
nextValue
);
onFilterChange
({
...
filters
,
filter
:
filterVal
});
setFilters
((
prevState
)
=>
({
...
prevState
,
filter
:
filterVal
}));
},
[
filters
,
onFilterChange
]);
const
handleNewSocketMessage
:
SocketMessage
.
AddressTokenTransfer
[
'
handler
'
]
=
(
payload
)
=>
{
setSocketAlert
(
''
);
if
(
data
?.
items
&&
data
.
items
.
length
>=
OVERLOAD_COUNT
)
{
if
(
matchFilters
(
filters
,
payload
.
token_transfer
,
currentAddress
))
{
setNewItemsCount
(
prev
=>
prev
+
1
);
}
}
else
{
queryClient
.
setQueryData
(
getResourceKey
(
'
address_token_transfers
'
,
{
pathParams
:
{
id
:
router
.
query
.
id
?.
toString
()
},
queryParams
:
{
...
filters
}
}),
(
prevData
:
AddressTokenTransferResponse
|
undefined
)
=>
{
if
(
!
prevData
)
{
return
;
}
if
(
!
matchFilters
(
filters
,
payload
.
token_transfer
,
currentAddress
))
{
return
prevData
;
}
return
{
...
prevData
,
items
:
[
payload
.
token_transfer
,
...
prevData
.
items
,
],
};
});
}
};
const
handleSocketClose
=
React
.
useCallback
(()
=>
{
setSocketAlert
(
'
Connection is lost. Please click here to load new token transfers.
'
);
},
[]);
const
handleSocketError
=
React
.
useCallback
(()
=>
{
setSocketAlert
(
'
An error has occurred while fetching new token transfers. Please click here to refresh the page.
'
);
},
[]);
const
channel
=
useSocketChannel
({
topic
:
`addresses:
${
(
router
.
query
.
id
as
string
).
toLowerCase
()
}
`
,
onSocketClose
:
handleSocketClose
,
onSocketError
:
handleSocketError
,
isDisabled
:
pagination
.
page
!==
1
,
});
useSocketMessage
({
channel
,
event
:
'
token_transfer
'
,
handler
:
handleNewSocketMessage
,
});
const
numActiveFilters
=
(
filters
.
type
?.
length
||
0
)
+
(
filters
.
filter
?
1
:
0
);
const
isActionBarHidden
=
!
numActiveFilters
&&
!
data
?.
items
.
length
;
const
content
=
(()
=>
{
if
(
isLoading
)
{
return
(
<>
<
Hide
below=
"lg"
>
<
SkeletonTable
columns=
{
[
'
44px
'
,
'
185px
'
,
'
160px
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
]
}
/>
</
Hide
>
<
Show
below=
"lg"
>
<
SkeletonList
/>
</
Show
>
</>
);
}
if
(
isError
)
{
return
<
DataFetchAlert
/>;
}
if
(
!
data
.
items
?.
length
&&
!
numActiveFilters
)
{
return
<
Text
as=
"span"
>
There are no token transfers
</
Text
>;
}
if
(
!
data
.
items
?.
length
)
{
return
<
EmptySearchResult
text=
{
`Couldn${ apos }t find any token transfer that matches your query.`
}
/>;
}
const
items
=
data
.
items
.
reduce
(
flattenTotal
,
[]);
return
(
<>
<
Hide
below=
"lg"
>
<
TokenTransferTable
data=
{
items
}
baseAddress=
{
currentAddress
}
showTxInfo
top=
{
80
}
enableTimeIncrement
showSocketInfo
socketInfoAlert=
{
socketAlert
}
socketInfoNum=
{
newItemsCount
}
/>
</
Hide
>
<
Show
below=
"lg"
>
<
TxsNewItemNotice
url=
{
window
.
location
.
href
}
num=
{
newItemsCount
}
alert=
{
socketAlert
}
/>
<
TokenTransferList
data=
{
items
}
baseAddress=
{
currentAddress
}
showTxInfo
enableTimeIncrement
/>
</
Show
>
</>
);
})();
const
hash
=
router
.
query
.
id
;
return
(
return
(
<
TokenTransfer
<>
resourceName=
"address_token_transfers"
{
!
isActionBarHidden
&&
(
pathParams=
{
{
id
:
hash
?.
toString
()
}
}
<
ActionBar
mt=
{
-
6
}
>
baseAddress=
{
typeof
hash
===
'
string
'
?
hash
:
undefined
}
<
TokenTransferFilter
enableTimeIncrement
defaultTypeFilters=
{
filters
.
type
}
scrollRef=
{
scrollRef
}
onTypeFilterChange=
{
handleTypeFilterChange
}
/>
appliedFiltersNum=
{
numActiveFilters
}
withAddressFilter
onAddressFilterChange=
{
handleAddressFilterChange
}
defaultAddressFilter=
{
filters
.
filter
}
/>
{
isPaginationVisible
&&
<
Pagination
ml=
"auto"
{
...
pagination
}
/>
}
</
ActionBar
>
)
}
{
content
}
</>
);
);
};
};
...
...
ui/shared/TokenTransfer/TokenTransfer.tsx
deleted
100644 → 0
View file @
99735f0f
import
{
Hide
,
Show
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
type
{
AddressFromToFilter
}
from
'
types/api/address
'
;
import
{
AddressFromToFilterValues
}
from
'
types/api/address
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
import
type
{
PaginationFilters
}
from
'
lib/api/resources
'
;
import
type
{
Params
as
UseApiQueryParams
}
from
'
lib/api/useApiQuery
'
;
import
getFilterValueFromQuery
from
'
lib/getFilterValueFromQuery
'
;
import
getFilterValuesFromQuery
from
'
lib/getFilterValuesFromQuery
'
;
import
useQueryWithPages
from
'
lib/hooks/useQueryWithPages
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
EmptySearchResult
from
'
ui/apps/EmptySearchResult
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
SkeletonList
from
'
ui/shared/skeletons/SkeletonList
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
{
flattenTotal
}
from
'
ui/shared/TokenTransfer/helpers
'
;
import
TokenTransferFilter
from
'
ui/shared/TokenTransfer/TokenTransferFilter
'
;
import
TokenTransferList
from
'
ui/shared/TokenTransfer/TokenTransferList
'
;
import
TokenTransferTable
from
'
ui/shared/TokenTransfer/TokenTransferTable
'
;
import
{
TOKEN_TYPE
}
from
'
./helpers
'
;
const
TOKEN_TYPES
=
TOKEN_TYPE
.
map
(
i
=>
i
.
id
);
const
getTokenFilterValue
=
(
getFilterValuesFromQuery
<
TokenType
>
).
bind
(
null
,
TOKEN_TYPES
);
const
getAddressFilterValue
=
(
getFilterValueFromQuery
<
AddressFromToFilter
>
).
bind
(
null
,
AddressFromToFilterValues
);
interface
Props
<
Resource
extends
'
tx_token_transfers
'
|
'
address_token_transfers
'
>
{
isLoading
?:
boolean
;
isDisabled
?:
boolean
;
resourceName
:
Resource
;
baseAddress
?:
string
;
showTxInfo
?:
boolean
;
txHash
?:
string
;
enableTimeIncrement
?:
boolean
;
pathParams
?:
UseApiQueryParams
<
Resource
>
[
'
pathParams
'
];
scrollRef
?:
React
.
RefObject
<
HTMLDivElement
>
;
}
type
State
=
{
type
:
Array
<
TokenType
>
|
undefined
;
filter
:
AddressFromToFilter
;
}
const
TokenTransfer
=
<
Resource
extends
'
tx_token_transfers
'
|
'
address_token_transfers
'
>
(
{
isLoading
:
isLoadingProp
,
isDisabled
,
resourceName
,
baseAddress
,
showTxInfo
=
true
,
enableTimeIncrement
,
pathParams
,
scrollRef
,
}
: Props
<
Resource
>
) =
>
{
const
router
=
useRouter
();
const
[
filters
,
setFilters
]
=
React
.
useState
<
State
>
(
{
type
:
getTokenFilterValue
(
router
.
query
.
type
),
filter
:
getAddressFilterValue
(
router
.
query
.
filter
)
},
);
const
{
isError
,
isLoading
,
data
,
pagination
,
onFilterChange
,
isPaginationVisible
}
=
useQueryWithPages
({
resourceName
,
pathParams
,
options
:
{
enabled
:
!
isDisabled
},
filters
:
filters
as
PaginationFilters
<
Resource
>
,
scrollRef
,
});
const
handleTypeFilterChange
=
React
.
useCallback
((
nextValue
:
Array
<
TokenType
>
)
=>
{
onFilterChange
({
...
filters
,
type
:
nextValue
}
as
PaginationFilters
<
Resource
>
);
setFilters
((
prevState
)
=>
({
...
prevState
,
type
:
nextValue
}));
},
[
filters
,
onFilterChange
]);
const
handleAddressFilterChange
=
React
.
useCallback
((
nextValue
:
string
)
=>
{
const
filterVal
=
getAddressFilterValue
(
nextValue
);
onFilterChange
({
...
filters
,
filter
:
filterVal
}
as
PaginationFilters
<
Resource
>
);
setFilters
((
prevState
)
=>
({
...
prevState
,
filter
:
filterVal
}));
},
[
filters
,
onFilterChange
]);
const
numActiveFilters
=
(
filters
.
type
?.
length
||
0
)
+
(
filters
.
filter
?
1
:
0
);
const
isActionBarHidden
=
!
numActiveFilters
&&
!
data
?.
items
.
length
;
const
content
=
(()
=>
{
if
(
isLoading
||
isLoadingProp
)
{
return
(
<>
<
Hide
below=
"lg"
>
<
SkeletonTable
columns=
{
showTxInfo
?
[
'
44px
'
,
'
185px
'
,
'
160px
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
]
:
[
'
185px
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
]
}
/>
</
Hide
>
<
Show
below=
"lg"
>
<
SkeletonList
/>
</
Show
>
</>
);
}
if
(
isError
)
{
return
<
DataFetchAlert
/>;
}
if
(
!
data
.
items
?.
length
&&
!
numActiveFilters
)
{
return
<
Text
as=
"span"
>
There are no token transfers
</
Text
>;
}
if
(
!
data
.
items
?.
length
)
{
return
<
EmptySearchResult
text=
{
`Couldn${ apos }t find any token transfer that matches your query.`
}
/>;
}
const
items
=
data
.
items
.
reduce
(
flattenTotal
,
[]);
return
(
<>
<
Hide
below=
"lg"
>
<
TokenTransferTable
data=
{
items
}
baseAddress=
{
baseAddress
}
showTxInfo=
{
showTxInfo
}
top=
{
80
}
enableTimeIncrement=
{
enableTimeIncrement
}
/>
</
Hide
>
<
Show
below=
"lg"
>
<
TokenTransferList
data=
{
items
}
baseAddress=
{
baseAddress
}
showTxInfo=
{
showTxInfo
}
enableTimeIncrement=
{
enableTimeIncrement
}
/>
</
Show
>
</>
);
})();
return
(
<>
{
!
isActionBarHidden
&&
(
<
ActionBar
mt=
{
-
6
}
>
<
TokenTransferFilter
defaultTypeFilters=
{
filters
.
type
}
onTypeFilterChange=
{
handleTypeFilterChange
}
appliedFiltersNum=
{
numActiveFilters
}
withAddressFilter=
{
Boolean
(
baseAddress
)
}
onAddressFilterChange=
{
handleAddressFilterChange
}
defaultAddressFilter=
{
filters
.
filter
}
/>
{
isPaginationVisible
&&
<
Pagination
ml=
"auto"
{
...
pagination
}
/>
}
</
ActionBar
>
)
}
{
content
}
</>
);
}
;
export default React.memo(TokenTransfer);
ui/shared/TokenTransfer/TokenTransferList.pw.tsx
0 → 100644
View file @
17e3dce6
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
{
test
,
expect
,
devices
}
from
'
@playwright/experimental-ct-react
'
;
import
React
from
'
react
'
;
import
*
as
tokenTransferMock
from
'
mocks/tokens/tokenTransfer
'
;
import
TestApp
from
'
playwright/TestApp
'
;
import
{
flattenTotal
}
from
'
./helpers
'
;
import
TokenTransferList
from
'
./TokenTransferList
'
;
const
flattenData
=
tokenTransferMock
.
mixTokens
.
items
.
reduce
(
flattenTotal
,
[]);
test
.
use
({
viewport
:
devices
[
'
iPhone 13 Pro
'
].
viewport
});
test
(
'
without tx info
'
,
async
({
mount
})
=>
{
const
component
=
await
mount
(
<
TestApp
>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
TokenTransferList
data=
{
flattenData
}
showTxInfo=
{
false
}
/>
</
TestApp
>,
);
await
expect
(
component
).
toHaveScreenshot
();
});
test
(
'
with tx info
'
,
async
({
mount
})
=>
{
const
component
=
await
mount
(
<
TestApp
>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
TokenTransferList
data=
{
flattenData
}
showTxInfo=
{
true
}
/>
</
TestApp
>,
);
await
expect
(
component
).
toHaveScreenshot
();
});
ui/shared/TokenTransfer/TokenTransferList.tsx
View file @
17e3dce6
...
@@ -15,9 +15,9 @@ interface Props {
...
@@ -15,9 +15,9 @@ interface Props {
const
TokenTransferList
=
({
data
,
baseAddress
,
showTxInfo
,
enableTimeIncrement
}:
Props
)
=>
{
const
TokenTransferList
=
({
data
,
baseAddress
,
showTxInfo
,
enableTimeIncrement
}:
Props
)
=>
{
return
(
return
(
<
Box
>
<
Box
>
{
data
.
map
((
item
,
index
)
=>
(
{
data
.
map
((
item
)
=>
(
// eslint-disable-next-line react/jsx-key
<
TokenTransferListItem
<
TokenTransferListItem
key=
{
index
}
{
...
item
}
{
...
item
}
baseAddress=
{
baseAddress
}
baseAddress=
{
baseAddress
}
showTxInfo=
{
showTxInfo
}
showTxInfo=
{
showTxInfo
}
...
...
ui/shared/TokenTransfer/TokenTransfer.pw.tsx
→
ui/shared/TokenTransfer/TokenTransfer
Table
.pw.tsx
View file @
17e3dce6
...
@@ -4,24 +4,19 @@ import React from 'react';
...
@@ -4,24 +4,19 @@ import React from 'react';
import
*
as
tokenTransferMock
from
'
mocks/tokens/tokenTransfer
'
;
import
*
as
tokenTransferMock
from
'
mocks/tokens/tokenTransfer
'
;
import
TestApp
from
'
playwright/TestApp
'
;
import
TestApp
from
'
playwright/TestApp
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
TokenTransfer
from
'
./TokenTransfer
'
;
import
{
flattenTotal
}
from
'
./helpers
'
;
import
TokenTransferTable
from
'
./TokenTransferTable
'
;
const
API_URL
=
buildApiUrl
(
'
tx_token_transfers
'
,
{
id
:
'
1
'
});
const
flattenData
=
tokenTransferMock
.
mixTokens
.
items
.
reduce
(
flattenTotal
,
[]);
test
(
'
without tx info +@mobile
'
,
async
({
mount
,
page
})
=>
{
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
(
tokenTransferMock
.
mixTokens
),
}));
test
(
'
without tx info
'
,
async
({
mount
})
=>
{
const
component
=
await
mount
(
const
component
=
await
mount
(
<
TestApp
>
<
TestApp
>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
TokenTransfer
<
TokenTransfer
Table
resourceName=
"tx_token_transfers"
data=
{
flattenData
}
pathParams=
{
{
id
:
'
1
'
}
}
top=
{
0
}
showTxInfo=
{
false
}
showTxInfo=
{
false
}
/>
/>
</
TestApp
>,
</
TestApp
>,
...
@@ -30,18 +25,13 @@ test('without tx info +@mobile', async({ mount, page }) => {
...
@@ -30,18 +25,13 @@ test('without tx info +@mobile', async({ mount, page }) => {
await
expect
(
component
).
toHaveScreenshot
();
await
expect
(
component
).
toHaveScreenshot
();
});
});
test
(
'
with tx info +@mobile
'
,
async
({
mount
,
page
})
=>
{
test
(
'
with tx info
'
,
async
({
mount
})
=>
{
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
(
tokenTransferMock
.
mixTokens
),
}));
const
component
=
await
mount
(
const
component
=
await
mount
(
<
TestApp
>
<
TestApp
>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
Box
h=
{
{
base
:
'
134px
'
,
lg
:
6
}
}
/>
<
TokenTransfer
<
TokenTransfer
Table
resourceName=
"tx_token_transfers"
data=
{
flattenData
}
pathParams=
{
{
id
:
'
1
'
}
}
top=
{
0
}
showTxInfo=
{
true
}
showTxInfo=
{
true
}
/>
/>
</
TestApp
>,
</
TestApp
>,
...
...
ui/shared/TokenTransfer/TokenTransferTable.tsx
View file @
17e3dce6
import
{
Table
,
Tbody
,
Tr
,
Th
}
from
'
@chakra-ui/react
'
;
import
{
Table
,
Tbody
,
Tr
,
Th
,
Td
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
{
default
as
Thead
}
from
'
ui/shared/TheadSticky
'
;
import
{
default
as
Thead
}
from
'
ui/shared/TheadSticky
'
;
import
TokenTransferTableItem
from
'
ui/shared/TokenTransfer/TokenTransferTableItem
'
;
import
TokenTransferTableItem
from
'
ui/shared/TokenTransfer/TokenTransferTableItem
'
;
import
TxsNewItemNotice
from
'
ui/txs/TxsNewItemNotice
'
;
interface
Props
{
interface
Props
{
data
:
Array
<
TokenTransfer
>
;
data
:
Array
<
TokenTransfer
>
;
...
@@ -12,9 +13,21 @@ interface Props {
...
@@ -12,9 +13,21 @@ interface Props {
showTxInfo
?:
boolean
;
showTxInfo
?:
boolean
;
top
:
number
;
top
:
number
;
enableTimeIncrement
?:
boolean
;
enableTimeIncrement
?:
boolean
;
showSocketInfo
?:
boolean
;
socketInfoAlert
?:
string
;
socketInfoNum
?:
number
;
}
}
const
TokenTransferTable
=
({
data
,
baseAddress
,
showTxInfo
,
top
,
enableTimeIncrement
}:
Props
)
=>
{
const
TokenTransferTable
=
({
data
,
baseAddress
,
showTxInfo
,
top
,
enableTimeIncrement
,
showSocketInfo
,
socketInfoAlert
,
socketInfoNum
,
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
size=
"sm"
>
<
Table
variant=
"simple"
size=
"sm"
>
...
@@ -31,8 +44,16 @@ const TokenTransferTable = ({ data, baseAddress, showTxInfo, top, enableTimeIncr
...
@@ -31,8 +44,16 @@ const TokenTransferTable = ({ data, baseAddress, showTxInfo, top, enableTimeIncr
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
,
index
)
=>
(
{
showSocketInfo
&&
(
<
TokenTransferTableItem
key=
{
index
}
{
...
item
}
baseAddress=
{
baseAddress
}
showTxInfo=
{
showTxInfo
}
enableTimeIncrement=
{
enableTimeIncrement
}
/>
<
Tr
>
<
Td
colSpan=
{
10
}
p=
{
0
}
>
<
TxsNewItemNotice
borderRadius=
{
0
}
pl=
"10px"
url=
{
window
.
location
.
href
}
alert=
{
socketInfoAlert
}
num=
{
socketInfoNum
}
/>
</
Td
>
</
Tr
>
)
}
{
data
.
map
((
item
)
=>
(
// eslint-disable-next-line react/jsx-key
<
TokenTransferTableItem
{
...
item
}
baseAddress=
{
baseAddress
}
showTxInfo=
{
showTxInfo
}
enableTimeIncrement=
{
enableTimeIncrement
}
/>
))
}
))
}
</
Tbody
>
</
Tbody
>
</
Table
>
</
Table
>
...
...
ui/shared/TokenTransfer/__screenshots__/TokenTransfer.pw.tsx_default_with-tx-info-mobile-1.png
deleted
100644 → 0
View file @
99735f0f
95.1 KB
ui/shared/TokenTransfer/__screenshots__/TokenTransfer.pw.tsx_default_without-tx-info-mobile-1.png
deleted
100644 → 0
View file @
99735f0f
77.8 KB
ui/shared/TokenTransfer/__screenshots__/TokenTransferList.pw.tsx_default_with-tx-info-1.png
0 → 100644
View file @
17e3dce6
97.4 KB
ui/shared/TokenTransfer/__screenshots__/TokenTransferList.pw.tsx_default_without-tx-info-1.png
0 → 100644
View file @
17e3dce6
77.4 KB
ui/shared/TokenTransfer/__screenshots__/TokenTransferTable.pw.tsx_default_with-tx-info-1.png
0 → 100644
View file @
17e3dce6
93.4 KB
ui/shared/TokenTransfer/__screenshots__/TokenTransferTable.pw.tsx_default_without-tx-info-1.png
0 → 100644
View file @
17e3dce6
76.1 KB
ui/tx/TxTokenTransfer.tsx
View file @
17e3dce6
import
{
Hide
,
Show
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
import
{
SECOND
}
from
'
lib/consts
'
;
import
{
SECOND
}
from
'
lib/consts
'
;
import
getFilterValuesFromQuery
from
'
lib/getFilterValuesFromQuery
'
;
import
useQueryWithPages
from
'
lib/hooks/useQueryWithPages
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
EmptySearchResult
from
'
ui/apps/EmptySearchResult
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
TokenTransfer
from
'
ui/shared/TokenTransfer/TokenTransfer
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
SkeletonList
from
'
ui/shared/skeletons/SkeletonList
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
{
TOKEN_TYPE
,
flattenTotal
}
from
'
ui/shared/TokenTransfer/helpers
'
;
import
TokenTransferFilter
from
'
ui/shared/TokenTransfer/TokenTransferFilter
'
;
import
TokenTransferList
from
'
ui/shared/TokenTransfer/TokenTransferList
'
;
import
TokenTransferTable
from
'
ui/shared/TokenTransfer/TokenTransferTable
'
;
import
TxPendingAlert
from
'
ui/tx/TxPendingAlert
'
;
import
TxPendingAlert
from
'
ui/tx/TxPendingAlert
'
;
import
TxSocketAlert
from
'
ui/tx/TxSocketAlert
'
;
import
TxSocketAlert
from
'
ui/tx/TxSocketAlert
'
;
import
useFetchTxInfo
from
'
ui/tx/useFetchTxInfo
'
;
import
useFetchTxInfo
from
'
ui/tx/useFetchTxInfo
'
;
const
TOKEN_TYPES
=
TOKEN_TYPE
.
map
(
i
=>
i
.
id
);
const
getTokenFilterValue
=
(
getFilterValuesFromQuery
<
TokenType
>
).
bind
(
null
,
TOKEN_TYPES
);
const
TxTokenTransfer
=
()
=>
{
const
TxTokenTransfer
=
()
=>
{
const
{
isError
,
isLoading
,
data
,
socketStatus
}
=
useFetchTxInfo
({
updateDelay
:
5
*
SECOND
});
const
txsInfo
=
useFetchTxInfo
({
updateDelay
:
5
*
SECOND
});
const
router
=
useRouter
();
const
[
typeFilter
,
setTypeFilter
]
=
React
.
useState
<
Array
<
TokenType
>>
(
getTokenFilterValue
(
router
.
query
.
type
)
||
[]);
const
tokenTransferQuery
=
useQueryWithPages
({
resourceName
:
'
tx_token_transfers
'
,
pathParams
:
{
id
:
txsInfo
.
data
?.
hash
.
toString
()
},
options
:
{
enabled
:
Boolean
(
txsInfo
.
data
?.
status
&&
txsInfo
.
data
?.
hash
)
},
filters
:
{
type
:
typeFilter
},
});
if
(
!
isLoading
&&
!
isError
&&
!
data
.
status
)
{
const
handleTypeFilterChange
=
React
.
useCallback
((
nextValue
:
Array
<
TokenType
>
)
=>
{
return
socketStatus
?
<
TxSocketAlert
status=
{
socketStatus
}
/>
:
<
TxPendingAlert
/>;
tokenTransferQuery
.
onFilterChange
({
type
:
nextValue
});
setTypeFilter
(
nextValue
);
},
[
tokenTransferQuery
]);
if
(
!
txsInfo
.
isLoading
&&
!
txsInfo
.
isError
&&
!
txsInfo
.
data
.
status
)
{
return
txsInfo
.
socketStatus
?
<
TxSocketAlert
status=
{
txsInfo
.
socketStatus
}
/>
:
<
TxPendingAlert
/>;
}
}
if
(
isError
)
{
if
(
txsInfo
.
isError
||
tokenTransferQuery
.
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
numActiveFilters
=
typeFilter
.
length
;
const
isActionBarHidden
=
!
numActiveFilters
&&
!
tokenTransferQuery
.
data
?.
items
.
length
;
const
content
=
(()
=>
{
if
(
txsInfo
.
isLoading
||
tokenTransferQuery
.
isLoading
)
{
return
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
SkeletonTable
columns=
{
[
'
185px
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
,
'
25%
'
]
}
/>
</
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
<
SkeletonList
/>
</
Show
>
</>
);
}
if
(
!
tokenTransferQuery
.
data
.
items
?.
length
&&
!
numActiveFilters
)
{
return
<
Text
as=
"span"
>
There are no token transfers
</
Text
>;
}
if
(
!
tokenTransferQuery
.
data
.
items
?.
length
)
{
return
<
EmptySearchResult
text=
{
`Couldn${ apos }t find any token transfer that matches your query.`
}
/>;
}
const
items
=
tokenTransferQuery
.
data
.
items
.
reduce
(
flattenTotal
,
[]);
return
(
<>
<
Hide
below=
"lg"
>
<
TokenTransferTable
data=
{
items
}
top=
{
80
}
/>
</
Hide
>
<
Show
below=
"lg"
>
<
TokenTransferList
data=
{
items
}
/>
</
Show
>
</>
);
})();
return
(
return
(
<
TokenTransfer
<>
isLoading=
{
isLoading
}
{
!
isActionBarHidden
&&
(
isDisabled=
{
!
data
?.
status
||
!
data
?.
hash
}
<
ActionBar
mt=
{
-
6
}
>
resourceName=
"tx_token_transfers"
<
TokenTransferFilter
pathParams=
{
{
id
:
data
?.
hash
.
toString
()
}
}
defaultTypeFilters=
{
typeFilter
}
showTxInfo=
{
false
}
onTypeFilterChange=
{
handleTypeFilterChange
}
txHash=
{
data
?.
hash
||
''
}
appliedFiltersNum=
{
numActiveFilters
}
/>
/>
{
tokenTransferQuery
.
isPaginationVisible
&&
<
Pagination
ml=
"auto"
{
...
tokenTransferQuery
.
pagination
}
/>
}
</
ActionBar
>
)
}
{
content
}
</>
);
);
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment