Skip to content

Commit

Permalink
Feat: new search bar component (#2030)
Browse files Browse the repository at this point in the history
* feat: wip new search bar

* feat: Introduce the SearchBarDropdown component

* chore: configure env to test with mainnet

* feat: add tracking events of the new search bar component

* feat: show current name of the creator in the new search bar

* feat: add logic to show current name applied

* test: fix broken test

* chore: use .org nft server to test

* fix: remove reverse that was reversing the array in place

* fix: fix of tracking bug

* fix: reduce the amount of creators shown to be a max of 5

* feat: add the empty state for wearables search

* chore: use nft-server stg

* feat: add early return to handleSeeAll

* feat: fix search on land section

* feat: add overflow: visible for mobile

* fix: change splice for slice

* fix: see all emotes button

* fix: destructure array before reversing it

* fix: race condition waiting for identity

* fix: tracking not triggering correctly for creators

* feat: add race sagas condition, tests and remove comments

* test: add Test for SearchBarDropdown

* test: add CollectionResultRow test

* test: some small changes
  • Loading branch information
juanmahidalgo authored Oct 10, 2023
1 parent 3fadbc4 commit b7746a3
Show file tree
Hide file tree
Showing 45 changed files with 2,128 additions and 143 deletions.
69 changes: 58 additions & 11 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@dcl/ui-env": "^1.2.0",
"@ethersproject/providers": "^5.6.2",
"@sentry/react": "^7.64.0",
"@types/uuid": "^9.0.4",
"@well-known-components/fetch-component": "^2.0.2",
"classnames": "^2.3.1",
"connected-react-router": "^6.9.1",
Expand Down Expand Up @@ -40,7 +41,8 @@
"redux-logger": "^3.0.6",
"redux-saga": "^1.1.3",
"reselect": "^4.0.0",
"typesafe-actions": "^5.1.0"
"typesafe-actions": "^5.1.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@sentry/cli": "^2.20.5",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/components/AssetBrowse/AssetBrowse.css
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@

.AssetBrowse .Row .right.Column {
max-width: 100%;
overflow: visible; /* so it shows the absolute positioned elements */
}

.AssetBrowse .sidebar {
Expand Down
23 changes: 23 additions & 0 deletions webapp/src/components/AssetTopbar/AssetTopbar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
position: relative;
}

.searchDropdown {
width: 100%;
background-color: red;
position: absolute;
height: 350px;
top: 60px;
z-index: 2;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
}

.searchContainer :global(.dcl.field.full) {
flex: 1;
}
Expand Down Expand Up @@ -150,6 +161,14 @@
right: 12px;
}

.searchFieldContainer {
display: flex;
flex-direction: column;
flex: 1;
position: relative;
justify-content: center;
}

