Skip to content

Commit aa67b77

Browse files
committed
feat: add space search bar in home and spaces nearby
1 parent 42215ec commit aa67b77

File tree

9 files changed

+230
-14
lines changed

9 files changed

+230
-14
lines changed

src/Home.js

+27-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Styles from './Styles';
1414
import Loader from './components/common/Loader';
1515
import Main from './components/common/Main';
1616
import { HOME_MAIN_ID } from './config/selectors';
17+
import { searchSpacesByQuery } from './utils/search';
1718

1819
class Home extends Component {
1920
static propTypes = {
@@ -39,15 +40,35 @@ class Home extends Component {
3940
activity: PropTypes.bool.isRequired,
4041
history: PropTypes.shape({ length: PropTypes.number.isRequired })
4142
.isRequired,
43+
searchQuery: PropTypes.string.isRequired,
4244
};
4345

44-
componentDidMount() {
46+
state = {
47+
// eslint-disable-next-line react/destructuring-assignment
48+
filteredSpaces: this.props.spaces,
49+
};
50+
51+
async componentDidMount() {
4552
const { dispatchGetSpaces } = this.props;
46-
dispatchGetSpaces();
53+
await dispatchGetSpaces();
4754
}
4855

56+
componentDidUpdate({ spaces: prevSpaces, searchQuery: prevSearchQuery }) {
57+
const { spaces, searchQuery } = this.props;
58+
if (!spaces.equals(prevSpaces) || searchQuery !== prevSearchQuery) {
59+
this.filterSpacesWithSearchQuery();
60+
}
61+
}
62+
63+
filterSpacesWithSearchQuery = () => {
64+
const { spaces, searchQuery } = this.props;
65+
const filteredSpaces = searchSpacesByQuery(spaces, searchQuery);
66+
this.setState({ filteredSpaces });
67+
};
68+
4969
render() {
50-
const { classes, spaces, activity } = this.props;
70+
const { classes, activity } = this.props;
71+
const { filteredSpaces } = this.state;
5172

5273
if (activity) {
5374
return (
@@ -63,15 +84,16 @@ class Home extends Component {
6384
);
6485
}
6586
return (
66-
<Main id={HOME_MAIN_ID}>
67-
<SpaceGrid spaces={spaces} showActions saved />
87+
<Main id={HOME_MAIN_ID} showSearch>
88+
<SpaceGrid spaces={filteredSpaces} showActions saved />
6889
</Main>
6990
);
7091
}
7192
}
7293

7394
const mapStateToProps = ({ Space }) => ({
7495
spaces: Space.get('saved'),
96+
searchQuery: Space.get('searchQuery'),
7597
activity: Boolean(Space.getIn(['current', 'activity']).size),
7698
});
7799

src/actions/space.js

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
FLAG_SYNCING_SPACE,
1717
SYNC_SPACE_SUCCEEDED,
1818
FLAG_CLEARING_USER_INPUT,
19+
SET_SPACE_SEARCH_QUERY,
1920
} from '../types';
2021
import {
2122
ERROR_ZIP_CORRUPTED,
@@ -445,6 +446,13 @@ const getSpacesNearby = async ({
445446
}
446447
};
447448

449+
const setSearchQuery = async ({ value }) => async dispatch => {
450+
dispatch({
451+
type: SET_SPACE_SEARCH_QUERY,
452+
payload: value,
453+
});
454+
};
455+
448456
export {
449457
loadSpace,
450458
clearSpace,
@@ -460,4 +468,5 @@ export {
460468
clearUserInput,
461469
createGetLocalSpace,
462470
createGetRemoteSpace,
471+
setSearchQuery,
463472
};

src/components/SpacesNearby.js

+31-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import GeolocationControl from './common/GeolocationControl';
1616
import { CONTROL_TYPES } from '../config/constants';
1717
import Main from './common/Main';
1818
import { SPACES_NEARBY_MAIN_ID } from '../config/selectors';
19+
import { searchSpacesByQuery } from '../utils/search';
1920

2021
class SpacesNearby extends Component {
2122
static propTypes = {
@@ -42,23 +43,36 @@ class SpacesNearby extends Component {
4243
spaces: PropTypes.instanceOf(Set).isRequired,
4344
activity: PropTypes.bool,
4445
geolocationEnabled: PropTypes.bool.isRequired,
46+
searchQuery: PropTypes.string.isRequired,
4547
};
4648

4749
static defaultProps = {
4850
geolocation: Map(),
4951
activity: false,
5052
};
5153

54+
state = {
55+
// eslint-disable-next-line react/destructuring-assignment
56+
filteredSpaces: this.props.spaces,
57+
};
58+
5259
constructor(props) {
5360
super(props);
5461
this.getSpacesNearby();
5562
}
5663

57-
componentDidUpdate({ geolocation: prevGeolocation }) {
58-
const { geolocation } = this.props;
64+
componentDidUpdate({
65+
geolocation: prevGeolocation,
66+
spaces: prevSpaces,
67+
searchQuery: prevSearchQuery,
68+
}) {
69+
const { geolocation, spaces, searchQuery } = this.props;
5970
if (!geolocation.equals(prevGeolocation)) {
6071
this.getSpacesNearby();
6172
}
73+
if (!spaces.equals(prevSpaces) || searchQuery !== prevSearchQuery) {
74+
this.filterSpacesWithSearchQuery();
75+
}
6276
}
6377

6478
getSpacesNearby = () => {
@@ -74,8 +88,15 @@ class SpacesNearby extends Component {
7488
}
7589
};
7690

91+
filterSpacesWithSearchQuery = () => {
92+
const { spaces, searchQuery } = this.props;
93+
const filteredSpaces = searchSpacesByQuery(spaces, searchQuery);
94+
this.setState({ filteredSpaces });
95+
};
96+
7797
render() {
78-
const { classes, spaces, activity, geolocationEnabled } = this.props;
98+
const { classes, activity, geolocationEnabled } = this.props;
99+
const { filteredSpaces } = this.state;
79100

80101
if (activity) {
81102
return (
@@ -92,14 +113,18 @@ class SpacesNearby extends Component {
92113
}
93114

94115
const geolocationContent = geolocationEnabled ? (
95-
<SpaceGrid spaces={spaces} />
116+
<SpaceGrid spaces={filteredSpaces} />
96117
) : (
97118
<div className="Main">
98119
<GeolocationControl controlType={CONTROL_TYPES.BUTTON} />
99120
</div>
100121
);
101122

102-
return <Main id={SPACES_NEARBY_MAIN_ID}>{geolocationContent}</Main>;
123+
return (
124+
<Main showSearch id={SPACES_NEARBY_MAIN_ID}>
125+
{geolocationContent}
126+
</Main>
127+
);
103128
}
104129
}
105130

@@ -112,6 +137,7 @@ const mapStateToProps = ({ authentication, Space }) => ({
112137
'settings',
113138
'geolocationEnabled',
114139
]),
140+
searchQuery: Space.get('searchQuery'),
115141
});
116142

117143
const mapDispatchToProps = {

src/components/common/Header.js

+24-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,19 @@ import { withTranslation } from 'react-i18next';
1010
import { connect } from 'react-redux';
1111
import Styles from '../../Styles';
1212
import { DRAWER_BUTTON_ID } from '../../config/selectors';
13+
import SearchSpaceBar from './SearchSpaceBar';
1314

14-
const Header = ({ classes, handleDrawerOpen, isSidebarOpen }) => {
15+
const styles = theme => ({
16+
...Styles(theme),
17+
});
18+
19+
const Header = ({
20+
classes,
21+
handleDrawerOpen,
22+
isSidebarOpen,
23+
showSearch,
24+
handleOnSearch,
25+
}) => {
1526
return (
1627
<AppBar
1728
position="fixed"
@@ -32,6 +43,9 @@ const Header = ({ classes, handleDrawerOpen, isSidebarOpen }) => {
3243
>
3344
<MenuIcon />
3445
</IconButton>
46+
{showSearch ? (
47+
<SearchSpaceBar handleOnInputChange={handleOnSearch} />
48+
) : null}
3549
</Toolbar>
3650
</AppBar>
3751
);
@@ -52,12 +66,20 @@ Header.propTypes = {
5266
formControl: PropTypes.string.isRequired,
5367
input: PropTypes.string.isRequired,
5468
button: PropTypes.string.isRequired,
69+
toolbarRoot: PropTypes.string.isRequired,
5570
}).isRequired,
5671
theme: PropTypes.shape({
5772
direction: PropTypes.string.isRequired,
5873
}).isRequired,
5974
isSidebarOpen: PropTypes.bool.isRequired,
6075
handleDrawerOpen: PropTypes.func.isRequired,
76+
handleOnSearch: PropTypes.func,
77+
showSearch: PropTypes.bool,
78+
};
79+
80+
Header.defaultProps = {
81+
showSearch: false,
82+
handleOnSearch: () => {},
6183
};
6284

6385
const mapStateToProps = ({ authentication }) => ({
@@ -68,7 +90,7 @@ const mapDispatchToProps = {};
6890

6991
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Header);
7092

71-
const StyledComponent = withStyles(Styles, { withTheme: true })(
93+
const StyledComponent = withStyles(styles, { withTheme: true })(
7294
ConnectedComponent
7395
);
7496

src/components/common/Main.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ class Main extends Component {
4040
style: PropTypes.shape({
4141
background: PropTypes.string,
4242
}),
43+
showSearch: PropTypes.bool,
44+
handleOnSearch: PropTypes.func,
4345
};
4446

4547
static defaultProps = {
4648
fullScreen: false,
49+
showSearch: false,
50+
handleOnSearch: () => {},
4751
id: null,
4852
style: {},
4953
};
@@ -57,13 +61,26 @@ class Main extends Component {
5761
};
5862

5963
render() {
60-
const { classes, children, fullScreen, id, style } = this.props;
64+
const {
65+
classes,
66+
children,
67+
fullScreen,
68+
id,
69+
style,
70+
showSearch,
71+
handleOnSearch,
72+
} = this.props;
6173
const { open } = this.state;
6274

6375
return (
6476
<div className={classes.root} style={style}>
6577
<CssBaseline />
66-
<Header isSidebarOpen={open} handleDrawerOpen={this.handleDrawerOpen} />
78+
<Header
79+
showSearch={showSearch}
80+
isSidebarOpen={open}
81+
handleDrawerOpen={this.handleDrawerOpen}
82+
handleOnSearch={handleOnSearch}
83+
/>
6784

6885
<Sidebar
6986
isSidebarOpen={open}

0 commit comments

Comments
 (0)