Step 7: Creating the user search

This step will focus on getting the user search working with the Achievers user API. You will use the Dropdown component from the Semantic UI React library for rendering the user search.

1. Create a new method

First, you'll create a new method in our apiMethods.js file that uses the fetch() method to access the Achievers GET /user endpoint.

src/apiMethods.js

Add the following method:

function doUserSearch(accessToken, q = '') {
  const url = buildUrl(process.env.REACT_APP_API_DOMAIN, {
    path: '/api/v5/users',
    queryParams: { q },
  });

  return fetch(url, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    credentials: 'same-origin',
  }).then(res => {
    if (res.status >= 200 && res.status < 300) {
      return res;
    }

    const err = new Error(res.statusText);
    err.res = res;
    throw err;
  }).then(res => res.json());
}

And update the export section as follows:

export {
  fetchModules,
+  doUserSearch,
};

Back in the Main component, you will need to pass along the accessToken so the Recipients component can use it as an argument to doUserSearch().

src/Main.js
    return (
      <div className='anywhereRecognition'>
        <Form>
-          <Recipients />
+          <Recipients accessToken={accessToken} />
          <Reason />

2. Update the Recipeient component

Now update the Recipients component itself. Swap out the TextArea component you added as a placeholder with a Dropdown component. Import the Lodash library, as you will be manipulating arrays.

src/Recipients.js

At the top of the file make the following changes to the import statements:

-import { Header, TextArea } from 'semantic-ui-react'
+import { Header, Dropdown } from 'semantic-ui-react'
+import _ from 'lodash';
+import { doUserSearch } from './apiMethods'; 

Update the render() method as follows:

   render() {
+    const renderLabel = label => ({
+      content: label.text,
+      image: label.image,
+    })
+
+    const { isFetching, options } = this.state
+
     return (
       <div className="recipients">
       <Header as="h2" content="Who do you want to recognize?" />
-      <TextArea rows={2} placeholder="Type in the name of the person you'd like to recognize" />
+        <Dropdown
+          fluid
+          selection
+          multiple
+          search
+          selection
+          closeOnChange
+          options={options}
+          placeholder='Add more people'
+          onSearchChange={this.handleSearchChange}
+          disabled={isFetching}
+          loading={isFetching}
+          renderLabel={renderLabel} 
+          onChange={this.handleRecipientsChange} />
       </div>
     );
   }

Add a componentWillMount() method that will set the initial state:

  componentWillMount() {
    this.setState({
      isFetching: false,
      multiple: true,
      search: true,
      searchQuery: '',
      value: [],
      options: [],
    })
  }

Add the two methods, handleRecipientsChange() and handleSearchChange, that are referenced by the Dropdown component:

  handleRecipientsChange(e, { value }) {
    this.setState({ value });
  }

  handleSearchChange = (e, { searchQuery }) => {
    const { accessToken } = this.props

    this.setState({ isFetching: true })

    doUserSearch(accessToken, searchQuery)
      .then(res => {
        const users = res.items.map((user) => { 
          return { key: user.id, text: user.fullName , image: { src: user.profileImageUrl }, value: user.id } 
        });

        this.setState((prev, props) => {
          const newOptions = _.uniqBy(users.concat(prev.options), 'key');
          return { isFetching: false, options: newOptions };
        });
      })
      .catch(err => {
        this.setState({ error: err, isLoading: false });
      });
  }

3. Add css to Recipients.css

Finally, add some css to Recipients.css so the drop-down looks the way you want it to:

src/Recipients.css
.recipients .ui.image {
  display: inline;
  margin-right: 4px;
}

With all of this added you should have a dropdown that looks something like this:

1072