webtrack-extension / src / page / components / history / history.component.js
history.component.js
Raw
import  React, { Component } from 'react';
import './history.component.css';
import { Actions, ActionsGroup, ActionsButton, ActionsLabel, Toggle } from 'framework7-react';

import LocalstorageHandler from '../../../lib/LocalstorageHandler';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import * as Icons from "@fortawesome/fontawesome-free-solid"
import moment from 'moment';
import lang from '../../../lib/lang';

const STEPS = 5;
const DEFAULT_BETWEEN = {
  start: 0,
  end: STEPS
}

export default class History extends Component {

  static defaultProps = {
    allowSending: true,
    allowRemove: true,
    items: [],
    onSend: ()=>{},
    onRemove: ()=>{},
  }

  constructor(props){
    super(props);
    this.next = this.next.bind(this);
    this.back = this.back.bind(this);
    this.handleToogleFilter = this.handleToogleFilter.bind(this);
    this.id = null;
    this.storageBetween = new LocalstorageHandler('history-between', DEFAULT_BETWEEN);
    this.storageFilter = new LocalstorageHandler('history-filter', true);
    let items = this.getItems();
    this.state = Object.assign({
      between: this.storageBetween.get(),
      actionGridOpened: false
    }, items)
  }

  /**
   * [getItems return filtered and sorted array object-arrays]
   * @param  {Array} items    [default: this.props.items]
   * @param  {Number} start   [default: this.storageBetween.get().start]
   * @param  {Number} end     [default: this.storageBetween.get().end]
   * @return {Object}  [{items: [], nextItems: []}]
   */
  getItems(items=this.props.items, start=this.storageBetween.get().start, end=this.storageBetween.get().end){
    items = this.getFilterItems(items);
    if(this.storageFilter.get()) items = items.filter(e => !e.send)
    return {
      items: items.slice(start, end),
      nextItems: items.slice(end, end+STEPS)
    }
  }

  /**
   * [getItems return filtered and sorted array object-arrays]
   * @param  {Array} items    [default: this.props.items]
   * @param  {Number} start   [default: this.storageBetween.get().start]
   * @param  {Number} end     [default: this.storageBetween.get().end]
   * @return {Object}  [{items: [], nextItems: []}]
   */
  getItems(items=this.props.items, start=this.storageBetween.get().start, end=this.storageBetween.get().end){
    items = this.getFilterItems(items);
    if(this.storageFilter.get()) items = items.filter(e => !e.send)
    return {
      items: items.slice(start, end),
      nextItems: items.slice(end, end+STEPS)
    }
  }

  /**
   * [getFilterItems sort array after start time]
   * @param  {Array} items
   * @return {Array}
   */
  getFilterItems(items){    
    return items.sort((a,b) => new Date(b.start).getTime() - new Date(a.start).getTime());
  }

  /**
   * [componentDidUpdate update between range in localstorage]
   * @param  {Object} nextProps
   * @param  {Object} nextState
   */
  componentDidUpdate(nextProps, nextState){
    this.storageBetween.set(nextState.between);
  } 

  /**
   * [componentWillReceiveProps update items and nextItems]
   * @param  {Object} nextProps
   */
  UNSAFE_componentWillReceiveProps(nextProps){
    this.setState(this.getItems(nextProps.items))
  }

 

  /**
   * [handleToogleFilter description]
   * @param  {[type]} boolean [description]
   * @return {[type]}         [description]
   */
  handleToogleFilter(boolean){
    this.storageFilter.set(boolean)
    this.storageBetween.set(DEFAULT_BETWEEN)
    this.setState(Object.assign({
      between: this.storageBetween.get()
    }, this.getItems()))
  }

  /**
   * [next added STEPS-value from state.between start and end. Set items and nextItems]
   */
  next(){
    this.setState(state => {
      state.between.start = state.between.start+STEPS;
      state.between.end = state.between.start+STEPS;
      const items = this.getItems(this.props.items, state.between.start, state.between.end);
      state.items = items.items
      state.nextItems = items.nextItems
      return state;
    });
  }

  /**
   * [back subtrect STEPS-value from state.between start and end. Set items and nextItems]
   */
  back(){
    this.setState(state => {
      state.between.start = state.between.start-STEPS>0? state.between.start-STEPS: 0;
      state.between.end = state.between.start+STEPS;
      const items = this.getItems(this.props.items, state.between.start, state.between.end);
      state.items = items.items
      state.nextItems = items.nextItems
      return state;
    })
  }

  /**
   * [getAction return framework7 Actionsheet]
   * @return {JSX}
   */
  getAction(){
    const SendButton = !this.props.allowSending? null: <ActionsButton onClick={()=> this.props.onSend(this.id)}>
                                                          <FontAwesomeIcon icon={Icons.faPaperPlane} />
                                                          <span>{lang.project.history.send_title}</span>
                                                        </ActionsButton>
    const DeleteButton = !this.props.allowRemove? null: <ActionsButton onClick={()=> this.props.onRemove(this.id)}>
                                                          <FontAwesomeIcon icon={Icons.faTrash} />
                                                          <span>{lang.project.history.delete_title}</span>
                                                        </ActionsButton>
    if(this.props.allowSending || this.props.allowRemove){
      return <Actions id="action" opened={this.state.actionGridOpened} onActionsClosed={() => this.setActionsGridOpened(false)} >
               <ActionsGroup>
                 <ActionsLabel>{lang.project.history.choose_action}</ActionsLabel>
                 {SendButton}
                 {DeleteButton}
               </ActionsGroup>
               <ActionsGroup>
                 <ActionsButton color="red">{lang.modal.abort}</ActionsButton>
               </ActionsGroup>
             </Actions>
    }else{
      return null;
    }
  }

  /**
   * [setActionsGridOpened open/close actionsheet]
   * @param {boolean} b
   */
  setActionsGridOpened(b=true){
    this.setState({
      actionGridOpened: b
    })
  }

  /**
   * [selectItem set select id and open actionsheet]
   * @param  {Number} id
   */
  selectItem(id){
    this.id = id;
    this.setActionsGridOpened()
  }


  render() {
      return (
      <div>
       <div className="card data-table history">
          <table>
            <thead>
              <tr>
                <th className="label-cell">{lang.project.history.table.title}</th>
                <th className="numeric-cell">{lang.project.history.table.time}</th>
              </tr>
            </thead>
            <tbody>
              {this.state.items.map((e, i) => <tr key={i} disabled={e.send} onClick={()=> !e.send? this.selectItem(e.id): ()=>{}} >
                                 <td className="label-cell">{new URL(e.url).host}</td>
                                 <td className="numeric-cell">{moment(e.start).format('YYYY-MM-DD HH:mm:ss')}</td>
                               </tr>)
              }
            </tbody>
          </table>
          <div className="data-table-footer">
            <Toggle defaultChecked={this.storageFilter.get()} color="blue" onToggleChange={this.handleToogleFilter} />
            <span className="data-table-pagination-label">{this.state.between.start>0? this.state.between.start+1: this.state.between.start}-{this.state.between.start+this.state.items.length} of {this.props.items.length}</span>
            <div className="data-table-pagination">
              <a href="#" onClick={this.back} className={this.state.between.start==0? "link disabled": "link"}>
                <i className="icon icon-prev color-gray"></i>
              </a>
              <a href="#"
                  onClick={this.next}
                  className={this.state.nextItems==0? "link disabled": "link"}
                >
                <i className="icon icon-next color-gray"></i>
              </a>
            </div>
          </div>
        </div>
       {this.getAction()}
      </div>
    );
  }


}