Home Reference Source Test Repository

app/modules/users/UserApp.component.js

'use strict';

// Styles
import './UserApp.scss';

// Dependencies
import React          from 'react';
import { connect }    from 'react-redux';

// Actions
import {
  fetchUsers
}                     from './reducers/users.reducer';

// Presentational Components

/**
 * Generate user item with a picture and a link to the profile
 * @param {!userObj} props
 * user object
 * @return {ReactDOM}
 * generate `<li class="userList_item"/>` markup
 */
export const User = (
  {
    login,
    url,
    avatar_url
  }
) =>
  <li className="userList_item">
    <a className="userList_itemLink"
       href={url}
       target="_blank">
      <img src={avatar_url}
           alt={`${login} avatar`} />
      <span>{login}</span>
    </a>
  </li>;

/**
 * Generate a list of users
 * @param {!Object} props
 * react props object
 * @param {!Array<userObj>} props.users
 * list of user object
 * @return {ReactDOM}
 * generate `<ul class="userList"/>` markup
 */
export const UserList = ({ users }) =>
  <ul className="userList">
    { users.map(user => <User key={user.id} {...user}/>) }
  </ul>;

/**
 * Generate a visual error when request fails
 * @param {!Object} props
 * react props object
 * @param {!Object} props.error
 * error object to display
 * @param {!string} props.error.message
 * error message
 * @return {ReactDOM}
 * generate `<p class="userError"/>` markup
 */
export const UserError = ({ error }) =>
  <p className="userError">
    <span className="userError_title">unable to get user list</span>
    <span className="userError_message">{error.message}</span>
  </p>;

/**
 * Generate a header to display list title and button to launch user query
 * @param {!Object} props
 * react props object
 * @param {!Object} props.onClick
 * function to run when refresh button is clicked
 * @return {ReactDOM}
 * generate `<div class="userHeader"/>` markup
 */
export const UserHeader = ({ onClick }) =>
  <div className="userHeader">
    <p className="userHeader_title">user list</p>
    <button className="userHeader_refresh"
            onClick={onClick}>refresh
    </button>
  </div>;

// Container Components

/**
 * Generate a header to display list title and button to launch user query
 * @param {!Object} props
 * react props object
 * @param {!Array<userObj>} props.users
 * list of user object
 * @param {!Object} props.error
 * error object to display
 * @param {!string} props.error.message
 * error message
 * @param {!Object} props.onRefreshButtonClick
 * function to run when refresh button is clicked
 * @return {ReactDOM}
 * generate `<section class="userApp"/>` markup
 */
export const UserApp = (
  {
    users,
    error,
    onRefreshButtonClick
  }
) =>
  <section className="userApp">
    <UserHeader onClick={onRefreshButtonClick}/>
    {
      error ? <UserError error={error}/> : <UserList users={users}/>
    }
  </section>;

const MapStateToProps = state => ({
    users : state.users.data,
    error : state.users.error
  });

const MapDispatchToProps = dispatch => ({
    onRefreshButtonClick : () => dispatch(fetchUsers())
  });

/**
 * connect react component to redux state
 * @return {ReactDOM}
 * generate connected `<section class="userApp"/>` markup
 */
export default connect(
  MapStateToProps,
  MapDispatchToProps
)(UserApp);