<repo_name>Bento-Code/react-github-api-user-search<file_sep>/gruntfile.js
'use strict';
module.exports = function(grunt) {
  var pkg = grunt.file.readJSON('package.json');

  var pre = './';

  grunt.initConfig({
		pkg: pkg,
		pre: pre,

    less: {
			development: {
        options: {
          paths: ["<%= pre %>public/css"],
					plugins: [
						new (require('less-plugin-autoprefix'))({browsers: ["> 1%"]}),
						new (require('less-plugin-clean-css'))()
					]
        },
        files: {"<%= pre %>public/css/main.css": "<%= pre %>public/less/main.less"}
      },
      production: {
        options: {
          paths: ["<%= pre %>css"],
					plugins: [
						new (require('less-plugin-autoprefix'))({browsers: ["> 1%"]}),
						new (require('less-plugin-clean-css'))()
					]
        },
        files: {"<%= pre %>public/css/main.min.css": "<%= pre %>public/less/main.less"}
      }
    },
		watch: {
			main: {
				files: [ '<%= pre %>public/less/*.less' ],
				tasks: [ 'build:main' ],
				options: {
					spawn: false,
				},
			}
		}
  });

  grunt.loadNpmTasks('grunt-composer');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', [ 'build', 'watch' ]);
  grunt.registerTask('install', [ 'composer:update', ]);
  grunt.registerTask('build', [ 'less' ]);
  grunt.registerTask('build:main', [ 'less' ]);
};
<file_sep>/README.md
# react-github-api-user-search

Search GitHub Users - This Application uses the GitHub API to search for GitHub Users

## Install:
```
npm install
```

## Run:
```
npm start
```

## Grunt:
```
// Run Grunt
grunt
```

## GitHub API KEY:
PLEASE CREATE AND ADD A GITHUB API KEY TO MAKE THE APP WORK WELL!

[GitHub API KEY](https://github.com/settings/apps)
<file_sep>/src/components/Search.js
// PLEASE CREATE AND ADD A GITHUB API KEY TO MAKE THE APP WORK WELL!

import React, {Component} from "react";

class Search extends Component {

  constructor(props) {
    super(props);
    this.state = {
      users: [],
      typed: '',
      cursor: 0,
    };

    this.key_events = this.key_events.bind(this)
  }

  key_events(event) {
    const {cursor, users} = this.state;

    if (event.keyCode === 38 && cursor > 0) {
      this.setState(prevState => ({
        cursor: prevState.cursor - 1
      }))
    } else if (event.keyCode === 40 && (cursor < users.length - 1)) {
      this.searchListFocus.focus();

      this.setState(prevState => ({
        cursor: prevState.cursor + 1
      }))
    } else if (event.keyCode === 13) {
      let current_user = '';

      for (var i = 0; i <= this.state.cursor; i++) {
        current_user = i;
      }

      window.open(
        this.state.users[current_user]['page_url'],
        '_blank'
      );
    }
  }

  error_message(error) {
    window.confirm("API rate limit exceeded -> Please Try Again");
    window.open(
      'https://developer.github.com/v3/#rate-limiting',
      '_blank'
    );
    console.log('Error: ', error);
  }

  onChange(event) {
    this.setState({typed: event.target.value});

    // fetch('https://api.github.com/search/users?state:open&order=asc&q=' + event.target.value)
    fetch('https://api.github.com/search/users?state:open&order=asc&per_page=15&q=' + event.target.value)
      .then(response => response.json())
      .then(parsedJSON => parsedJSON.items.map(user => (
        {
          name: `${user.login}`,
          thumbnail: `${user.avatar_url}`,
          page_url: `${user.html_url}`
        }
      )))
      .then(users => this.setState({
        users
      }))
      .catch(error => this.error_message(error));
  }


  render() {
    const {users, cursor} = this.state;

    return (
      <div className="search_container">
        <div className="search">
          <input type="text" placeholder="Search a Github User..." value={this.state.typed} className="search" onChange={this.onChange.bind(this)} autoFocus onKeyDown={this.key_events}/>

          <ul className="user_list" onKeyDown={this.key_events} ref={(search_focus) => {
            this.searchListFocus = search_focus;
          }} tabIndex="-1">
            {
              this.state.typed !== '' && users.length > 0 ?
                users.map((user, i) => {
                  return <li key={user.name} className={cursor === i ? 'active' : null}>
                    <a href={user.page_url} target="_blank" rel="noopener noreferrer" ref={(child) => {
                      this.child_element = child;
                    }}>
                      <span>{user.name}</span>
                      <img src={user.thumbnail} alt={user.thumbnail}/>
                    </a>
                  </li>
                }) : ''
            }
          </ul>
        </div>
      </div>
    );
  }
}

export default Search;