.searchContainer.searchMap {
align-self: flex-end;
background-color: #16141a;
Expand Down Expand Up @@ -215,4 +234,8 @@
.assetTopbar .infoRow {
margin-bottom: 10px;
}

.searchContainer :global(.dcl.close) {
right: 0;
}
}
119 changes: 102 additions & 17 deletions webapp/src/components/AssetTopbar/AssetTopbar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { NFTCategory } from '@dcl/schemas'
import classNames from 'classnames'
import {
Close,
Expand Down Expand Up @@ -27,6 +28,7 @@ import trash from '../../images/trash.png'
import { Chip } from '../Chip'
import { Props } from './AssetTopbar.types'
import { SelectedFilters } from './SelectedFilters'
import { SearchBarDropdown } from './SearchBarDropdown'
import styles from './AssetTopbar.module.css'

export const AssetTopbar = ({
Expand All @@ -46,22 +48,65 @@ export const AssetTopbar = ({
sortByOptions
}: Props): JSX.Element => {
const isMobile = useTabletAndBelowMediaQuery()
const searchBarFieldRef = useRef<HTMLDivElement>(null)
const category = section ? getCategoryFromSection(section) : undefined
const [searchValueForDropdown, setSearchValueForDropdown] = useState(search)
const [shouldRenderSearchDropdown, setShouldRenderSearchDropdown] = useState(
false
)

const handleInputChange = useCallback(
text => {
if (shouldRenderSearchDropdown) {
setSearchValueForDropdown(text)
} else if (text) {
// common search, when the dropdown is not opened
onBrowse({
search: text,
section: category ? getSectionFromCategory(category) : section
})
}
},
[category, onBrowse, section, shouldRenderSearchDropdown]
)
const [searchValue, setSearchValue] = useInput(search, handleInputChange, 500)

const handleClearSearch = useCallback(() => {
setSearchValue({ target: { value: '' } } as React.ChangeEvent<
HTMLInputElement
>)
setSearchValueForDropdown('') // clears the input

onBrowse({
search: ''
}) // triggers search with no search term
}, [onBrowse, setSearchValue])

const handleSearch = useCallback(
(value: string) => {
if (search !== value) {
({
value,
contractAddresses
}: {
value?: string
contractAddresses?: string[]
}) => {
if (value !== undefined && search !== value) {
onBrowse({
search: value,
section: category ? getSectionFromCategory(category) : section
})
} else if (contractAddresses && contractAddresses.length) {
onBrowse({
contracts: contractAddresses,
search: ''
})
handleClearSearch()
}
setShouldRenderSearchDropdown(false)
},
[category, onBrowse, search, section]
[category, handleClearSearch, onBrowse, search, section]
)

const [searchValue, setSearchValue] = useInput(search, handleSearch, 500)

const handleOrderByDropdownChange = useCallback(
(_, props: DropdownProps) => {
const sortBy: SortBy = props.value as SortBy
Expand Down Expand Up @@ -107,25 +152,65 @@ export const AssetTopbar = ({
? sortBy
: sortByOptions[0].value

useEffect(() => {
// when the category changes, close the dropdown
setShouldRenderSearchDropdown(false)
}, [category])

const handleFieldClick = useCallback(() => {
// opens the dropdown on the field focus
setShouldRenderSearchDropdown(
category === NFTCategory.EMOTE || category === NFTCategory.WEARABLE
)
}, [category])

const handleSearchBarDropdownClickOutside = useCallback(event => {
// when clicking outside the dropdown, close it
const containsClick = searchBarFieldRef.current?.contains(event.target)
if (!containsClick) {
setShouldRenderSearchDropdown(false)
}
}, [])

const renderSearch = useCallback(() => {
return (
<SearchBarDropdown
category={category}
searchTerm={searchValueForDropdown}
onSearch={handleSearch}
onClickOutside={handleSearchBarDropdownClickOutside}
/>
)
}, [
category,
handleSearch,
handleSearchBarDropdownClickOutside,
searchValueForDropdown
])

return (
<div className={styles.assetTopbar}>
<div className={styles.assetTopbar} ref={searchBarFieldRef}>
<div
className={classNames(styles.searchContainer, {
[styles.searchMap]: isMap
})}
>
{!isMap && !isListsSection(section) && (
<Field
className={styles.searchField}
placeholder={t('nft_filters.search')}
kind="full"
value={searchValue}
onChange={setSearchValue}
icon={<Icon name="search" className="searchIcon" />}
iconPosition="left"
/>
<div className={styles.searchFieldContainer}>
<Field
className={styles.searchField}
placeholder={t('nft_filters.search')}
kind="full"
value={searchValue}
onChange={setSearchValue}
icon={<Icon name="search" className="searchIcon" />}
iconPosition="left"
onClick={handleFieldClick}
/>
{searchValue ? <Close onClick={handleClearSearch} /> : null}
</div>
)}
{searchValue ? <Close onClick={() => handleSearch('')} /> : null}
{shouldRenderSearchDropdown && renderSearch()}
{isLandSection(section) && !isAccountView(view!) && (
<div
className={classNames(styles.mapToggle, { [styles.map]: isMap })}
Expand Down
Loading

0 comments on commit b7746a3

Please sign in to comment.