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
7bfbb3a1
Commit
7bfbb3a1
authored
May 07, 2024
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove old public tags page
parent
3acc8615
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1 addition
and
1033 deletions
+1
-1033
resources.ts
lib/api/resources.ts
+0
-6
useNavItems.tsx
lib/hooks/useNavItems.tsx
+0
-6
getPageOgType.ts
lib/metadata/getPageOgType.ts
+0
-1
description.ts
lib/metadata/templates/description.ts
+0
-1
title.ts
lib/metadata/templates/title.ts
+0
-1
getPageType.ts
lib/mixpanel/getPageType.ts
+0
-1
nextjs-routes.d.ts
nextjs/nextjs-routes.d.ts
+0
-1
redirects.js
nextjs/redirects.js
+0
-12
public-tags-request.tsx
pages/account/public-tags-request.tsx
+0
-19
account.ts
stubs/account.ts
+1
-14
account.ts
types/api/account.ts
+0
-25
PublicTags.tsx
ui/pages/PublicTags.tsx
+0
-103
DeletePublicTagModal.tsx
ui/publicTags/DeletePublicTagModal.tsx
+0
-109
PublicTagListItem.tsx
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
+0
-59
PublicTagTable.tsx
ui/publicTags/PublicTagTable/PublicTagTable.tsx
+0
-47
PublicTagTableItem.tsx
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
+0
-66
PublicTagsData.tsx
ui/publicTags/PublicTagsData.tsx
+0
-104
PublicTagFormAction.tsx
ui/publicTags/PublicTagsForm/PublicTagFormAction.tsx
+0
-36
PublicTagFormAddressInput.tsx
ui/publicTags/PublicTagsForm/PublicTagFormAddressInput.tsx
+0
-78
PublicTagFormComment.tsx
ui/publicTags/PublicTagsForm/PublicTagFormComment.tsx
+0
-43
PublicTagsForm.tsx
ui/publicTags/PublicTagsForm/PublicTagsForm.tsx
+0
-250
PublicTagsFormInput.tsx
ui/publicTags/PublicTagsForm/PublicTagsFormInput.tsx
+0
-51
No files found.
lib/api/resources.ts
View file @
7bfbb3a1
...
...
@@ -2,7 +2,6 @@ import { getFeaturePayload } from 'configs/app/features/types';
import
type
{
UserInfo
,
CustomAbis
,
PublicTags
,
ApiKeys
,
VerifiedAddressResponse
,
TokenInfoApplicationConfig
,
...
...
@@ -147,10 +146,6 @@ export const RESOURCES = {
pathParams
:
[
'
id
'
as
const
],
filterFields
:
[
],
},
public_tags
:
{
path
:
'
/api/account/v2/user/public_tags/:id?
'
,
pathParams
:
[
'
id
'
as
const
],
},
private_tags_address
:
{
path
:
'
/api/account/v2/user/tags/address/:id?
'
,
pathParams
:
[
'
id
'
as
const
],
...
...
@@ -863,7 +858,6 @@ export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>
export
type
ResourcePayloadA
<
Q
extends
ResourceName
>
=
Q
extends
'
user_info
'
?
UserInfo
:
Q
extends
'
custom_abi
'
?
CustomAbis
:
Q
extends
'
public_tags
'
?
PublicTags
:
Q
extends
'
private_tags_address
'
?
AddressTagsResponse
:
Q
extends
'
private_tags_tx
'
?
TransactionTagsResponse
:
Q
extends
'
api_keys
'
?
ApiKeys
:
...
...
lib/hooks/useNavItems.tsx
View file @
7bfbb3a1
...
...
@@ -255,12 +255,6 @@ export default function useNavItems(): ReturnType {
icon
:
'
privattags
'
,
isActive
:
pathname
===
'
/account/tag-address
'
,
},
{
text
:
'
Public tags
'
,
nextRoute
:
{
pathname
:
'
/account/public-tags-request
'
as
const
},
icon
:
'
publictags
'
,
isActive
:
pathname
===
'
/account/public-tags-request
'
,
},
{
text
:
'
API keys
'
,
nextRoute
:
{
pathname
:
'
/account/api-key
'
as
const
},
...
...
lib/metadata/getPageOgType.ts
View file @
7bfbb3a1
...
...
@@ -27,7 +27,6 @@ const OG_TYPE_DICT: Record<Route['pathname'], OGPageType> = {
'
/account/watchlist
'
:
'
Regular page
'
,
'
/account/api-key
'
:
'
Regular page
'
,
'
/account/custom-abi
'
:
'
Regular page
'
,
'
/account/public-tags-request
'
:
'
Regular page
'
,
'
/account/tag-address
'
:
'
Regular page
'
,
'
/account/verified-addresses
'
:
'
Root page
'
,
'
/withdrawals
'
:
'
Root page
'
,
...
...
lib/metadata/templates/description.ts
View file @
7bfbb3a1
...
...
@@ -30,7 +30,6 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'
/account/watchlist
'
:
DEFAULT_TEMPLATE
,
'
/account/api-key
'
:
DEFAULT_TEMPLATE
,
'
/account/custom-abi
'
:
DEFAULT_TEMPLATE
,
'
/account/public-tags-request
'
:
DEFAULT_TEMPLATE
,
'
/account/tag-address
'
:
DEFAULT_TEMPLATE
,
'
/account/verified-addresses
'
:
DEFAULT_TEMPLATE
,
'
/withdrawals
'
:
DEFAULT_TEMPLATE
,
...
...
lib/metadata/templates/title.ts
View file @
7bfbb3a1
...
...
@@ -25,7 +25,6 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'
/account/watchlist
'
:
'
- watchlist
'
,
'
/account/api-key
'
:
'
- API keys
'
,
'
/account/custom-abi
'
:
'
- custom ABI
'
,
'
/account/public-tags-request
'
:
'
- public tag requests
'
,
'
/account/tag-address
'
:
'
- private tags
'
,
'
/account/verified-addresses
'
:
'
- my verified addresses
'
,
'
/withdrawals
'
:
'
withdrawals
'
,
...
...
lib/mixpanel/getPageType.ts
View file @
7bfbb3a1
...
...
@@ -25,7 +25,6 @@ export const PAGE_TYPE_DICT: Record<Route['pathname'], string> = {
'
/account/watchlist
'
:
'
Watchlist
'
,
'
/account/api-key
'
:
'
API keys
'
,
'
/account/custom-abi
'
:
'
Custom ABI
'
,
'
/account/public-tags-request
'
:
'
Public tags
'
,
'
/account/tag-address
'
:
'
Private tags
'
,
'
/account/verified-addresses
'
:
'
Verified addresses
'
,
'
/withdrawals
'
:
'
Withdrawals
'
,
...
...
nextjs/nextjs-routes.d.ts
View file @
7bfbb3a1
...
...
@@ -9,7 +9,6 @@ declare module "nextjs-routes" {
|
StaticRoute
<
"
/404
"
>
|
StaticRoute
<
"
/account/api-key
"
>
|
StaticRoute
<
"
/account/custom-abi
"
>
|
StaticRoute
<
"
/account/public-tags-request
"
>
|
StaticRoute
<
"
/account/tag-address
"
>
|
StaticRoute
<
"
/account/verified-addresses
"
>
|
StaticRoute
<
"
/account/watchlist
"
>
...
...
nextjs/redirects.js
View file @
7bfbb3a1
...
...
@@ -48,18 +48,6 @@ const oldUrls = [
source
:
'
/account/custom_abi/new
'
,
destination
:
'
/account/custom-abi
'
,
},
{
source
:
'
/account/public_tags_request
'
,
destination
:
'
/account/public-tags-request
'
,
},
{
source
:
'
/account/public_tags_request/:id/edit
'
,
destination
:
'
/account/public-tags-request
'
,
},
{
source
:
'
/account/public_tags_request/new
'
,
destination
:
'
/account/public-tags-request
'
,
},
// TRANSACTIONS
{
...
...
pages/account/public-tags-request.tsx
deleted
100644 → 0
View file @
3acc8615
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
React
from
'
react
'
;
import
PageNextJs
from
'
nextjs/PageNextJs
'
;
const
PublicTags
=
dynamic
(()
=>
import
(
'
ui/pages/PublicTags
'
),
{
ssr
:
false
});
const
Page
:
NextPage
=
()
=>
{
return
(
<
PageNextJs
pathname=
"/account/public-tags-request"
>
<
PublicTags
/>
</
PageNextJs
>
);
};
export
default
Page
;
export
{
account
as
getServerSideProps
}
from
'
nextjs/getServerSideProps
'
;
stubs/account.ts
View file @
7bfbb3a1
import
type
{
PublicTag
,
AddressTag
,
TransactionTag
,
ApiKey
,
CustomAbi
,
VerifiedAddress
,
TokenInfoApplication
,
WatchlistAddress
}
from
'
types/api/account
'
;
import
type
{
AddressTag
,
TransactionTag
,
ApiKey
,
CustomAbi
,
VerifiedAddress
,
TokenInfoApplication
,
WatchlistAddress
}
from
'
types/api/account
'
;
import
{
ADDRESS_PARAMS
,
ADDRESS_HASH
}
from
'
./addressParams
'
;
import
{
TX_HASH
}
from
'
./tx
'
;
...
...
@@ -16,19 +16,6 @@ export const PRIVATE_TAG_TX: TransactionTag = {
transaction_hash
:
TX_HASH
,
};
export
const
PUBLIC_TAG
:
PublicTag
=
{
additional_comment
:
'
my comment
'
,
addresses
:
[
ADDRESS_HASH
],
addresses_with_info
:
[
ADDRESS_PARAMS
],
company
:
'
Blockscout
'
,
email
:
'
john.doe@example.com
'
,
full_name
:
'
name
'
,
id
:
1
,
is_owner
:
true
,
tags
:
'
placeholder
'
,
website
:
'
example.com
'
,
};
export
const
WATCH_LIST_ITEM_WITH_TOKEN_INFO
:
WatchlistAddress
=
{
address
:
ADDRESS_PARAMS
,
address_balance
:
'
7072643779453701031672
'
,
...
...
types/api/account.ts
View file @
7bfbb3a1
...
...
@@ -103,23 +103,6 @@ export type WatchlistResponse = {
}
|
null
;
}
export
interface
PublicTag
{
website
:
string
;
tags
:
string
;
// tag_1;tag_2;tag_3 etc.
is_owner
:
boolean
;
id
:
number
;
full_name
:
string
;
email
:
string
;
company
:
string
;
addresses
:
Array
<
string
>
;
addresses_with_info
:
Array
<
AddressParam
>
;
additional_comment
:
string
;
}
export
type
PublicTagNew
=
Omit
<
PublicTag
,
'
id
'
|
'
addresses_with_info
'
>
export
type
PublicTags
=
Array
<
PublicTag
>
;
export
type
CustomAbis
=
Array
<
CustomAbi
>
export
interface
CustomAbi
{
...
...
@@ -175,14 +158,6 @@ export type TransactionTagErrors = {
identity_id
?:
Array
<
string
>
;
}
export
type
PublicTagErrors
=
{
additional_comment
:
Array
<
string
>
;
addresses
:
Array
<
string
>
;
email
:
Array
<
string
>
;
full_name
:
Array
<
string
>
;
tags
:
Array
<
string
>
;
}
export
interface
VerifiedAddress
{
userId
:
string
;
chainId
:
string
;
...
...
ui/pages/PublicTags.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
useRouter
}
from
'
next/router
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
{
animateScroll
}
from
'
react-scroll
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
PublicTagsData
from
'
ui/publicTags/PublicTagsData
'
;
import
PublicTagsForm
from
'
ui/publicTags/PublicTagsForm/PublicTagsForm
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
type
TScreen
=
'
data
'
|
'
form
'
;
type
TToastAction
=
'
added
'
|
'
removed
'
;
const
toastDescriptions
=
{
added
:
'
Your request sent to moderator. Waiting for...
'
,
removed
:
'
Tags have been removed.
'
,
}
as
Record
<
TToastAction
,
string
>
;
const
PublicTagsComponent
:
React
.
FC
=
()
=>
{
const
router
=
useRouter
();
const
addressHash
=
getQueryParamString
(
router
.
query
.
address
);
const
[
screen
,
setScreen
]
=
useState
<
TScreen
>
(
addressHash
?
'
form
'
:
'
data
'
);
const
[
formData
,
setFormData
]
=
useState
<
Partial
<
PublicTag
>
|
undefined
>
(
addressHash
?
{
addresses
:
[
addressHash
]
}
:
undefined
);
const
toast
=
useToast
();
useRedirectForInvalidAuthToken
();
React
.
useEffect
(()
=>
{
addressHash
&&
router
.
replace
({
pathname
:
'
/account/public-tags-request
'
});
// componentDidMount
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[
]);
const
showToast
=
useCallback
((
action
:
TToastAction
)
=>
{
toast
({
position
:
'
top-right
'
,
title
:
'
Success
'
,
description
:
toastDescriptions
[
action
],
colorScheme
:
'
green
'
,
status
:
'
success
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
icon
:
null
,
});
},
[
toast
]);
const
changeToFormScreen
=
useCallback
((
data
?:
PublicTag
)
=>
{
setFormData
(
data
);
setScreen
(
'
form
'
);
animateScroll
.
scrollToTop
({
duration
:
500
,
delay
:
100
,
});
},
[]);
const
changeToDataScreen
=
useCallback
((
success
?:
boolean
)
=>
{
if
(
success
)
{
showToast
(
'
added
'
);
}
setScreen
(
'
data
'
);
animateScroll
.
scrollToTop
({
duration
:
500
,
delay
:
100
,
});
},
[
showToast
]);
const
onTagDelete
=
useCallback
(()
=>
showToast
(
'
removed
'
),
[
showToast
]);
const
onGoBack
=
useCallback
(()
=>
setScreen
(
'
data
'
),
[
]);
let
content
;
let
header
;
if
(
screen
===
'
data
'
)
{
content
=
<
PublicTagsData
changeToFormScreen=
{
changeToFormScreen
}
onTagDelete=
{
onTagDelete
}
/>;
header
=
'
Public tags
'
;
}
else
{
content
=
<
PublicTagsForm
changeToDataScreen=
{
changeToDataScreen
}
data=
{
formData
}
/>;
header
=
formData
?
'
Request to edit a public tag/label
'
:
'
Request a public tag/label
'
;
}
const
backLink
=
{
label
:
'
Public tags
'
,
onClick
:
onGoBack
,
};
return
(
<>
<
PageTitle
title=
{
header
}
backLink=
{
screen
===
'
form
'
?
backLink
:
undefined
}
display=
{
{
base
:
'
block
'
,
lg
:
'
inline-flex
'
}
}
/>
{
content
}
</>
);
};
export
default
PublicTagsComponent
;
ui/publicTags/DeletePublicTagModal.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
Box
,
Text
,
FormControl
,
FormLabel
,
Textarea
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
type
{
PublicTags
,
PublicTag
}
from
'
types/api/account
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
type
Props
=
{
isOpen
:
boolean
;
onClose
:
()
=>
void
;
data
:
PublicTag
;
onDeleteSuccess
:
()
=>
void
;
}
const
DeletePublicTagModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClose
,
data
,
onDeleteSuccess
})
=>
{
const
[
reason
,
setReason
]
=
useState
<
string
>
(
''
);
const
tags
=
data
.
tags
.
split
(
'
;
'
);
const
queryClient
=
useQueryClient
();
const
apiFetch
=
useApiFetch
();
const
formBackgroundColor
=
useColorModeValue
(
'
white
'
,
'
gray.900
'
);
const
deleteApiKey
=
useCallback
(()
=>
{
const
body
=
{
remove_reason
:
reason
};
return
apiFetch
(
'
public_tags
'
,
{
pathParams
:
{
id
:
String
(
data
.
id
)
},
fetchParams
:
{
method
:
'
DELETE
'
,
body
},
});
},
[
data
.
id
,
apiFetch
,
reason
]);
const
onSuccess
=
useCallback
(
async
()
=>
{
onDeleteSuccess
();
queryClient
.
setQueryData
([
resourceKey
(
'
public_tags
'
)
],
(
prevData
:
PublicTags
|
undefined
)
=>
{
return
prevData
?.
filter
((
item
)
=>
item
.
id
!==
data
.
id
);
});
},
[
queryClient
,
data
,
onDeleteSuccess
]);
const
onFieldChange
=
useCallback
((
event
:
ChangeEvent
<
HTMLTextAreaElement
>
)
=>
{
setReason
(
event
.
currentTarget
.
value
);
},
[]);
const
renderContent
=
useCallback
(()
=>
{
let
text
;
if
(
tags
.
length
===
1
)
{
text
=
(
<>
<
Text
display=
"inline"
as=
"span"
>
Public tag
</
Text
>
<
Text
fontWeight=
"700"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tags[0] }" `
}
</
Text
>
<
Text
as=
"span"
>
will be removed.
</
Text
>
</>
);
}
if
(
tags
.
length
>
1
)
{
const
tagsText
:
Array
<
JSX
.
Element
|
string
>
=
[];
tags
.
forEach
((
tag
,
index
)
=>
{
if
(
index
<
tags
.
length
-
2
)
{
tagsText
.
push
(<
Text
fontWeight=
"700"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }"`
}
</
Text
>);
tagsText
.
push
(
'
,
'
);
}
if
(
index
===
tags
.
length
-
2
)
{
tagsText
.
push
(<
Text
fontWeight=
"700"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }" `
}
</
Text
>);
tagsText
.
push
(
'
and
'
);
}
if
(
index
===
tags
.
length
-
1
)
{
tagsText
.
push
(<
Text
fontWeight=
"700"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }" `
}
</
Text
>);
}
});
text
=
(
<>
<
Text
as=
"span"
>
Public tags
</
Text
>
{
tagsText
}
<
Text
as=
"span"
>
will be removed.
</
Text
>
</>
);
}
return
(
<>
<
Box
marginBottom=
{
8
}
>
{
text
}
</
Box
>
<
FormControl
variant=
"floating"
id=
"tag-delete"
backgroundColor=
{
formBackgroundColor
}
>
<
Textarea
size=
"lg"
value=
{
reason
}
onChange=
{
onFieldChange
}
/>
<
FormLabel
>
Why do you want to remove tags?
</
FormLabel
>
</
FormControl
>
</>
);
},
[
tags
,
reason
,
onFieldChange
,
formBackgroundColor
]);
return
(
<
DeleteModal
isOpen=
{
isOpen
}
onClose=
{
onClose
}
title=
"Request to remove a public tag"
renderContent=
{
renderContent
}
mutationFn=
{
deleteApiKey
}
onSuccess=
{
onSuccess
}
/>
);
};
export
default
React
.
memo
(
DeletePublicTagModal
);
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
VStack
,
Text
,
HStack
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
interface
Props
{
item
:
PublicTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
const
PublicTagListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
ListItemMobile
>
<
VStack
spacing=
{
3
}
alignItems=
"flex-start"
maxW=
"100%"
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
maxW=
"100%"
>
{
item
.
addresses_with_info
.
map
((
address
)
=>
(
<
AddressEntity
key=
{
address
.
hash
}
address=
{
address
}
isLoading=
{
isLoading
}
fontWeight=
"600"
w=
"100%"
/>
))
}
</
VStack
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Public tags
</
Text
>
<
HStack
spacing=
{
2
}
alignItems=
"baseline"
>
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
<
Tag
key=
{
tag
}
isLoading=
{
isLoading
}
isTruncated
>
{
tag
}
</
Tag
>)
}
</
HStack
>
</
HStack
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Status
</
Text
>
<
Skeleton
fontSize=
"sm"
color=
"text_secondary"
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
<
span
>
Submitted
</
span
>
</
Skeleton
>
</
HStack
>
</
VStack
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
ListItemMobile
>
);
};
export
default
React
.
memo
(
PublicTagListItem
);
ui/publicTags/PublicTagTable/PublicTagTable.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
Table
,
Thead
,
Tbody
,
Tr
,
Th
,
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
PublicTags
,
PublicTag
}
from
'
types/api/account
'
;
import
PublicTagTableItem
from
'
./PublicTagTableItem
'
;
interface
Props
{
data
?:
PublicTags
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
const
PublicTagTable
=
({
data
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Tr
>
<
Th
width=
"50%"
>
Smart contract / Address (0x...)
</
Th
>
<
Th
width=
"25%"
>
Public tag
</
Th
>
<
Th
width=
"25%"
>
Request status
</
Th
>
<
Th
width=
"108px"
></
Th
>
</
Tr
>
</
Thead
>
<
Tbody
>
{
data
?.
map
((
item
,
index
)
=>
(
<
PublicTagTableItem
key=
{
item
.
id
+
(
isLoading
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
))
}
</
Tbody
>
</
Table
>
);
};
export
default
PublicTagTable
;
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
Tr
,
Td
,
VStack
,
Box
,
Skeleton
,
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
interface
Props
{
item
:
PublicTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
const
PublicTagTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
>
{
item
.
addresses_with_info
.
map
((
address
)
=>
(
<
AddressEntity
key=
{
address
.
hash
}
address=
{
address
}
isLoading=
{
isLoading
}
fontWeight=
"600"
py=
"2px"
/>
))
}
</
VStack
>
</
Td
>
<
Td
>
<
VStack
spacing=
{
2
}
alignItems=
"baseline"
>
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
<
Tag
key=
{
tag
}
isLoading=
{
isLoading
}
isTruncated
>
{
tag
}
</
Tag
>)
}
</
VStack
>
</
Td
>
<
Td
>
<
Skeleton
fontSize=
"sm"
fontWeight=
"500"
py=
"2px"
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
Submitted
</
Skeleton
>
</
Td
>
<
Td
>
<
Box
py=
"2px"
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Box
>
</
Td
>
</
Tr
>
);
};
export
default
React
.
memo
(
PublicTagTableItem
);
ui/publicTags/PublicTagsData.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
{
PUBLIC_TAG
}
from
'
stubs/account
'
;
import
PublicTagListItem
from
'
ui/publicTags/PublicTagTable/PublicTagListItem
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DeletePublicTagModal
from
'
./DeletePublicTagModal
'
;
import
PublicTagTable
from
'
./PublicTagTable/PublicTagTable
'
;
type
Props
=
{
changeToFormScreen
:
(
data
?:
PublicTag
)
=>
void
;
onTagDelete
:
()
=>
void
;
}
const
PublicTagsData
=
({
changeToFormScreen
,
onTagDelete
}:
Props
)
=>
{
const
deleteModalProps
=
useDisclosure
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
PublicTag
>
();
const
{
data
,
isPlaceholderData
,
isError
}
=
useApiQuery
(
'
public_tags
'
,
{
queryOptions
:
{
placeholderData
:
Array
(
3
).
fill
(
PUBLIC_TAG
),
},
});
const
onDeleteModalClose
=
useCallback
(()
=>
{
setDeleteModalData
(
undefined
);
deleteModalProps
.
onClose
();
},
[
deleteModalProps
]);
const
changeToForm
=
useCallback
(()
=>
{
changeToFormScreen
();
},
[
changeToFormScreen
]);
const
onItemEditClick
=
useCallback
((
item
:
PublicTag
)
=>
{
changeToFormScreen
(
item
);
},
[
changeToFormScreen
]);
const
onItemDeleteClick
=
useCallback
((
item
:
PublicTag
)
=>
{
setDeleteModalData
(
item
);
deleteModalProps
.
onOpen
();
},
[
deleteModalProps
]);
const
description
=
(
<
AccountPageDescription
>
You can request a public category tag which is displayed to all Blockscout users.
Public tags may be added to contract or external addresses, and any associated transactions will inherit that tag.
Clicking a tag opens a page with related information and helps provide context and data organization.
Requests are sent to a moderator for review and approval. This process can take several days.
</
AccountPageDescription
>
);
if
(
isError
)
{
return
<
DataFetchAlert
/>;
}
const
list
=
(
<>
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
{
data
?.
map
((
item
,
index
)
=>
(
<
PublicTagListItem
key=
{
item
.
id
+
(
isPlaceholderData
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
PublicTagTable
data=
{
data
}
isLoading=
{
isPlaceholderData
}
onEditClick=
{
onItemEditClick
}
onDeleteClick=
{
onItemDeleteClick
}
/>
</
Box
>
</>
);
return
(
<>
{
description
}
{
Boolean
(
data
?.
length
)
&&
list
}
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
size=
"lg"
onClick=
{
changeToForm
}
>
Request to add public tag
</
Button
>
</
Skeleton
>
{
deleteModalData
&&
(
<
DeletePublicTagModal
{
...
deleteModalProps
}
onClose=
{
onDeleteModalClose
}
data=
{
deleteModalData
}
onDeleteSuccess=
{
onTagDelete
}
/>
)
}
</>
);
};
export
default
PublicTagsData
;
ui/publicTags/PublicTagsForm/PublicTagFormAction.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
RadioGroup
,
Radio
,
Stack
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ControllerRenderProps
,
Control
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
import
type
{
Inputs
}
from
'
./PublicTagsForm
'
;
interface
Props
{
control
:
Control
<
Inputs
>
;
isDisabled
?:
boolean
;
}
export
default
function
PublicTagFormAction
({
control
,
isDisabled
}:
Props
)
{
const
renderRadioGroup
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
'
action
'
>
})
=>
{
return
(
<
RadioGroup
defaultValue=
"add"
colorScheme=
"blue"
{
...
field
}
>
<
Stack
spacing=
{
5
}
>
<
Radio
value=
"add"
>
I want to add tags for my project
</
Radio
>
<
Radio
value=
"report"
isDisabled=
{
isDisabled
}
>
I want to report an incorrect public tag
</
Radio
>
</
Stack
>
</
RadioGroup
>
);
},
[
isDisabled
]);
return
(
<
Controller
name=
"action"
control=
{
control
}
render=
{
renderRadioGroup
}
/>
);
}
ui/publicTags/PublicTagsForm/PublicTagFormAddressInput.tsx
deleted
100644 → 0
View file @
3acc8615
import
type
{
InputProps
}
from
'
@chakra-ui/react
'
;
import
{
IconButton
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ControllerRenderProps
,
Control
,
FieldError
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
import
{
ADDRESS_REGEXP
}
from
'
lib/validations/address
'
;
import
AddressInput
from
'
ui/shared/AddressInput
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
type
{
Inputs
}
from
'
./PublicTagsForm
'
;
interface
Props
{
control
:
Control
<
Inputs
>
;
index
:
number
;
fieldsLength
:
number
;
error
?:
FieldError
;
onAddFieldClick
:
(
e
:
React
.
SyntheticEvent
)
=>
void
;
onRemoveFieldClick
:
(
index
:
number
)
=>
(
e
:
React
.
SyntheticEvent
)
=>
void
;
size
?:
InputProps
[
'
size
'
];
}
const
MAX_INPUTS_NUM
=
10
;
export
default
function
PublicTagFormAction
({
control
,
index
,
fieldsLength
,
error
,
onAddFieldClick
,
onRemoveFieldClick
,
size
}:
Props
)
{
const
renderAddressInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
`addresses.
${
number
}
.address`
>
})
=>
{
return
(
<
AddressInput
<
Inputs
,
`
addresses
.
$
{
number
}
.
address
`
>
field=
{
field
}
error=
{
error
}
size=
{
size
}
placeholder="Smart contract / Address (0x...)"
/
>
);
}, [ error, size ]);
return (
<
Flex
flexDir=
"column"
rowGap=
{
5
}
alignItems=
"flex-end"
>
<
Controller
name=
{
`addresses.${ index }.address`
}
control=
{
control
}
render=
{
renderAddressInput
}
rules=
{
{
pattern
:
ADDRESS_REGEXP
,
required
:
index
===
0
,
}
}
/>
<
Flex
columnGap=
{
5
}
position=
{
{
base
:
'
static
'
,
lg
:
'
absolute
'
}
}
left=
{
{
base
:
'
auto
'
,
lg
:
'
calc(100% + 20px)
'
}
}
h=
"100%"
alignItems=
"center"
>
{
fieldsLength
>
1
&&
(
<
IconButton
aria
-
label=
"delete"
variant=
"outline"
w=
"30px"
h=
"30px"
onClick=
{
onRemoveFieldClick
(
index
)
}
icon=
{
<
IconSvg
name=
"minus"
w=
"20px"
h=
"20px"
/>
}
/>
)
}
{
index
===
fieldsLength
-
1
&&
fieldsLength
<
MAX_INPUTS_NUM
&&
(
<
IconButton
aria
-
label=
"add"
variant=
"outline"
w=
"30px"
h=
"30px"
onClick=
{
onAddFieldClick
}
icon=
{
<
IconSvg
name=
"plus"
w=
"20px"
h=
"20px"
/>
}
/>
)
}
</
Flex
>
</
Flex
>
);
}
ui/publicTags/PublicTagsForm/PublicTagFormComment.tsx
deleted
100644 → 0
View file @
3acc8615
import
type
{
InputProps
}
from
'
@chakra-ui/react
'
;
import
{
FormControl
,
Textarea
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ControllerRenderProps
,
Control
,
FieldError
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
import
InputPlaceholder
from
'
ui/shared/InputPlaceholder
'
;
import
type
{
Inputs
}
from
'
./PublicTagsForm
'
;
const
TEXT_INPUT_MAX_LENGTH
=
255
;
interface
Props
{
control
:
Control
<
Inputs
>
;
error
?:
FieldError
;
size
?:
InputProps
[
'
size
'
];
}
export
default
function
PublicTagFormComment
({
control
,
error
,
size
}:
Props
)
{
const
renderComment
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
'
comment
'
>
})
=>
{
return
(
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
size=
{
size
}
isRequired
>
<
Textarea
{
...
field
}
isInvalid=
{
Boolean
(
error
)
}
/>
<
InputPlaceholder
text=
"Specify the reason for adding tags and color preference(s)"
error=
{
error
}
/>
</
FormControl
>
);
},
[
error
,
size
]);
return
(
<
Controller
name=
"comment"
control=
{
control
}
render=
{
renderComment
}
rules=
{
{
maxLength
:
TEXT_INPUT_MAX_LENGTH
,
required
:
true
,
}
}
/>
);
}
ui/publicTags/PublicTagsForm/PublicTagsForm.tsx
deleted
100644 → 0
View file @
3acc8615
import
{
Button
,
Box
,
Grid
,
GridItem
,
Text
,
HStack
,
chakra
,
}
from
'
@chakra-ui/react
'
;
import
{
useMutation
,
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
FieldError
,
Path
,
SubmitHandler
}
from
'
react-hook-form
'
;
import
{
useForm
,
useFieldArray
}
from
'
react-hook-form
'
;
import
type
{
PublicTags
,
PublicTag
,
PublicTagNew
,
PublicTagErrors
}
from
'
types/api/account
'
;
import
type
{
ResourceErrorAccount
}
from
'
lib/api/resources
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
{
EMAIL_REGEXP
}
from
'
lib/validations/email
'
;
import
FormSubmitAlert
from
'
ui/shared/FormSubmitAlert
'
;
import
PublicTagFormAction
from
'
./PublicTagFormAction
'
;
import
PublicTagFormAddressInput
from
'
./PublicTagFormAddressInput
'
;
import
PublicTagFormComment
from
'
./PublicTagFormComment
'
;
import
PublicTagsFormInput
from
'
./PublicTagsFormInput
'
;
type
Props
=
{
changeToDataScreen
:
(
success
?:
boolean
)
=>
void
;
data
?:
Partial
<
PublicTag
>
;
}
export
type
Inputs
=
{
fullName
?:
string
;
email
?:
string
;
companyName
?:
string
;
companyUrl
?:
string
;
action
:
'
add
'
|
'
report
'
;
tags
?:
string
;
addresses
?:
Array
<
{
name
:
string
;
address
:
string
;
}
>
;
comment
?:
string
;
}
const
placeholders
=
{
fullName
:
'
Your name
'
,
email
:
'
Email
'
,
companyName
:
'
Company name
'
,
companyUrl
:
'
Company website
'
,
tags
:
'
Public tag (max 35 characters)
'
,
comment
:
'
Specify the reason for adding tags and color preference(s).
'
,
}
as
Record
<
Path
<
Inputs
>
,
string
>
;
const
ADDRESS_INPUT_BUTTONS_WIDTH
=
100
;
const
PublicTagsForm
=
({
changeToDataScreen
,
data
}:
Props
)
=>
{
const
queryClient
=
useQueryClient
();
const
apiFetch
=
useApiFetch
();
const
inputSize
=
{
base
:
'
md
'
,
lg
:
'
lg
'
};
const
{
control
,
handleSubmit
,
formState
:
{
errors
,
isDirty
},
setError
}
=
useForm
<
Inputs
>
({
defaultValues
:
{
fullName
:
data
?.
full_name
||
''
,
email
:
data
?.
email
||
''
,
companyName
:
data
?.
company
||
''
,
companyUrl
:
data
?.
website
||
''
,
tags
:
data
?.
tags
?.
split
(
'
;
'
).
map
((
tag
)
=>
tag
).
join
(
'
;
'
)
||
''
,
addresses
:
data
?.
addresses
?.
map
((
address
,
index
:
number
)
=>
({
name
:
`address.
${
index
}
.address`
,
address
}))
||
[
{
name
:
'
address.0.address
'
,
address
:
''
}
],
comment
:
data
?.
additional_comment
||
''
,
action
:
data
?.
is_owner
===
undefined
||
data
?.
is_owner
?
'
add
'
:
'
report
'
,
},
mode
:
'
onTouched
'
,
});
const
{
fields
,
append
,
remove
}
=
useFieldArray
({
name
:
'
addresses
'
,
control
,
});
const
[
isAlertVisible
,
setAlertVisible
]
=
useState
(
false
);
const
onAddFieldClick
=
useCallback
(()
=>
append
({
address
:
''
,
name
:
''
}),
[
append
]);
const
onRemoveFieldClick
=
useCallback
((
index
:
number
)
=>
()
=>
remove
(
index
),
[
remove
]);
const
updatePublicTag
=
(
formData
:
Inputs
)
=>
{
const
body
:
PublicTagNew
=
{
full_name
:
formData
.
fullName
||
''
,
email
:
formData
.
email
||
''
,
company
:
formData
.
companyName
||
''
,
website
:
formData
.
companyUrl
||
''
,
is_owner
:
formData
.
action
===
'
add
'
,
addresses
:
formData
.
addresses
?.
map
(({
address
})
=>
address
)
||
[],
tags
:
formData
.
tags
?.
split
(
'
;
'
).
map
((
s
)
=>
s
.
trim
()).
join
(
'
;
'
)
||
''
,
additional_comment
:
formData
.
comment
||
''
,
};
if
(
!
data
?.
id
)
{
return
apiFetch
(
'
public_tags
'
,
{
fetchParams
:
{
method
:
'
POST
'
,
body
}
});
}
return
apiFetch
(
'
public_tags
'
,
{
pathParams
:
{
id
:
String
(
data
.
id
)
},
fetchParams
:
{
method
:
'
PUT
'
,
body
},
});
};
const
mutation
=
useMutation
({
mutationFn
:
updatePublicTag
,
onSuccess
:
async
(
data
)
=>
{
const
response
=
data
as
unknown
as
PublicTag
;
queryClient
.
setQueryData
([
resourceKey
(
'
public_tags
'
)
],
(
prevData
:
PublicTags
|
undefined
)
=>
{
const
isExisting
=
prevData
&&
prevData
.
some
((
item
)
=>
item
.
id
===
response
.
id
);
if
(
isExisting
)
{
return
prevData
.
map
((
item
)
=>
{
if
(
item
.
id
===
response
.
id
)
{
return
response
;
}
return
item
;
});
}
return
[
response
,
...(
prevData
||
[])
];
});
changeToDataScreen
(
true
);
},
onError
:
(
error
:
ResourceErrorAccount
<
PublicTagErrors
>
)
=>
{
const
errorMap
=
error
.
payload
?.
errors
;
if
(
errorMap
?.
full_name
||
errorMap
?.
email
||
errorMap
?.
tags
||
errorMap
?.
addresses
||
errorMap
?.
additional_comment
)
{
errorMap
?.
full_name
&&
setError
(
'
fullName
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
full_name
'
)
});
errorMap
?.
email
&&
setError
(
'
email
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
email
'
)
});
errorMap
?.
tags
&&
setError
(
'
tags
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
tags
'
)
});
errorMap
?.
addresses
&&
setError
(
'
addresses.0.address
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
addresses
'
)
});
errorMap
?.
additional_comment
&&
setError
(
'
comment
'
,
{
type
:
'
custom
'
,
message
:
getErrorMessage
(
errorMap
,
'
additional_comment
'
)
});
}
else
{
setAlertVisible
(
true
);
}
},
});
const
onSubmit
:
SubmitHandler
<
Inputs
>
=
useCallback
((
data
)
=>
{
setAlertVisible
(
false
);
mutation
.
mutate
(
data
);
},
[
mutation
]);
return
(
<
chakra
.
form
noValidate
width=
{
{
base
:
'
auto
'
,
lg
:
`calc(100% - ${ ADDRESS_INPUT_BUTTONS_WIDTH }px)`
}
}
maxWidth=
"844px"
onSubmit=
{
handleSubmit
(
onSubmit
)
}
>
{
isAlertVisible
&&
<
Box
mb=
{
4
}
><
FormSubmitAlert
/></
Box
>
}
<
Text
size=
"sm"
variant=
"secondary"
paddingBottom=
{
5
}
>
Company info
</
Text
>
<
Grid
templateColumns=
{
{
base
:
'
1fr
'
,
lg
:
'
1fr 1fr
'
}
}
rowGap=
{
4
}
columnGap=
{
5
}
>
<
GridItem
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="fullName"
control=
{
control
}
label=
{
placeholders
.
fullName
}
error=
{
errors
.
fullName
}
required
size=
{
inputSize
}
/
>
</
GridItem
>
<
GridItem
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="companyName"
control=
{
control
}
label=
{
placeholders
.
companyName
}
error=
{
errors
.
companyName
}
size=
{
inputSize
}
/
>
</
GridItem
>
<
GridItem
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="email"
control=
{
control
}
label=
{
placeholders
.
email
}
pattern=
{
EMAIL_REGEXP
}
error=
{
errors
.
email
}
required
size=
{
inputSize
}
/
>
</
GridItem
>
<
GridItem
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="companyUrl"
control=
{
control
}
label=
{
placeholders
.
companyUrl
}
error=
{
errors
?.
companyUrl
}
size=
{
inputSize
}
/
>
</
GridItem
>
</
Grid
>
<
Box
marginTop=
{
{
base
:
5
,
lg
:
8
}
}
marginBottom=
{
{
base
:
5
,
lg
:
8
}
}
>
<
PublicTagFormAction
control=
{
control
}
/>
</
Box
>
<
Text
size=
"sm"
variant=
"secondary"
marginBottom=
{
5
}
>
Public tags (2 tags maximum, please use
"
;
"
as a divider)
</
Text
>
<
Box
marginBottom=
{
4
}
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="tags"
control=
{
control
}
label=
{
placeholders
.
tags
}
error=
{
errors
.
tags
}
required
size=
{
inputSize
}
/
>
</
Box
>
{
fields
.
map
((
field
,
index
)
=>
{
return
(
<
Box
position=
"relative"
key=
{
field
.
id
}
marginBottom=
{
4
}
>
<
PublicTagFormAddressInput
control=
{
control
}
error=
{
errors
?.
addresses
?.[
index
]?.
address
as
FieldError
}
index=
{
index
}
fieldsLength=
{
fields
.
length
}
onAddFieldClick=
{
onAddFieldClick
}
onRemoveFieldClick=
{
onRemoveFieldClick
}
size=
{
inputSize
}
/>
</
Box
>
);
})
}
<
Box
marginBottom=
{
8
}
>
<
PublicTagFormComment
control=
{
control
}
error=
{
errors
.
comment
}
size=
{
inputSize
}
/>
</
Box
>
<
HStack
spacing=
{
6
}
>
<
Button
size=
"lg"
type=
"submit"
isDisabled=
{
!
isDirty
}
isLoading=
{
mutation
.
isPending
}
>
Send request
</
Button
>
</
HStack
>
</
chakra
.
form
>
);
};
export default React.memo(PublicTagsForm);
ui/publicTags/PublicTagsForm/PublicTagsFormInput.tsx
deleted
100644 → 0
View file @
3acc8615
import
type
{
InputProps
}
from
'
@chakra-ui/react
'
;
import
{
FormControl
,
Input
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ControllerRenderProps
,
FieldError
,
FieldValues
,
Path
,
Control
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
import
InputPlaceholder
from
'
ui/shared/InputPlaceholder
'
;
const
TEXT_INPUT_MAX_LENGTH
=
255
;
interface
Props
<
TInputs
extends
FieldValues
>
{
fieldName
:
Path
<
TInputs
>
;
label
:
string
;
required
?:
boolean
;
control
:
Control
<
TInputs
,
object
>
;
pattern
?:
RegExp
;
error
?:
FieldError
;
size
?:
InputProps
[
'
size
'
];
}
export
default
function
PublicTagsFormInput
<
Inputs
extends
FieldValues
>
({
label
,
control
,
required
,
fieldName
,
pattern
,
error
,
size
,
}:
Props
<
Inputs
>
)
{
const
renderInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
typeof
fieldName
>
})
=>
{
return
(
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
isRequired=
{
required
}
size=
{
size
}
>
<
Input
{
...
field
}
required=
{
required
}
isInvalid=
{
Boolean
(
error
)
}
maxLength=
{
TEXT_INPUT_MAX_LENGTH
}
/>
<
InputPlaceholder
text=
{
label
}
error=
{
error
}
/>
</
FormControl
>
);
},
[
label
,
required
,
error
,
size
]);
return
(
<
Controller
name=
{
fieldName
}
control=
{
control
}
render=
{
renderInput
}
rules=
{
{
pattern
,
required
}
}
/>
);
}
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