AppStateESS/InternshipInventory

View on GitHub
javascript/affiliationAgreement/AffiliateList.jsx

Summary

Maintainability
F
1 wk
Test Coverage
import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import {CSSTransition} from 'react-transition-group'
import classNames from 'classnames';

class ErrorMessagesBlock extends React.Component {
    render() {
        if(this.props.errors === null){
            return '';
        }

        var errors = this.props.errors;

        return (
            <div className="row">
                <div className="col-sm-12 col-md-6 col-md-push-3">
                    <div className="alert alert-warning" role="alert">
                        <p><i className="fa fa-exclamation-circle fa-2x"></i> Warning: {errors}</p>

                    </div>
                </div>
            </div>
        );
    }
}

class DepartmentList extends React.Component {
    render() {
        return (
            <option value={this.props.id}>{this.props.name}</option>
        )
    }
}

class ShowAffiliate extends React.Component {
    constructor(props){
        super(props);

        this.handleChange = this.handleChange.bind(this);
        this.onShowAffiliate = this.onShowAffiliate.bind(this);
    }
    handleChange() {
        this.props.onShowAffiliate(this.props.id);
    }
    onShowAffiliate() {
        window.location =  "index.php?module=intern&action=showAffiliateEditView&affiliation_agreement_id=" + this.props.id;
    }
    render(){
        var b = new Date().getTime();
        var a = new Date(this.props.end_date * 1000);
        var year = a.getFullYear();
        var month = a.getMonth() + 1;
        var date = a.getDate();
        var dateForm = month + '/' + date + '/' + year;
        var active = 'Active';

        var green = false, yellow = false, red = false;

        var expiration = (a - b)/1000;

        if(this.props.auto_renew){
            green = true;
            active = 'Active (auto-renewed)';
        }else if(expiration < 0){
            red = true;
            active = 'Expired';
        } else if(expiration < 7884000) {
            yellow = true;
        } else {
            green = true;
        }

        var alertClass = classNames({
            'alert-danger': red,
            'alert-success': green,
            'alert-warning': yellow
        });

        return (
            <tr role="button" id={this.props.id} className={alertClass} onClick={this.onShowAffiliate} key={this.props.id}>

                <td>{this.props.name}</td>
                <td>{dateForm}</td>
                <td>{active}</td>

            </tr>
        );
    }
}

