Skip to content

Commit d7ec5da

Browse files
authored
Merge pull request AgileVentures#157 from AgileVentures/156_userlist_search_feature
Add user search feature to users dashboard
2 parents 2624cf6 + 5927441 commit d7ec5da

File tree

6 files changed

+109
-30
lines changed

6 files changed

+109
-30
lines changed

cypress/integration/common/web_steps.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ When(`I click on the Users link in the navbar`, () => {
2929
cy.wait('@getUsers')
3030
})
3131

32-
Then(`I should see 12 cards with basic user info`, () => {
32+
Then(`I should see {string} cards with basic user info`, (number) => {
3333
cy.get('h1')
3434
.should('contain', 'Volunteers Directory')
3535
.get('.user-card')
36-
.should('have.length', 12)
36+
.should('have.length', Number(number))
37+
})
38+
39+
When(`I enter {string} into search bar`, name => {
40+
cy.get('input')
41+
.type(name)
3742
})
3843

3944
When("I click on a user's name", () => {

cypress/integration/journey.feature

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ Feature: Journey test
77
Given I am at the "Home" page
88
Then I should see "Scrums"
99
When I click on the Users link in the navbar
10-
Then I should see 12 cards with basic user info
10+
Then I should see "12" cards with basic user info
11+
When I enter "Matt" into search bar
12+
Then I should see "3" cards with basic user info
1113
When I click on a user's name
1214
Then I should see the user's info
1315
When I click on the Projects link in the navbar

src/assets/UsersList.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
h1 {
22
font-size: 50px !important;
33
padding: 20px !important;
4-
}
4+
}
5+
6+
.users-list-search-input {
7+
margin-bottom: 20px;
8+
}

src/containers/UsersList.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component, Fragment } from 'react'
2-
import { Header, Card, Grid, Container } from 'semantic-ui-react'
2+
import { Header, Card, Grid, Container, Input } from 'semantic-ui-react'
33
import Paginate from '../components/Paginate'
44
import PaginationLinks from '../components/PaginationLinks'
55
import { connect } from 'react-redux'
@@ -68,6 +68,21 @@ export class UsersList extends Component {
6868
})
6969
};
7070

