Skip to content

# Step 08 — AddReading component

Gerald Goh edited this page Aug 11, 2020 · 1 revision

Create header component

app/javascript/components/Head.jsx

import React from 'react';

const Head = () => (
  <div>
    <nav className="navbar navbar-inverse bg-blue fixed-top">
      <h1 className="navbar-brand abs">Add Reading</h1>
    </nav>
  </div>
);

export default Head;

Create input form

app/javascript/components/ReadingForm.jsx

/* eslint-disable react/destructuring-assignment, react/no-unused-state */
import React from 'react';
import axios from 'axios';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import {
  Bedroom,
  Study,
  Garage,
  Living,
  Kitchen,
  Guest,
} from './Rooms';

class ReadingForm extends React.Component {
  constructor(props) {
    super(props);
    const defaultState = {
      currentStep: 1,
      bedroom: '',
      study: '',
      garage: '',
      living: '',
      kitchen: '',
      guest: '',
      units: '',
      quota: '',
    };
    this.state = defaultState;
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.prev = this.prev.bind(this);
    this.next = this.next.bind(this);
  }

  componentDidMount() {
    const userID = JSON.parse(localStorage.getItem('redux')).id;
    const { units } = this.state;
    axios.get(`/api/v1/users/${userID}`, { units })
      .then((response) => response.data)
      .then((response) => {
        if (response.code === 200) {
          this.setState({
            units: response.data.units,
            quota: (Number(response.data.units) / 30) / 6,
          });
        } else if (response.code === 401) {
          this.setState({
            errors: response.errors,
          });
        }
      });
  }

  handleChange(event) {
    const { name, value } = event.target;
    this.setState({
      [name]: value,
    });
  }

  handleSubmit(event) {
    event.preventDefault();
    const {
      bedroom, study, garage, living, kitchen, guest, units,
    } = this.state;
    const consumption = Number(bedroom)
    + Number(study)
    + Number(garage)
    + Number(living)
    + Number(kitchen)
    + Number(guest);
    const available = (units / 30) - consumption;
    const saved = Math.floor(100 - (100 * (consumption / (units / 30))));
    axios.post('/api/v1/readings', {
      bedroom, study, garage, living, kitchen, guest, consumption, available, saved,
    })
      .then((response) => response.data)
      .then((response) => {
        if (response.code === 400) {
          this.setState({
            errors: response.errors,
          });
        } else if (response.code === 200) {
          this.setState({
            bedroom: '',
            study: '',
            garage: '',
            living: '',
            kitchen: '',
            consumption: '',
            available: '',
            saved: '',
          });
          this.props.history.push('/readings');
        }
      });
  }

  next() {
    let { currentStep } = this.state;
    currentStep = currentStep === 6 ? 6 : currentStep + 1;
    this.setState({
      currentStep,
    });
  }

  prev() {
    let { currentStep } = this.state;
    currentStep = currentStep === 1 ? 1 : currentStep - 1;
    this.setState({
      currentStep,
    });
  }

  previousButton() {
    const { currentStep } = this.state;
    if (currentStep !== 1) {
      return (
        <button
          type="button"
          id="prevBtn"
          onClick={this.prev}
        >
          Previous
        </button>
      );
    }
    return null;
  }

  nextButton() {
    const { currentStep } = this.state;
    if (currentStep < 6) {
      return (
        <button
          type="button"
          id="nextBtn"
          onClick={this.next}
        >
          Next
        </button>
      );
    }
    return null;
  }

  render() {
    return (
      <>
        <form id="regForm" onSubmit={this.handleSubmit}>
          <Bedroom
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            bedroom={this.state.bedroom}
          />
          <Study
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            study={this.state.study}
          />
          <Garage
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            garage={this.state.garage}
          />
          <Living
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            living={this.state.living}
          />
          <Kitchen
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            kitchen={this.state.kitchen}
          />
          <Guest
            currentStep={this.state.currentStep}
            quota={this.state.quota}
            handleChange={this.handleChange}
            guest={this.state.guest}
          />
          <div className="row justify-content-center btn-box">
            {this.previousButton()}
            {this.nextButton()}
          </div>
        </form>
      </>
    );
  }
}

ReadingForm.propTypes = {
  // eslint-disable-next-line react/forbid-prop-types
  history: PropTypes.object.isRequired,
};

export default withRouter(ReadingForm);

Create Rooms components

app/javascript/components/Rooms.jsx

import React from 'react';
import InputGraph from '../graph/InputGraph'

export function Bedroom(props) {
  if (props.currentStep !== 1) {
    return null
  } 
  return(
    <React.Fragment>         
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Bedroom Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.bedroom} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="bedroom"
          name="bedroom"
          type="number"
          placeholder="Enter bedroom reading"
          value={props.bedroom}
          onChange={props.handleChange}
        />      
      </div>
    </React.Fragment>    
  );
}

