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
cced383d
Commit
cced383d
authored
Dec 20, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
watchlist resource
parent
375a8b46
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
87 additions
and
37 deletions
+87
-37
resources.ts
lib/api/resources.ts
+8
-0
useApiFetch.tsx
lib/api/useApiFetch.tsx
+1
-1
useApiQuery.tsx
lib/api/useApiQuery.tsx
+6
-8
account.ts
types/api/account.ts
+6
-0
Watchlist.tsx
ui/pages/Watchlist.tsx
+32
-7
AddressForm.tsx
ui/watchlist/AddressModal/AddressForm.tsx
+15
-11
DeleteAddressModal.tsx
ui/watchlist/DeleteAddressModal.tsx
+7
-4
WatchListItem.tsx
ui/watchlist/WatchlistTable/WatchListItem.tsx
+6
-3
WatchListTableItem.tsx
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
+6
-3
No files found.
lib/api/resources.ts
View file @
cced383d
...
...
@@ -12,6 +12,14 @@ export const RESOURCES = {
custom_abi
:
{
path
:
'
/api/account/v1/user/custom_abis/:id?
'
,
},
watchlist
:
{
path
:
'
/api/account/v1/user/watchlist/:id?
'
,
},
// DEPRECATED
old_api
:
{
path
:
'
/api
'
,
},
};
export
const
resourceKey
=
(
x
:
keyof
typeof
RESOURCES
)
=>
x
;
...
...
lib/api/useApiFetch.tsx
View file @
cced383d
...
...
@@ -6,7 +6,7 @@ import useFetch from 'lib/hooks/useFetch';
import
buildUrl
from
'
./buildUrl
'
;
import
type
{
RESOURCES
,
ResourcePayload
,
ResourceError
}
from
'
./resources
'
;
interface
Params
{
export
interface
Params
{
pathParams
?:
Record
<
string
,
string
>
;
queryParams
?:
Record
<
string
,
string
>
;
fetchParams
?:
Pick
<
FetchParams
,
'
body
'
|
'
method
'
>
;
...
...
lib/api/useApiQuery.tsx
View file @
cced383d
import
type
{
UseQueryOptions
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
useFetch
from
'
lib/hooks/useFetch
'
;
import
buildUrl
from
'
./buildUrl
'
;
import
type
{
RESOURCES
,
ResourcePayload
,
ResourceError
}
from
'
./resources
'
;
import
type
{
Params
as
ApiFetchParams
}
from
'
./useApiFetch
'
;
import
useApiFetch
from
'
./useApiFetch
'
;
interface
Params
<
R
extends
keyof
typeof
RESOURCES
>
{
interface
Params
<
R
extends
keyof
typeof
RESOURCES
>
extends
ApiFetchParams
{
queryOptions
?:
Omit
<
UseQueryOptions
<
unknown
,
ResourceError
,
ResourcePayload
<
R
>>
,
'
queryKey
'
|
'
queryFn
'
>
;
}
export
default
function
useApiQuery
<
R
extends
keyof
typeof
RESOURCES
>
(
resource
:
R
,
{
queryOptions
}:
Params
<
R
>
=
{},
{
queryOptions
,
pathParams
,
queryParams
,
fetchParams
}:
Params
<
R
>
=
{},
)
{
const
fetch
=
use
Fetch
();
const
apiFetch
=
useApi
Fetch
();
return
useQuery
<
unknown
,
ResourceError
,
ResourcePayload
<
R
>>
([
resource
],
async
()
=>
{
const
url
=
buildUrl
(
resource
);
return
fetch
(
url
,
{
credentials
:
'
include
'
});
return
apiFetch
(
resource
,
{
pathParams
,
queryParams
,
fetchParams
});
},
queryOptions
);
}
types/api/account.ts
View file @
cced383d
...
...
@@ -67,6 +67,12 @@ export interface WatchlistAddress {
address
?:
AddressParam
;
}
export
interface
WatchlistTokensResponse
{
message
:
string
;
result
?:
Array
<
unknown
>
;
status
:
string
;
}
export
interface
WatchlistAddressNew
{
addressName
:
string
;
notificationSettings
:
NotificationSettings
;
...
...
ui/pages/Watchlist.tsx
View file @
cced383d
...
...
@@ -2,10 +2,11 @@ import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
import
{
useQuery
,
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
WatchlistAddress
,
WatchlistTokensResponse
}
from
'
types/api/account
'
;
import
type
{
TWatchlist
,
TWatchlistItem
}
from
'
types/client/account
'
;
import
{
QueryKeys
}
from
'
types/client/accountQueries
'
;
import
useFetch
from
'
lib/hooks/useFetch
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
...
...
@@ -20,14 +21,38 @@ import WatchListItem from 'ui/watchlist/WatchlistTable/WatchListItem';
import
WatchlistTable
from
'
ui/watchlist/WatchlistTable/WatchlistTable
'
;
const
WatchList
:
React
.
FC
=
()
=>
{
const
{
data
,
isLoading
,
isError
}
=
useQuery
<
unknown
,
unknown
,
TWatchlist
>
([
QueryKeys
.
watchlist
],
async
()
=>
fetch
(
'
/node-api/account/watchlist/get-with-tokens
'
));
const
apiFetch
=
useApiFetch
();
const
{
data
,
isLoading
,
isError
}
=
useQuery
<
unknown
,
unknown
,
TWatchlist
>
([
resourceKey
(
'
watchlist
'
)
],
async
()
=>
{
try
{
const
watchlistAddresses
=
await
apiFetch
<
'
watchlist
'
,
Array
<
WatchlistAddress
>>
(
'
watchlist
'
);
if
(
!
Array
.
isArray
(
watchlistAddresses
))
{
throw
Error
();
}
const
watchlistTokens
=
await
Promise
.
all
(
watchlistAddresses
.
map
(({
address
})
=>
{
if
(
!
address
?.
hash
)
{
return
Promise
.
resolve
(
0
);
}
return
apiFetch
<
'
old_api
'
,
WatchlistTokensResponse
>
(
'
old_api
'
,
{
queryParams
:
{
address
:
address
.
hash
,
module
:
'
account
'
,
action
:
'
tokenlist
'
}
})
.
then
((
response
)
=>
{
if
(
'
result
'
in
response
&&
Array
.
isArray
(
response
.
result
))
{
return
response
.
result
.
length
;
}
return
0
;
});
}));
return
watchlistAddresses
.
map
((
item
,
index
)
=>
({
...
item
,
tokens_count
:
watchlistTokens
[
index
]
}));
}
catch
(
error
)
{
return
error
;
}
});
const
queryClient
=
useQueryClient
();
const
addressModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
fetch
=
useFetch
();
useRedirectForInvalidAuthToken
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
TWatchlistItem
>
();
...
...
@@ -44,7 +69,7 @@ const WatchList: React.FC = () => {
},
[
addressModalProps
]);
const
onAddOrEditSuccess
=
useCallback
(
async
()
=>
{
await
queryClient
.
refetchQueries
([
QueryKeys
.
watchlist
]);
await
queryClient
.
refetchQueries
([
resourceKey
(
'
watchlist
'
)
]);
setAddressModalData
(
undefined
);
addressModalProps
.
onClose
();
},
[
addressModalProps
,
queryClient
]);
...
...
@@ -60,7 +85,7 @@ const WatchList: React.FC = () => {
},
[
deleteModalProps
]);
const
onDeleteSuccess
=
useCallback
(
async
()
=>
{
queryClient
.
setQueryData
([
QueryKeys
.
watchlist
],
(
prevData
:
TWatchlist
|
undefined
)
=>
{
queryClient
.
setQueryData
([
resourceKey
(
'
watchlist
'
)
],
(
prevData
:
TWatchlist
|
undefined
)
=>
{
return
prevData
?.
filter
((
item
)
=>
item
.
id
!==
deleteModalData
?.
id
);
});
},
[
deleteModalData
?.
id
,
queryClient
]);
...
...
ui/watchlist/AddressModal/AddressForm.tsx
View file @
cced383d
...
...
@@ -12,9 +12,9 @@ import { useForm, Controller } from 'react-hook-form';
import
type
{
WatchlistErrors
}
from
'
types/api/account
'
;
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
type
{
ErrorType
}
from
'
lib/hooks/useFetch
'
;
import
useFetch
from
'
lib/hooks/useFetch
'
;
import
{
ADDRESS_REGEXP
}
from
'
lib/validations/address
'
;
import
AddressInput
from
'
ui/shared/AddressInput
'
;
import
CheckboxInput
from
'
ui/shared/CheckboxInput
'
;
...
...
@@ -83,7 +83,7 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
mode
:
'
onTouched
'
,
});
const
fetch
=
use
Fetch
();
const
apiFetch
=
useApi
Fetch
();
function
updateWatchlist
(
formData
:
Inputs
)
{
const
body
=
{
...
...
@@ -96,11 +96,14 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
};
if
(
!
isAdd
&&
data
)
{
// edit address
return
fetch
<
TWatchlistItem
,
WatchlistErrors
>
(
`/node-api/account/watchlist/
${
data
.
id
}
`
,
{
method
:
'
PUT
'
,
body
});
return
apiFetch
(
'
watchlist
'
,
{
pathParams
:
{
id
:
data
?.
id
||
''
},
fetchParams
:
{
method
:
'
PUT
'
,
body
},
});
}
else
{
// add address
return
fetch
<
TWatchlistItem
,
WatchlistErrors
>
(
'
/node-api/account/watchlist
'
,
{
method
:
'
POST
'
,
body
});
return
apiFetch
(
'
watchlist
'
,
{
fetchParams
:
{
method
:
'
POST
'
,
body
}
});
}
}
...
...
@@ -109,13 +112,14 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
await
onSuccess
();
setPending
(
false
);
},
onError
:
(
e
:
ErrorType
<
WatchlistErrors
>
)
=>
{
onError
:
(
e
rror
:
ResourceError
<
{
errors
:
WatchlistErrors
}
>
)
=>
{
setPending
(
false
);
if
(
e
?.
error
?.
address_hash
||
e
?.
error
?.
name
)
{
e
?.
error
?.
address_hash
&&
setError
(
'
address
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
e
.
error
,
'
address_hash
'
)
});
e
?.
error
?.
name
&&
setError
(
'
tag
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
e
.
error
,
'
name
'
)
});
}
else
if
(
e
?.
error
?.
watchlist_id
)
{
setError
(
'
address
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
e
.
error
,
'
watchlist_id
'
)
});
const
errorMap
=
error
.
payload
?.
errors
;
if
(
errorMap
?.
address_hash
||
errorMap
?.
name
)
{
errorMap
?.
address_hash
&&
setError
(
'
address
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
address_hash
'
)
});
errorMap
?.
name
&&
setError
(
'
tag
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
name
'
)
});
}
else
if
(
errorMap
?.
watchlist_id
)
{
setError
(
'
address
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
watchlist_id
'
)
});
}
else
{
setAlertVisible
(
true
);
}
...
...
ui/watchlist/DeleteAddressModal.tsx
View file @
cced383d
...
...
@@ -3,7 +3,7 @@ import React, { useCallback } from 'react';
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
use
Fetch
from
'
lib/hooks/use
Fetch
'
;
import
use
ApiFetch
from
'
lib/api/useApi
Fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
...
...
@@ -16,11 +16,14 @@ type Props = {
const
DeleteAddressModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClose
,
onSuccess
,
data
})
=>
{
const
isMobile
=
useIsMobile
();
const
fetch
=
use
Fetch
();
const
apiFetch
=
useApi
Fetch
();
const
mutationFn
=
useCallback
(()
=>
{
return
fetch
(
`/node-api/account/watchlist/
${
data
?.
id
}
`, { method: 'DELETE' });
}, [ data?.id, fetch ]);
return
apiFetch
(
'
custom_abi
'
,
{
pathParams
:
{
id
:
data
.
id
},
fetchParams
:
{
method
:
'
DELETE
'
},
});
},
[
data
?.
id
,
apiFetch
]);
const
address
=
data
?.
address_hash
;
...
...
ui/watchlist/WatchlistTable/WatchListItem.tsx
View file @
cced383d
...
...
@@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react';
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
use
Fetch
from
'
lib/hooks/use
Fetch
'
;
import
use
ApiFetch
from
'
lib/api/useApi
Fetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
...
...
@@ -29,7 +29,7 @@ const WatchListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
},
[
item
,
onDeleteClick
]);
const
errorToast
=
useToast
();
const
fetch
=
use
Fetch
();
const
apiFetch
=
useApi
Fetch
();
const
showErrorToast
=
useCallback
(()
=>
{
errorToast
({
...
...
@@ -61,7 +61,10 @@ const WatchListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
setSwitchDisabled
(
true
);
const
body
=
{
...
item
,
notification_methods
:
{
email
:
!
notificationEnabled
}
};
setNotificationEnabled
(
prevState
=>
!
prevState
);
return
fetch
(
`/node-api/account/watchlist/
${
item
.
id
}
`
,
{
method
:
'
PUT
'
,
body
});
return
apiFetch
(
'
watchlist
'
,
{
pathParams
:
{
id
:
item
.
id
},
fetchParams
:
{
method
:
'
PUT
'
,
body
},
});
},
{
onError
:
()
=>
{
showErrorToast
();
...
...
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
View file @
cced383d
...
...
@@ -9,7 +9,7 @@ import React, { useCallback, useState } from 'react';
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
use
Fetch
from
'
lib/hooks/use
Fetch
'
;
import
use
ApiFetch
from
'
lib/api/useApi
Fetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
...
...
@@ -34,7 +34,7 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
},
[
item
,
onDeleteClick
]);
const
errorToast
=
useToast
();
const
fetch
=
use
Fetch
();
const
apiFetch
=
useApi
Fetch
();
const
showErrorToast
=
useCallback
(()
=>
{
errorToast
({
...
...
@@ -66,7 +66,10 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
setSwitchDisabled
(
true
);
const
body
=
{
...
item
,
notification_methods
:
{
email
:
!
notificationEnabled
}
};
setNotificationEnabled
(
prevState
=>
!
prevState
);
return
fetch
(
`/node-api/account/watchlist/
${
item
.
id
}
`
,
{
method
:
'
PUT
'
,
body
});
return
apiFetch
(
'
watchlist
'
,
{
pathParams
:
{
id
:
item
.
id
},
fetchParams
:
{
method
:
'
PUT
'
,
body
},
});
},
{
onError
:
()
=>
{
showErrorToast
();
...
...
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