71+
handleSearchInput = e => {
72+
const users = this.props.users.filter(user => {
73+
const name = this.sanitizeInput(`${user.first_name} ${user.last_name}`)
74+
const query = this.sanitizeInput(e.target.value)
75+
76+
return name.includes(query)
77+
})
78+
79+
this.normalizeUsers(users)
80+
};
81+
82+
sanitizeInput = input => {
83+
return input.toLowerCase().trim()
84+
};
85+
7186
render () {
7287
let {
7388
firstPage,
@@ -83,20 +98,33 @@ export class UsersList extends Component {
8398
<Grid.Row>
8499
<Grid.Column width={12}>
85100
<Header as='h1'>Volunteers Directory</Header>
101+
<Input
102+
onChange={this.handleSearchInput}
103+
className='users-list-search-input'
104+
fluid
105+
icon='search'
106+
placeholder='Search...'
107+
/>
86108
<Card.Group centered itemsPerRow={3}>
87-
<Paginate
88-
items={usersList}
89-
Component={User}
109+
{usersList ? (
110+
<Paginate
111+
items={usersList}
112+
Component={User}
113+
pageCount={pageCount}
114+
/>
115+
) : (
116+
'No users found.'
117+
)}
118+
</Card.Group>
119+
{pageCount !== 1 ? (
120+
<PaginationLinks
121+
handlePageSelect={this.handlePageSelect}
122+
firstPage={firstPage}
123+
lastPage={lastPage}
90124
pageCount={pageCount}
125+
selectedPage={selectedPage}
91126
/>
92-
</Card.Group>
93-
<PaginationLinks
94-
handlePageSelect={this.handlePageSelect}
95-
firstPage={firstPage}
96-
lastPage={lastPage}
97-
pageCount={pageCount}
98-
selectedPage={selectedPage}
99-
/>
127+
) : null}
100128
</Grid.Column>
101129
</Grid.Row>
102130
</Grid>

src/fixtures/users.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,27 +91,27 @@ export default [
9191
},
9292
{
9393
id: 4,
94-
email: 'test@test.com.br',
94+
email: 'test@test.com.gb',
9595
created_at: '2015-01-26T23:19:00.575Z',
9696
updated_at: '2016-08-22T09:23:23.947Z',
97-
first_name: 'Matt',
98-
last_name: 'Tester',
97+
first_name: 'Gordon',
98+
last_name: 'Brown',
9999
display_email: null,
100100
slug: 'matt-tester',
101101
youtube_id: null,
102102
display_profile: true,
103-
latitude: 27.5949,
104-
longitude: 48.5482,
105-
country_name: 'Brazil',
106-
city: 'Florianopolis',
107-
region: 'Santa Catarina',
103+
latitude: 51.5074,
104+
longitude: 0.1278,
105+
country_name: 'England',
106+
city: 'London',
107+
region: 'London',
108108
youtube_user_name: null,
109109
github_profile_url: null,
110110
display_hire_me: null,
111111
bio: null,
112112
receive_mailings: true,
113-
timezone_offset: -18000,
114-
country_code: 'BR',
113+
timezone_offset: 0,
114+
country_code: 'EN',
115115
status_count: 0,
116116
deleted_at: null,
117117
event_participation_count: 0,

src/tests/containers/UserList.test.js

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import usersFixture from '../../fixtures/users'
55
import { StaticRouter } from 'react-router'
66

77
describe('UsersList', () => {
8-
let wrapper
8+
let wrapper, usersList, searchBox
99
const context = {}
1010
wrapper = mount(
1111
<StaticRouter context={context}>
@@ -23,6 +23,8 @@ describe('UsersList', () => {
2323
/>
2424
</StaticRouter>
2525
)
26+
usersList = wrapper.find('UsersList')
27+
searchBox = wrapper.find('Input')
2628

2729
it('should have a header Volunteers Directory', () => {
2830
expect(wrapper.find('Header').text()).toBe('Volunteers Directory')
@@ -36,12 +38,24 @@ describe('UsersList', () => {
3638
expect(wrapper.find('PaginationLinks')).toHaveLength(1)
3739
})
3840

41+
it('should have an Input search bar component', () => {
42+
expect(wrapper.find('Input')).toHaveLength(1)
43+
})
44+
45+
it('should normalize users for pagination', () => {
46+
let users = usersList.instance().state.users
47+
48+
expect(Object.keys(users).length).toEqual(3)
49+
expect(users[1]).toHaveLength(12)
50+
expect(users[3]).toHaveLength(2)
51+
})
52+
3953
it('should call handlePageSelect when a pagination link is clicked', () => {
4054
let paginationLink2 = wrapper.find('span').filterWhere(item => {
4155
return item.text() === '2'
4256
})
4357
paginationLink2.simulate('click')
44-
let usersList = wrapper.find('UsersList')
58+
4559
expect(usersList.instance().state.selectedPage).toEqual(2)
4660
expect(usersList.instance().state.lastPage).toBe(false)
4761
expect(usersList.instance().state.firstPage).toBe(false)
@@ -52,7 +66,7 @@ describe('UsersList', () => {
5266
return item.text() === '3'
5367
})
5468
paginationLink2.simulate('click')
55-
let usersList = wrapper.find('UsersList')
69+
5670
expect(usersList.instance().state.lastPage).toBe(true)
5771
})
5872

@@ -61,10 +75,36 @@ describe('UsersList', () => {
6175
return item.text() === '1'
6276
})
6377
paginationLink2.simulate('click')
64-
let usersList = wrapper.find('UsersList')
78+
6579
expect(usersList.instance().state.firstPage).toBe(true)
6680
})
6781

82+
it('should limit the users list after query is entered in search box', () => {
83+
expect(usersList.instance().state.users[1]).toHaveLength(12)
84+
85+
// For some reason `searchBox.simulate('change', ...)` was not
86+
// triggering the event.
87+
searchBox.props().onChange({ target: { value: 'gordon' } })
88+
89+
expect(usersList.instance().state.users[1]).toHaveLength(1)
90+
expect(usersList.instance().state.users[1][0].first_name).toEqual('Gordon')
91+
92+
searchBox.props().onChange({ target: { value: '' } })
93+
})
94+
95+
it('should show no users if query in search box does not match any entry', () => {
96+
expect(usersList.instance().state.users[1]).toHaveLength(12)
97+
98+
searchBox.props().onChange({ target: { value: 'blablabla' } })
99+
100+
expect(usersList.instance().state.users[1]).toBeUndefined()
101+
102+
let resultColumns = wrapper.find('CardGroup')
103+
expect(resultColumns.text()).toEqual('No users found.')
104+
105+
searchBox.props().onChange({ target: { value: '' } })
106+
})
107+
68108
it("shouldn't render a Project component without users", () => {
69109
const wrapper = mount(
70110
<StaticRouter context={context}>

0 commit comments

Comments
 (0)