export function Study(props) {
  if (props.currentStep !== 2) {
    return null
  } 
  return(
    <React.Fragment>         
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Study room Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.study} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="study"
          name="study"
          type="number"
          placeholder="Enter study reading"
          value={props.study}
          onChange={props.handleChange}
        />      
      </div>
    </React.Fragment>  
  );
}

export function Garage(props) {
  if (props.currentStep !== 3) {
    return null
  } 
  return(
    <React.Fragment>         
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Garage Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.garage} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="garage"
          name="garage"
          type="number"
          placeholder="Enter garage reading"
          value={props.garage}
          onChange={props.handleChange}
        />      
      </div>
    </React.Fragment>    
  );
}

export function Living(props) {
  if (props.currentStep !== 4) {
    return null
  } 
  return(
    <React.Fragment>         
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Living Room Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.living} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="living"
          name="living"
          type="number"
          placeholder="Enter living reading"
          value={props.living}
          onChange={props.handleChange}
        />      
      </div>
    </React.Fragment>  
  );
}

export function Kitchen(props) {
  if (props.currentStep !== 5) {
    return null
  } 
  return(
    <React.Fragment>         
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Kitchen Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.kitchen} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="kitchen"
          name="kitchen"
          type="number"
          placeholder="Enter kitchen reading"
          value={props.kitchen}
          onChange={props.handleChange}
        />      
      </div>
    </React.Fragment>    
  );
}

export function Guest(props) {
  if (props.currentStep !== 6) {
    return null
  } 
  return(
    <React.Fragment>
      <div className="row justify-content-center">
        <div className="row justify-content-center reading-header">
          <h4>Take your Guest Room Reading</h4>
        </div>
        <div className="graph-content">
          <InputGraph strokeWidth={2} percentage={props.guest} />
        </div>       
      </div>
      <div className="row justify-content-center reading-input">      
        <input
          className="form-control"
          id="guest"
          name="guest"
          type="number"
          placeholder="Enter guest reading"
          value={props.guest}
          onChange={props.handleChange}
        />      
      </div>
    <button className="btn btn-success btn-block">Submit</button>
    </React.Fragment>
  );
}

Create Graph Component

app/javascript/components/graph/InputGraph.jsx

import React from 'react';

const InputGraph = ({ strokeWidth, percentage }) => {
	const radius = (50 - strokeWidth / 2);
    const pathDescription = `
      M 50,50 m 0,-${radius}
      a ${radius},${radius} 0 1 1 0,${2 * radius}
      a ${radius},${radius} 0 1 1 0,-${2 * radius}
    `;

    const diameter = Math.PI * 2 * radius;
    const progressStyle = {
			stroke: '#42B5E8',
  		strokeLinecap: 'round',
      strokeDasharray: `${diameter}px ${diameter}px`,
      strokeDashoffset: `${((100 - percentage) / 100 * diameter)}px`,
    };

    return (
      <svg
        className={'CircularProgressbar'}
        viewBox="0 0 100 100"
				width={300}
				height={300}
        
      >
        <path
          className="CircularProgressbar-trail"
          d={pathDescription}
          strokeWidth={strokeWidth}
          fillOpacity={0}
					style={{
						stroke: '#FFFFFF',
					}}
        />

        <path
          className="CircularProgressbar-path"
          d={pathDescription}
          strokeWidth={strokeWidth}
          fillOpacity={0}
          style={progressStyle}
        />

        <text
          className="CircularProgressbar-text"
          x={50}
          y={50}
					style={{
						fill: '#007dbc',
  					fontSize: '14px',
  					dominantBaseline: 'central',
  					textAnchor: 'middle',
					}}
        >
          {`${percentage} Units`}
        </text>
      </svg>
    );
};

export default InputGraph;

Create Reading Containers

app/javascript/containers/AddReading.jsx

import React from 'react';
import Head from '../components/addReading/Head';
import ReadingForm from '../components/addReading/ReadingForm';
import Navbar from '../components/Navbar';

export default () => (
  <div>
    <Head />
    <ReadingForm />
    <Navbar />
  </div>
);

Add route

app/javascript/routes/index.jsx

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from '../containers/Home';
import Readings from '../containers/Readings';
import AddReading from '../containers/AddReading';
import reducer from "../reducer/sessions"
import { Provider } from "react-redux"
import { compose, createStore } from 'redux';
import persistState from 'redux-localstorage'
import PrivateRoute from "./privateRoute"

const store = createStore(
  reducer, compose(persistState())
)

export default (
  <Provider store={store}>
    <Router>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/addreading" component={AddReading} />
        <PrivateRoute path="/readings" component={Readings} />
      </Switch>
    </Router>
  </Provider>  
);

export {store};

Add CSS for graphs

app/assets/stylesheets/custom.css.scss

.
.
.graph-content {
  margin: 10% 0 10% 0;
}

.reading-input {
  margin: 5% 0 5% 0;
}
.
.