Codeminer42/Punchclock

View on GitHub
app/javascript/packs/components/Form.js

Summary

Maintainability
F
3 days
Test Coverage
import React from 'react';
import Select from 'react-select2-wrapper';
import { compareHours } from '../utils/calendar';

class Form extends React.Component{
  state = {
    selectedProject: "",
    hasConfirmedOperation: false,
    workPeriods: {
      from1: "09:00",
      to1: "12:00",
      from2: "13:00",
      to2: "18:00",
      areValid: true
    }
  }

  render() {
    const { calendar: { selecteds } } = this.props;
    const workPeriods = this.state.workPeriods;

    const isSelectedsEmpty = selecteds.isEmpty();
    const isSaveButtonDisabled = isSelectedsEmpty || !!!this.state.selectedProject
    const invalidWorkPeriods = !workPeriods.areValid;

    const projectsList = Projects.map((p) =>  {
      return {text: p[1], id: p[0]}
    });

    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
        <div className="form-container mb-4">
          {/* Form Header */}
          <div className="d-flex justify-content-between align-items-baseline selected-days-container">
            <h6>Selecionado ({this.props.calendar.selecteds.size})</h6>
            <div className="d-flex align-items-center">
              <button
                className="btn btn-outline-secondary btn-sm text-dark mr-2"
                disabled={isSelectedsEmpty}
                type="button"
                onClick={() => {this.handleDeselect()}}
              >
                Remover seleção <i className="fa fa-times-circle fa-sm"></i>
              </button>
              <button
                className="btn btn-outline-danger btn-sm text-danger"
                disabled={isSelectedsEmpty}
                type="button"
                onClick={() => {this.handleErase()}}
              >
                  Apagar <i style={{color: "#c61515"}} className="fa fa-trash fa-sm"></i>
              </button>
            </div>
          </div>
          {/* Form Inputs Control */}
          <div className="row p-3">
            <div className="col select-container">
              <Select
                ref="project"
                value={this.state.selectedProject}
                data={projectsList}
                disabled={isSelectedsEmpty}
                options={{ placeholder: 'Projeto' }}
                onChange={(e) => this.handleProjectChange(e)}
                onOpen={() => this.focusOnSearch()}
              />
            </div>
            <div className="col">
              <div className="d-flex align-items-center">
                <i style={{color: isSelectedsEmpty ? "#9ea8ad" : "#555"}} className="fa fa-coffee fa-lg"></i>
                <input
                  disabled={isSelectedsEmpty}
                  placeholder="De"
                  ref="from1"
                  name="from1"
                  type="time"
                  defaultValue={workPeriods.from1}
                  className="form-control form-control-sm w-auto ml-1"
                  onChange={this.handleValidWorkPeriods.bind(this)} />
                <span className="mx-1">-</span>
                <input
                  disabled={isSelectedsEmpty}
                  placeholder="Até"
                  ref="to1"
                  name="to1"
                  type="time"
                  defaultValue={workPeriods.to1}
                  className="form-control form-control-sm w-auto"
                  onChange={this.handleValidWorkPeriods.bind(this)} />
              </div>
            </div>
            <div className="col">
              <div className="d-flex align-items-center">
                <i style={{color: isSelectedsEmpty ? "#9ea8ad" : "#555"}} className="fa fa-utensils fa-lg"></i>
                <input
                  disabled={isSelectedsEmpty}
                  placeholder="De"
                  ref="from2"
                  name="from2"
                  type="time"
                  defaultValue={workPeriods.from2}
                  className="form-control form-control-sm w-auto ml-1"
                  onChange={this.handleValidWorkPeriods.bind(this)} />
                <span className="mx-1">-</span>
                <input
                  disabled={isSelectedsEmpty}
                  placeholder="Até"
                  ref="to2"
                  name="to2"
                  type="time"
                  defaultValue={workPeriods.to2}
                  className="form-control form-control-sm w-auto"
                  onChange={this.handleValidWorkPeriods.bind(this)} />
              </div>
            </div>
            <div className="col">
              <input className="w-100" disabled={isSaveButtonDisabled || invalidWorkPeriods} type="submit" value="Salvar" />
            </div>
          </div>
        </div>
      </form>
    );
  }

  /* Removes the double confirmation prompt */
  componentDidUpdate() {
    const { currentAllocationId, selecteds } = this.props.calendar;
    const selectedProject = this.state.selectedProject
    const selectedsEmpty = selecteds.size == 0;

    if(selectedsEmpty && selectedProject !== currentAllocationId && !selectedProject && currentAllocationId) {
      this.setState({ selectedProject: currentAllocationId });
    }

    if (this.state.hasConfirmedOperation) {
      this.handleSave();
      this.setState({ hasConfirmedOperation: false })
    }
  }

  handleSave(e) {
    this.props.onSaveSheets(
      this.props.calendar.deleteds,
      this.props.calendar.sheets,
      this.props.calendar.sheetsSaveds
    );
  }

  handleSubmit(e) {
    e.preventDefault();
    this.props.onSetTimeSheet([
        { from: this.refs.from1.value,
          to: this.refs.to1.value,
          project_id: this.refs.project.el.val()},
        { from: this.refs.from2.value,
          to: this.refs.to2.value,
          project_id: this.refs.project.el.val()}
      ],
      this.props.calendar.selecteds,
      this.props.calendar.sheets,
      this.props.calendar.deleteds
    );
    this.setState({ hasConfirmedOperation: true, selectedProject: "" })
  }

  areValidWorkPeriods(from1, to1, from2, to2) {
    const firstCondition = compareHours({ firstHour: from1, secondHour: to1 }) && compareHours({ firstHour: from2, secondHour: to2 })
    const secondCondition = compareHours({ firstHour: from1, secondHour: from2 }) && compareHours({ firstHour: to1, secondHour: to2 })

    return firstCondition && secondCondition;
  }

  handleValidWorkPeriods({target: { name, value }}) {
    const updatedWorkPeriods = {
      ...this.state.workPeriods,
      [name]: value,
    }

    const { from1, to1, from2, to2 } = updatedWorkPeriods

    this.setState({
      workPeriods: { ...updatedWorkPeriods,
      areValid: this.areValidWorkPeriods(from1, to1, from2, to2)
    }})
  }

  handleErase() {
    this.props.onErase(
      this.props.calendar.selecteds,
      this.props.calendar.sheets,
      this.props.calendar.deleteds,
      this.props.calendar.sheetsSaveds,
    );
    this.setState({ hasConfirmedOperation: true })
  }

  handleDeselect() {
    this.props.onDeselect();
  }

  handleProjectChange(e) {
    this.setState({ selectedProject: e.currentTarget.value })
  }

  focusOnSearch() {
    $(".select2-search__field")[0].focus()
  }
}

export default Form;