Skip to content

Commit

Permalink
Users are searched by API
Browse files Browse the repository at this point in the history
  • Loading branch information
SemaiCZE committed Oct 19, 2017
1 parent b22a6cc commit 79cd34b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 120 deletions.
38 changes: 26 additions & 12 deletions src/components/helpers/Search/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ import { LoadingIcon, SearchIcon, WarningIcon } from '../../icons';
import styles from './search.less';

class Search extends Component {
componentDidMount() {
const { showAllOnEmptyQuery, onChange, query } = this.props;
if (showAllOnEmptyQuery) {
onChange(query);
}
}

render() {
const {
id = '',
Expand All @@ -23,7 +30,8 @@ class Search extends Component {
hasFailed,
query,
foundItems,
renderList
renderList,
showAllOnEmptyQuery = false
} = this.props;

return (
Expand Down Expand Up @@ -60,17 +68,22 @@ class Search extends Component {
</InputGroup>
</FormGroup>
</form>
{query &&
query.length > 0 &&
{((query && query.length > 0) || showAllOnEmptyQuery) &&
<div>
<p>
{' '}
<FormattedMessage
id="app.search.query"
defaultMessage="Searched query: "
/>
<strong><em>{'"'}{query}{'"'}</em></strong>
</p>
{query.length > 0 &&
<p>
{' '}<FormattedMessage
id="app.search.query"
defaultMessage="Searched query: "
/>
<strong>
<em>
{'"'}
{query}
{'"'}
</em>
</strong>
</p>}

{(!isLoading || foundItems.size > 0) &&
<div className={styles.list}>
Expand All @@ -91,7 +104,8 @@ Search.propTypes = {
foundItems: ImmutablePropTypes.list.isRequired,
isLoading: PropTypes.bool,
hasFailed: PropTypes.bool,
isReady: PropTypes.bool
isReady: PropTypes.bool,
showAllOnEmptyQuery: PropTypes.bool
};

export default Search;
12 changes: 7 additions & 5 deletions src/containers/SearchContainer/SearchContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ const SearchContainer = ({
search,
status,
foundItems,
renderList
}) => (
renderList,
showAllOnEmptyQuery = false
}) =>
<Search
type={type}
id={id}
Expand All @@ -31,8 +32,8 @@ const SearchContainer = ({
hasFailed={status === searchStatus.FAILED}
onChange={search}
renderList={renderList}
/>
);
showAllOnEmptyQuery={showAllOnEmptyQuery}
/>;

SearchContainer.propTypes = {
id: PropTypes.string.isRequired,
Expand All @@ -41,7 +42,8 @@ SearchContainer.propTypes = {
query: PropTypes.string,
status: PropTypes.string,
foundItems: ImmutablePropTypes.list.isRequired,
renderList: PropTypes.func.isRequired
renderList: PropTypes.func.isRequired,
showAllOnEmptyQuery: PropTypes.bool
};

const mapStateToProps = (state, { id }) => {
Expand Down
158 changes: 56 additions & 102 deletions src/pages/Users/Users.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,24 @@ import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { push } from 'react-router-redux';
import { LinkContainer } from 'react-router-bootstrap';
import {
FormGroup,
ControlLabel,
FormControl,
InputGroup
} from 'react-bootstrap';

import FetchManyResourceRenderer from '../../components/helpers/FetchManyResourceRenderer';
import { SettingsIcon, SearchIcon, TransferIcon } from '../../components/icons';
import { SettingsIcon, TransferIcon } from '../../components/icons';
import Button from '../../components/widgets/FlatButton';
import DeleteUserButtonContainer from '../../containers/DeleteUserButtonContainer';
import PageContent from '../../components/layout/PageContent';
import Box from '../../components/widgets/Box';
import UsersList from '../../components/Users/UsersList';
import SearchContainer from '../../containers/SearchContainer';
import {
usersSelector,
isSuperAdmin,
fetchManyStatus
fetchManyStatus,
loggedInUserSelector
} from '../../redux/selectors/users';
import { loggedInUserIdSelector } from '../../redux/selectors/auth';
import { fetchAllUsers } from '../../redux/modules/users';
import { takeOver } from '../../redux/modules/auth';
import { loggedInUserIdSelector } from '../../redux/selectors/auth';
import { searchPeople } from '../../redux/modules/search';

import withLinks from '../../hoc/withLinks';

Expand All @@ -35,38 +31,16 @@ class Users extends Component {

componentWillMount() {
this.props.loadAsync();
this.setState({ visibleUsers: [] });
}

componentWillReceiveProps(nextProps) {
this.setState({
visibleUsers: nextProps.users.toArray().map(user => user.toJS().data)
});
}

onChange(query, allUsers) {
const normalizedQuery = query.toLocaleLowerCase();
const filteredUsers = allUsers
.toArray()
.map(user => user.toJS().data)
.filter(
user =>
user.name.lastName.toLocaleLowerCase().startsWith(normalizedQuery) ||
user.fullName.toLocaleLowerCase().startsWith(normalizedQuery) ||
user.id.toLocaleLowerCase().startsWith(normalizedQuery)
);
this.setState({
visibleUsers: filteredUsers
});
}

render() {
const {
users,
links: { EDIT_USER_URI_FACTORY, DASHBOARD_URI },
takeOver,
isSuperAdmin,
fetchStatus
fetchStatus,
search,
user
} = this.props;

return (
Expand Down Expand Up @@ -139,67 +113,42 @@ class Users extends Component {
defaultMessage="Users"
/>
}
noPadding
unlimitedHeight
>
<div>
<form style={{ padding: '10px' }}>
<FormGroup>
<ControlLabel>
<FormattedMessage
id="app.search.title"
defaultMessage="Search:"
/>
</ControlLabel>
<InputGroup>
<FormControl
onChange={e => {
this.query = e.target.value;
}}
/>
<InputGroup.Button>
<Button
type="submit"
onClick={e => {
e.preventDefault();
this.onChange(this.query, users);
}}
disabled={false}
>
<SearchIcon />
</Button>
</InputGroup.Button>
</InputGroup>
</FormGroup>
</form>
<UsersList
users={this.state.visibleUsers}
createActions={userId =>
<div>
<LinkContainer to={EDIT_USER_URI_FACTORY(userId)}>
<Button bsSize="xs">
<SettingsIcon />{' '}
<FormattedMessage
id="app.users.settings"
defaultMessage="Settings"
/>
</Button>
</LinkContainer>
{isSuperAdmin &&
<Button
bsSize="xs"
onClick={() => takeOver(userId, DASHBOARD_URI)}
>
<TransferIcon />{' '}
<FormattedMessage
id="app.users.takeOver"
defaultMessage="Login as"
/>
</Button>}
<DeleteUserButtonContainer id={userId} bsSize="xs" />
</div>}
/>
</div>
<SearchContainer
type="users"
id="users-page"
search={search(user.toJS().data.instanceId)}
showAllOnEmptyQuery={true}
renderList={users =>
<UsersList
users={users}
createActions={userId =>
<div>
<LinkContainer to={EDIT_USER_URI_FACTORY(userId)}>
<Button bsSize="xs">
<SettingsIcon />{' '}
<FormattedMessage
id="app.users.settings"
defaultMessage="Settings"
/>
</Button>
</LinkContainer>
{isSuperAdmin &&
<Button
bsSize="xs"
onClick={() => takeOver(userId, DASHBOARD_URI)}
>
<TransferIcon />{' '}
<FormattedMessage
id="app.users.takeOver"
defaultMessage="Login as"
/>
</Button>}
<DeleteUserButtonContainer id={userId} bsSize="xs" />
</div>}
/>}
/>
</Box>
</div>
</PageContent>}
Expand All @@ -212,24 +161,29 @@ Users.propTypes = {
loadAsync: PropTypes.func.isRequired,
push: PropTypes.func.isRequired,
links: PropTypes.object.isRequired,
users: ImmutablePropTypes.map,
takeOver: PropTypes.func.isRequired,
isSuperAdmin: PropTypes.bool,
fetchStatus: PropTypes.string
fetchStatus: PropTypes.string,
search: PropTypes.func,
user: ImmutablePropTypes.map.isRequired
};

export default withLinks(
connect(
state => ({
users: usersSelector(state),
fetchStatus: fetchManyStatus(state),
isSuperAdmin: isSuperAdmin(loggedInUserIdSelector(state))(state)
}),
state => {
return {
isSuperAdmin: isSuperAdmin(loggedInUserIdSelector(state))(state),
fetchStatus: fetchManyStatus(state),
user: loggedInUserSelector(state)
};
},
dispatch => ({
push: url => dispatch(push(url)),
loadAsync: () => Users.loadAsync({}, dispatch),
takeOver: (userId, redirectUrl) =>
dispatch(takeOver(userId)).then(() => dispatch(push(redirectUrl)))
dispatch(takeOver(userId)).then(() => dispatch(push(redirectUrl))),
search: instanceId => query =>
dispatch(searchPeople(instanceId)('users-page', query))
})
)(Users)
);
2 changes: 1 addition & 1 deletion src/redux/modules/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default handleActions(
initialState
);

export const search = endpoint => (id, query) =>
export const search = endpoint => (id, query = '') =>
createApiAction({
type: actionTypes.SEARCH,
endpoint,
Expand Down

0 comments on commit 79cd34b

Please sign in to comment.