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
336fcf55
Commit
336fcf55
authored
Jan 22, 2024
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
search
parent
09e4f139
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
229 additions
and
15 deletions
+229
-15
index.ts
mocks/search/index.ts
+16
-1
search.ts
types/api/search.ts
+9
-2
SearchResults.pw.tsx
ui/pages/SearchResults.pw.tsx
+31
-0
SearchResults.tsx
ui/pages/SearchResults.tsx
+17
-5
SearchResults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
...esults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
+0
-0
SearchResults.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
...Results.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
+0
-0
SearchResultListItem.tsx
ui/searchResults/SearchResultListItem.tsx
+29
-3
SearchResultTableItem.tsx
ui/searchResults/SearchResultTableItem.tsx
+28
-0
utils.ts
ui/shared/search/utils.ts
+11
-1
SearchBar.pw.tsx
ui/snippets/searchBar/SearchBar.pw.tsx
+30
-0
SearchBarSuggest.tsx
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
+3
-3
SearchBarSuggestItem.tsx
...ppets/searchBar/SearchBarSuggest/SearchBarSuggestItem.tsx
+7
-0
SearchBarSuggestUserOp.tsx
...ets/searchBar/SearchBarSuggest/SearchBarSuggestUserOp.tsx
+48
-0
SearchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
...rchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
+0
-0
SearchBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
...archBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
+0
-0
No files found.
mocks/search/index.ts
View file @
336fcf55
import
type
{
SearchResultToken
,
SearchResultBlock
,
SearchResultAddressOrContract
,
SearchResultTx
,
SearchResultLabel
,
SearchResult
}
from
'
types/api/search
'
;
import
type
{
SearchResultToken
,
SearchResultBlock
,
SearchResultAddressOrContract
,
SearchResultTx
,
SearchResultLabel
,
SearchResult
,
SearchResultUserOp
,
}
from
'
types/api/search
'
;
export
const
token1
:
SearchResultToken
=
{
address
:
'
0x377c5F2B300B25a534d4639177873b7fEAA56d4B
'
,
...
...
@@ -101,6 +109,13 @@ export const tx1: SearchResultTx = {
url
:
'
/tx/0x349d4025d03c6faec117ee10ac0bce7c7a805dd2cbff7a9f101304d9a8a525dd
'
,
};
export
const
userOp1
:
SearchResultUserOp
=
{
timestamp
:
'
2024-01-11T14:15:48.000000Z
'
,
type
:
'
user_operation
'
,
user_operation_hash
:
'
0xcb560d77b0f3af074fa05c1e5c691bcdfe457e630062b5907e9e71fc74b2ec61
'
,
url
:
'
/op/0xcb560d77b0f3af074fa05c1e5c691bcdfe457e630062b5907e9e71fc74b2ec61
'
,
};
export
const
baseResponse
:
SearchResult
=
{
items
:
[
token1
,
...
...
types/api/search.ts
View file @
336fcf55
...
...
@@ -55,7 +55,14 @@ export interface SearchResultTx {
url
?:
string
;
// not used by the frontend, we build the url ourselves
}
export
type
SearchResultItem
=
SearchResultToken
|
SearchResultAddressOrContract
|
SearchResultBlock
|
SearchResultTx
|
SearchResultLabel
;
export
interface
SearchResultUserOp
{
type
:
'
user_operation
'
;
user_operation_hash
:
string
;
timestamp
:
string
;
url
?:
string
;
// not used by the frontend, we build the url ourselves
}
export
type
SearchResultItem
=
SearchResultToken
|
SearchResultAddressOrContract
|
SearchResultBlock
|
SearchResultTx
|
SearchResultLabel
|
SearchResultUserOp
;
export
interface
SearchResult
{
items
:
Array
<
SearchResultItem
>
;
...
...
@@ -79,5 +86,5 @@ export interface SearchResultFilters {
export
interface
SearchRedirectResult
{
parameter
:
string
|
null
;
redirect
:
boolean
;
type
:
'
address
'
|
'
block
'
|
'
transaction
'
|
null
;
type
:
'
address
'
|
'
block
'
|
'
transaction
'
|
'
user_operation
'
|
null
;
}
ui/pages/SearchResults.pw.tsx
View file @
336fcf55
...
...
@@ -8,6 +8,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import
TestApp
from
'
playwright/TestApp
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
*
as
configs
from
'
playwright/utils/configs
'
;
import
SearchResults
from
'
./SearchResults
'
;
...
...
@@ -157,6 +158,36 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
await
expect
(
component
.
locator
(
'
main
'
)).
toHaveScreenshot
();
});
const
testWithUserOps
=
test
.
extend
({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context
:
contextWithEnvs
(
configs
.
featureEnvs
.
userOps
)
as
any
,
});
testWithUserOps
(
'
search by user op hash +@mobile
'
,
async
({
mount
,
page
})
=>
{
const
hooksConfig
=
{
router
:
{
query
:
{
q
:
searchMock
.
userOp1
.
user_operation_hash
},
},
};
await
page
.
route
(
buildApiUrl
(
'
search
'
)
+
`?q=
${
searchMock
.
userOp1
.
user_operation_hash
}
`
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
({
items
:
[
searchMock
.
userOp1
,
],
}),
}));
const
component
=
await
mount
(
<
TestApp
>
<
SearchResults
/>
</
TestApp
>,
{
hooksConfig
},
);
await
expect
(
component
.
locator
(
'
main
'
)).
toHaveScreenshot
();
});
test
.
describe
(
'
with apps
'
,
()
=>
{
const
MARKETPLACE_CONFIG_URL
=
app
.
url
+
buildExternalAssetFilePath
(
'
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL
'
,
'
https://marketplace-config.json
'
)
||
''
;
const
extendedTest
=
test
.
extend
({
...
...
ui/pages/SearchResults.tsx
View file @
336fcf55
...
...
@@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
import
type
{
FormEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
config
from
'
configs/app
'
;
import
useMarketplaceApps
from
'
ui/marketplace/useMarketplaceApps
'
;
import
SearchResultListItem
from
'
ui/searchResults/SearchResultListItem
'
;
import
SearchResultsInput
from
'
ui/searchResults/SearchResultsInput
'
;
...
...
@@ -52,6 +53,10 @@ const SearchResultsPageContent = () => {
router
.
replace
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
redirectCheckQuery
.
data
.
parameter
}
});
return
;
}
case
'
user_operation
'
:
{
router
.
replace
({
pathname
:
'
/op/[hash]
'
,
query
:
{
hash
:
redirectCheckQuery
.
data
.
parameter
}
});
return
;
}
}
}
...
...
@@ -62,12 +67,19 @@ const SearchResultsPageContent = () => {
event
.
preventDefault
();
},
[
]);
const
dataToDisplay
=
(
data
?.
items
||
[]).
filter
((
item
)
=>
{
if
(
!
config
.
features
.
userOps
.
isEnabled
&&
item
.
type
===
'
user_operation
'
)
{
return
false
;
}
return
true
;
});
const
content
=
(()
=>
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
}
const
hasData
=
data
?.
items
.
length
||
(
pagination
.
page
===
1
&&
marketplaceApps
.
displayedApps
.
length
);
const
hasData
=
data
ToDisplay
.
length
||
(
pagination
.
page
===
1
&&
marketplaceApps
.
displayedApps
.
length
);
if
(
!
hasData
)
{
return
null
;
...
...
@@ -83,7 +95,7 @@ const SearchResultsPageContent = () => {
searchTerm=
{
debouncedSearchTerm
}
/>
))
}
{
data
&&
data
.
items
.
map
((
item
,
index
)
=>
(
{
data
ToDisplay
.
map
((
item
,
index
)
=>
(
<
SearchResultListItem
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
data=
{
item
}
...
...
@@ -110,7 +122,7 @@ const SearchResultsPageContent = () => {
searchTerm=
{
debouncedSearchTerm
}
/>
))
}
{
data
&&
data
.
items
.
map
((
item
,
index
)
=>
(
{
data
ToDisplay
.
map
((
item
,
index
)
=>
(
<
SearchResultTableItem
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
data=
{
item
}
...
...
@@ -130,7 +142,7 @@ const SearchResultsPageContent = () => {
return
null
;
}
const
resultsCount
=
pagination
.
page
===
1
&&
!
data
?.
next_page_params
?
(
data
?.
items
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
:
'
50+
'
;
const
resultsCount
=
pagination
.
page
===
1
&&
!
data
?.
next_page_params
?
(
data
ToDisplay
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
:
'
50+
'
;
const
text
=
isPlaceholderData
&&
pagination
.
page
===
1
?
(
<
Skeleton
h=
{
6
}
w=
"280px"
borderRadius=
"full"
mb=
{
pagination
.
isVisible
?
0
:
6
}
/>
...
...
@@ -141,7 +153,7 @@ const SearchResultsPageContent = () => {
<
chakra
.
span
fontWeight=
{
700
}
>
{
resultsCount
}
</
chakra
.
span
>
<
span
>
matching result
{
(((
data
?.
items
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
)
>
1
)
||
pagination
.
page
>
1
?
'
s
'
:
''
}
for
</
span
>
<
span
>
matching result
{
(((
data
ToDisplay
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
)
>
1
)
||
pagination
.
page
>
1
?
'
s
'
:
''
}
for
</
span
>
“
<
chakra
.
span
fontWeight=
{
700
}
>
{
debouncedSearchTerm
}
</
chakra
.
span
>
”
</
Box
>
)
...
...
ui/pages/__screenshots__/SearchResults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
25.6 KB
ui/pages/__screenshots__/SearchResults.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
21.3 KB
ui/searchResults/SearchResultListItem.tsx
View file @
336fcf55
...
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
UserOpEtity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
...
...
@@ -56,7 +57,6 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
wordBreak=
"break-all"
isLoading=
{
isLoading
}
onClick=
{
handleLinkClick
}
flexGrow=
{
1
}
overflow=
"hidden"
>
<
Skeleton
...
...
@@ -200,6 +200,26 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
</
TxEntity
.
Container
>
);
}
case
'
user_operation
'
:
{
return
(
<
UserOpEtity
.
Container
>
<
UserOpEtity
.
Icon
/>
<
UserOpEtity
.
Link
isLoading=
{
isLoading
}
hash=
{
data
.
user_operation_hash
}
onClick=
{
handleLinkClick
}
>
<
UserOpEtity
.
Content
asProp=
"mark"
hash=
{
data
.
user_operation_hash
}
fontSize=
"sm"
lineHeight=
{
5
}
fontWeight=
{
700
}
/>
</
UserOpEtity
.
Link
>
</
UserOpEtity
.
Container
>
);
}
}
})();
...
...
@@ -240,6 +260,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
);
}
case
'
user_operation
'
:
{
return
(
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
);
}
case
'
label
'
:
{
return
(
<
Flex
alignItems=
"center"
>
...
...
@@ -295,12 +321,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
return
(
<
ListItemMobile
py=
{
3
}
fontSize=
"sm"
rowGap=
{
2
}
>
<
Flex
justifyContent=
"space-between
"
w=
"100%"
overflow=
"hidden"
lineHeight=
{
6
}
>
<
Grid
templateColumns=
"1fr auto
"
w=
"100%"
overflow=
"hidden"
lineHeight=
{
6
}
>
{
firstRow
}
<
Skeleton
isLoaded=
{
!
isLoading
}
color=
"text_secondary"
ml=
{
8
}
textTransform=
"capitalize"
>
<
span
>
{
category
?
searchItemTitles
[
category
].
itemTitleShort
:
''
}
</
span
>
</
Skeleton
>
</
Flex
>
</
Grid
>
{
Boolean
(
secondRow
)
&&
(
<
Box
w=
"100%"
overflow=
"hidden"
whiteSpace=
{
data
.
type
!==
'
app
'
?
'
nowrap
'
:
undefined
}
>
{
secondRow
}
...
...
ui/searchResults/SearchResultTableItem.tsx
View file @
336fcf55
...
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
UserOpEtity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
...
...
@@ -284,6 +285,33 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
</>
);
}
case
'
user_operation
'
:
{
return
(
<>
<
Td
colSpan=
{
2
}
fontSize=
"sm"
>
<
UserOpEtity
.
Container
>
<
UserOpEtity
.
Icon
/>
<
UserOpEtity
.
Link
isLoading=
{
isLoading
}
hash=
{
data
.
user_operation_hash
}
onClick=
{
handleLinkClick
}
>
<
UserOpEtity
.
Content
asProp=
"mark"
hash=
{
data
.
user_operation_hash
}
fontSize=
"sm"
lineHeight=
{
5
}
fontWeight=
{
700
}
/>
</
UserOpEtity
.
Link
>
</
UserOpEtity
.
Container
>
</
Td
>
<
Td
fontSize=
"sm"
verticalAlign=
"middle"
isNumeric
>
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
</
Td
>
</>
);
}
}
})();
...
...
ui/shared/search/utils.ts
View file @
336fcf55
import
type
{
SearchResultItem
}
from
'
types/api/search
'
;
import
type
{
MarketplaceAppOverview
}
from
'
types/client/marketplace
'
;
export
type
ApiCategory
=
'
token
'
|
'
nft
'
|
'
address
'
|
'
public_tag
'
|
'
transaction
'
|
'
block
'
;
import
config
from
'
configs/app
'
;
export
type
ApiCategory
=
'
token
'
|
'
nft
'
|
'
address
'
|
'
public_tag
'
|
'
transaction
'
|
'
block
'
|
'
user_operation
'
;
export
type
Category
=
ApiCategory
|
'
app
'
;
export
type
ItemsCategoriesMap
=
...
...
@@ -23,6 +25,10 @@ export const searchCategories: Array<{id: Category; title: string }> = [
{
id
:
'
block
'
,
title
:
'
Blocks
'
},
];
if
(
config
.
features
.
userOps
.
isEnabled
)
{
searchCategories
.
push
({
id
:
'
user_operation
'
,
title
:
'
User operations
'
});
}
export
const
searchItemTitles
:
Record
<
Category
,
{
itemTitle
:
string
;
itemTitleShort
:
string
}
>
=
{
app
:
{
itemTitle
:
'
App
'
,
itemTitleShort
:
'
App
'
},
token
:
{
itemTitle
:
'
Token
'
,
itemTitleShort
:
'
Token
'
},
...
...
@@ -31,6 +37,7 @@ export const searchItemTitles: Record<Category, { itemTitle: string; itemTitleSh
public_tag
:
{
itemTitle
:
'
Public tag
'
,
itemTitleShort
:
'
Tag
'
},
transaction
:
{
itemTitle
:
'
Transaction
'
,
itemTitleShort
:
'
Txn
'
},
block
:
{
itemTitle
:
'
Block
'
,
itemTitleShort
:
'
Block
'
},
user_operation
:
{
itemTitle
:
'
User operation
'
,
itemTitleShort
:
'
User op
'
},
};
export
function
getItemCategory
(
item
:
SearchResultItem
|
SearchResultAppItem
):
Category
|
undefined
{
...
...
@@ -57,5 +64,8 @@ export function getItemCategory(item: SearchResultItem | SearchResultAppItem): C
case
'
app
'
:
{
return
'
app
'
;
}
case
'
user_operation
'
:
{
return
'
user_operation
'
;
}
}
}
ui/snippets/searchBar/SearchBar.pw.tsx
View file @
336fcf55
...
...
@@ -9,6 +9,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import
TestApp
from
'
playwright/TestApp
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
*
as
configs
from
'
playwright/utils/configs
'
;
import
SearchBar
from
'
./SearchBar
'
;
...
...
@@ -204,6 +205,35 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
await
expect
(
page
).
toHaveScreenshot
({
clip
:
{
x
:
0
,
y
:
0
,
width
:
1200
,
height
:
300
}
});
});
const
testWithUserOps
=
base
.
extend
({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context
:
contextWithEnvs
(
configs
.
featureEnvs
.
userOps
)
as
any
,
});
testWithUserOps
(
'
search by user op hash +@mobile
'
,
async
({
mount
,
page
})
=>
{
await
page
.
route
(
'
https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242
'
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
(
textAdMock
.
duck
),
}));
const
API_URL
=
buildApiUrl
(
'
quick_search
'
)
+
`?q=
${
searchMock
.
tx1
.
tx_hash
}
`
;
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
([
searchMock
.
userOp1
,
]),
}));
await
mount
(
<
TestApp
>
<
SearchBar
/>
</
TestApp
>,
);
await
page
.
getByPlaceholder
(
/search/i
).
type
(
searchMock
.
tx1
.
tx_hash
);
await
page
.
waitForResponse
(
API_URL
);
await
expect
(
page
).
toHaveScreenshot
({
clip
:
{
x
:
0
,
y
:
0
,
width
:
1200
,
height
:
300
}
});
});
test
(
'
search with view all link
'
,
async
({
mount
,
page
})
=>
{
const
API_URL
=
buildApiUrl
(
'
quick_search
'
)
+
'
?q=o
'
;
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
View file @
336fcf55
...
...
@@ -111,12 +111,12 @@ const SearchBarSuggest = ({ query, searchTerm, onItemClick, containerId }: Props
return
<
Text
>
Something went wrong. Try refreshing the page or come back later.
</
Text
>;
}
if
(
!
query
.
data
||
query
.
data
.
length
===
0
)
{
const
resultCategories
=
searchCategories
.
filter
(
cat
=>
itemsGroups
[
cat
.
id
]);
if
(
resultCategories
.
length
===
0
)
{
return
<
Text
>
No results found.
</
Text
>;
}
const
resultCategories
=
searchCategories
.
filter
(
cat
=>
itemsGroups
[
cat
.
id
]);
return
(
<>
{
resultCategories
.
length
>
1
&&
(
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggestItem.tsx
View file @
336fcf55
...
...
@@ -12,6 +12,7 @@ import SearchBarSuggestItemLink from './SearchBarSuggestItemLink';
import
SearchBarSuggestLabel
from
'
./SearchBarSuggestLabel
'
;
import
SearchBarSuggestToken
from
'
./SearchBarSuggestToken
'
;
import
SearchBarSuggestTx
from
'
./SearchBarSuggestTx
'
;
import
SearchBarSuggestUserOp
from
'
./SearchBarSuggestUserOp
'
;
interface
Props
{
data
:
SearchResultItem
;
...
...
@@ -38,6 +39,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
case
'
block
'
:
{
return
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
String
(
data
.
block_hash
)
}
});
}
case
'
user_operation
'
:
{
return
route
({
pathname
:
'
/op/[hash]
'
,
query
:
{
hash
:
data
.
user_operation_hash
}
});
}
}
})();
...
...
@@ -60,6 +64,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
case
'
transaction
'
:
{
return
<
SearchBarSuggestTx
data=
{
data
}
searchTerm=
{
searchTerm
}
isMobile=
{
isMobile
}
/>;
}
case
'
user_operation
'
:
{
return
<
SearchBarSuggestUserOp
data=
{
data
}
searchTerm=
{
searchTerm
}
isMobile=
{
isMobile
}
/>;
}
}
})();
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggestUserOp.tsx
0 → 100644
View file @
336fcf55
import
{
chakra
,
Text
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
SearchResultUserOp
}
from
'
types/api/search
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
*
as
UserOpEntity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
interface
Props
{
data
:
SearchResultUserOp
;
isMobile
:
boolean
|
undefined
;
searchTerm
:
string
;
}
const
SearchBarSuggestTx
=
({
data
,
isMobile
}:
Props
)
=>
{
const
icon
=
<
UserOpEntity
.
Icon
/>;
const
hash
=
(
<
chakra
.
mark
overflow=
"hidden"
whiteSpace=
"nowrap"
fontWeight=
{
700
}
>
<
HashStringShortenDynamic
hash=
{
data
.
user_operation_hash
}
isTooltipDisabled
/>
</
chakra
.
mark
>
);
const
date
=
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
);
if
(
isMobile
)
{
return
(
<>
<
Flex
alignItems=
"center"
>
{
icon
}
{
hash
}
</
Flex
>
<
Text
variant=
"secondary"
>
{
date
}
</
Text
>
</>
);
}
return
(
<
Flex
columnGap=
{
2
}
>
<
Flex
alignItems=
"center"
minW=
{
0
}
>
{
icon
}
{
hash
}
</
Flex
>
<
Text
variant=
"secondary"
textAlign=
"end"
flexShrink=
{
0
}
ml=
"auto"
>
{
date
}
</
Text
>
</
Flex
>
);
};
export
default
React
.
memo
(
SearchBarSuggestTx
);
ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
27.4 KB
ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
16.6 KB
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