// Main module that calls several components to build
// the affiliate agreements list screen.
class AffiliateList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            mainData: null,
            displayData: null,
            deptData: null,
            errorWarning: null,
            messageType: null,
            searchDept: null,
            searchName: '',
            textData: "",
            sortBy: '',
            showFilter: ''
        };

        this.getData = this.getData.bind(this);
        this.getDept = this.getDept.bind(this);
        this.onSearchListChange = this.onSearchListChange.bind(this);
        this.searchListByDept = this.searchListByDept.bind(this);
        this.onSortByChange = this.onSortByChange.bind(this);
        this.onShow = this.onShow.bind(this);
        this.updateDisplayData = this.updateDisplayData.bind(this);
    }
    UNSAFE_componentWillMount() {
        // Grabs department and affiliate agreement
        // data at start of execution.
        this.getData();
        this.getDept();
    }
    getData() {
        $.ajax({
            url: 'index.php?module=intern&action=AffiliateListRest',
            type: 'GET',
            dataType: 'json',
            success: function(data) {
                this.setState({mainData: data,
                                displayData: data});
            }.bind(this),
            error: function(xhr, status, err) {
                alert("Failed to grab displayed data.")
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    }
    getDept() {
        //Fetch list of departments
        $.ajax({
            url: 'index.php?module=intern&action=deptRest',
            action: 'GET',
            dataType: 'json',
            success: function(data) {
                data.unshift({name: "Select a department", id: "-1"});
                this.setState({deptData: data});
            }.bind(this),
            error: function(xhr, status, err) {
                alert("Failed to grab deptartment data.")
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    }
    onSearchListChange(e) {

        var name = null;

        // Saves the name that the user is looking for.
        name = e.target.value.toLowerCase();
        this.setState({searchName: name});

        this.updateDisplayData(name, this.state.sortBy, this.state.showFilter);

    }
    //Method for taking an array and searching it by name, returns array.
    searchListByName(data, nameToSearch) {
      var filtered = [];

      // Looks for the name by filtering the mainData
      for (var i = 0; i < data.length; i++) {
          var item = data[i];

          // Make the item, name lowercase for easier searching
          if (item.name.toLowerCase().includes(nameToSearch)) {
              filtered.push(item);
          }
      }
      return filtered;

    }
    searchListByDept(e) {
        var dept = null;

        try {
            // Saves the dept that the user is looking for.
            dept = e.target.value;
        } catch (err) {
            dept = this.state.searchDept;
        }
        if(dept === "-1"){
            this.getData();
            return;
        }

        $.ajax({
            type: 'GET',
            url: 'index.php?module=intern&action=AffiliateDeptAgreementRest',
            dataType: 'json',
            data: {dept : dept},
            success: function(data)
            {
                this.setState({searchDept: dept,
                                mainData: data,
                                displayData: data});
            }.bind(this),
            error: function(xhr, status, err) {
                alert("Failed to grab searched list.")
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    }
    // Returns sorted array to be used in createList function
    onSortByChange(e) {
        var sort = null;

        //Saves sorting option that was clicked.
        sort = e.target.value;
        this.setState({sortBy: sort});

        this.updateDisplayData(this.state.searchName, sort, this.state.showFilter);

    }
    //Method for storing the selected sort order and setting sortBy state.
    sortBy(unsorted, typeOfSort) {
      var sorted = [];

      // Different logic for different types of sorts,
      // all utilizing sort function.
      switch(typeOfSort) {
          case 'sortByAZ':

              sorted = unsorted.sort(function (a, b) {
                  if (a.name < b.name) return -1;
                  if (a.name > b.name) return 1;
                  return 0;
              });
              break;
          case 'sortByZA':

              sorted = unsorted.sort(function (a, b) {
                  if (a.name > b.name) return -1;
                  if (a.name < b.name) return 1;
                  return 0;
              });
              break;
          case 'SoonerToLater':

              sorted = unsorted.sort(function (a,b) {
                  if (a.end_date < b.end_date){
                    if(a.auto_renew && !b.auto_renew){
                        return 1;
                    } else{
                        return -1;
                    }
                  }
                  if (a.end_date > b.end_date) return 1;
                  return 0;
              });
              break;
          case 'LaterToSooner':

              sorted = unsorted.sort(function (a,b) {
                  if (a.end_date > b.end_date){
                    if(!a.auto_renew && b.auto_renew){
                        return 1;
                    } else{
                        return -1;
                    }
                  }
                  if (a.end_date < b.end_date) return 1;
                  return 0;
              });
              break;
          default:
              sorted = unsorted;
      }
      return sorted;

    }
    onShow(e) {
        var option = null;

        // Saves filter option.
        option = e.target.value;
        this.setState({showFilter: option});

        this.updateDisplayData(this.state.searchName, this.state.sortBy, option);

    }
    viewShowFilter(data, filter) {
        var filtered = [];

        for (var i = 0; i < data.length; i++) {
            var item = data[i];

            // Finding out if expired or not.
            var current = new Date().getTime();
            var itemDate = new Date(item.end_date * 1000);
            var expiration = (itemDate - current)/1000;

            if (filter === 'active') {
                if (!item.auto_renew && expiration > 0) {
                    filtered.push(item);
                }
            }
            else if (filter ==='auto_renew') {
                if (item.auto_renew) {
                    filtered.push(item);
                }
            }
            else if (filter ==='expired') {
                if (!item.auto_renew && expiration < 0) {
                    filtered.push(item);
                }
            }
            else {
                filtered.push(item);
            }
        }
        return filtered;

    }
    // Organizes the order of the sort/filter functions to update the data displayed.
    // searchName and sort are both states.
    updateDisplayData(typedName, sort, showFilter) {
        var filtered = [];

        // First filters data.
        if (showFilter !== null) {
            filtered = this.viewShowFilter(this.state.mainData, showFilter);
        } else {
            filtered = this.state.mainData;
        }

        // Second searches list for name.
        if (typedName !== null) {
            filtered = this.searchListByName(filtered, typedName);
        }

        // Third sorts list.
        if (sort !== null) {
            filtered = this.sortBy(filtered, sort);
        } else {
            filtered = this.sortBy(filtered, 'sortByAZ');
        }

        this.setState({displayData: filtered});

    }
    render() {

        var AffiliateData = null;
        if (this.state.mainData != null) {
            AffiliateData = this.state.displayData.map(function (affil) {
                return (
                    <ShowAffiliate key={affil.id}
                        name={affil.name}
                        end_date={affil.end_date}
                        id={affil.id}
                        auto_renew={affil.auto_renew} />
                );
            });
        } else {
            AffiliateData = <tr><td></td></tr>;
        }

        var dData = null;
        if (this.state.deptData != null) {
            dData = this.state.deptData.map(function (dept) {
            return (
                    <DepartmentList key={dept.id}
                        name={dept.name}
                        id={dept.id} />
                );
            });
        } else {
            dData = "";
        }

        var errors;
        if (this.state.errorWarning == null){
            errors = '';
        } else {
            errors = <ErrorMessagesBlock key="errorSet" errors={this.state.errorWarning} messageType={this.state.messageType} />
        }

        return (
            <div className="affiliateList">

                <CSSTransition timeout={500}>
                    <div>
                        {errors}
                    </div>
                </CSSTransition>

                <div className="row">
                    <div className="col-md-4">
                        <h2>Affiliation Agreements</h2>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-3">
                        <a href="index.php?module=intern&action=addAgreementView" className="btn btn-md btn-success"><i className="fa fa-plus"></i> Add New Agreement </a>
                    </div>
                </div>
                <br></br>
                <div className="row">
                    <div className="col-md-3">
                        <div className="input-group">
                            <label>Search by Name</label>
                            <input type="text" className="form-control" placeholder="Search for..." onChange={this.onSearchListChange} />
                        </div>
                    </div>
                    <div className="col-md-3">
                        <div className="form-group">
                            <label>Search by Department</label>
                            <select className="form-control" onChange={this.searchListByDept}>
                                {dData}
                            </select>
                        </div>
                    </div>
                    <div className="col-md-3">
                        <div className="form-group">
                            <label>Sort By</label>
                            <select className="form-control" onChange={this.onSortByChange} value={this.state.value}>
                                <option value="-1">Select an option</option>
                                <option value="sortByAZ">Name: A-Z</option>
                                <option value="sortByZA">Name: Z-A</option>
                                <option value="SoonerToLater">Expiration Date: Sooner to Later</option>
                                <option value="LaterToSooner">Expiration Date: Later to Sooner</option>
                            </select>
                        </div>
                    </div>
                    <div className="col-md-3">
                        <label className="control-label">Filter</label> <br />
                        <div className="btn-group" data-toggle="buttons" onClick={this.onShow} value={this.state.value}>
                            <button className="btn btn-default" value="all">
                                <input  type="radio"/>All
                            </button>
                            <button className="btn btn-default" value="active">
                                <input type="radio"/>Active
                            </button>
                            <button className="btn btn-default" value="auto_renew">
                                <input  type="radio"/>Auto
                            </button>
                            <button className="btn btn-default" value="expired">
                                <input  type="radio"/>Expired
                            </button>
                        </div>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-12">
                        <table className="table">
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Expiration Date</th>
                                    <th>Active/Expired</th>
                                </tr>
                            </thead>
                            <tbody>
                                {AffiliateData}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

        );
    }
}

ReactDOM.render(
    <AffiliateList />,
    document.getElementById('AffiliateList')
);