React App: Bootstrap

Aim

Add styles to the reactapp.

Summary

Add several buttons to filter data and show the most recent temperature. Note I have focussed on temperature only.

../_images/reactapp_bootstrap_mobile.png

Install

cd homesensors/reactapp
npm install --save react-bootstrap
npm install --save bootstrap

Code listing

import React, { Component } from 'react'
import './App.css'
import {Button, ButtonToolbar, DropdownButton, MenuItem} from 'react-bootstrap/lib'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/css/bootstrap-theme.css'


class App extends Component {
    constructor(props){
    super(props)

    this.measurementsFilter.bind(this)
    this.dropdownSelectionHandle.bind(this)

    this.state={
        data: [],
        pageLoadDate: "",
        sensorNames: [],
        sensorLocations: [],
        sensorMeasurementType: [],
        temperature: "loading",
        days: 28,
        button7: "primary",
        button28: "success",
        button365: "primary",
        focusName: ""
    }

}

        componentDidMount() {
            this.setState({
                pageLoadDate: new Date()
            })
        }

        componentWillMount() {
            this.getDataFromApi()
        }


        getDataFromApi() {
            return fetch('/homesensors/api/v1.0/sensor_data', {credentials: 'same-origin'})
                .then((response) => response.json())
                .then((responseJson) => {
                    this.setState({
                        data: responseJson.data
                }, () =>  this.measurementsFilter(this.state.data, this.state.days))
                })
                .catch((error) => {
                     console.error(error)
            })
        }


        measurementsFilter(arrObjects, days) {
            // copy
            var data = arrObjects.slice()

            // convert date
            for (var j=0; j<data.length; j++){
                data[j].dsCollected = new Date(data[j].dsCollected)
            }

            // set n days to filter
            var d = new Date(new Date().setDate(new Date().getDate()-days))

            // filter time interval
            var filteredArray = data.filter(el=> {
            return el.dsCollected >= d
            })

            // get sensor attributes
            var names = this.sensorAttrList(filteredArray, "name")
            var locs = this.sensorAttrList(filteredArray, "location")
            var mtype = this.sensorAttrList(filteredArray, "measurementType")

            // filter temp data
            var tempArray = filteredArray.filter(el=> {
                return el.measurementType === "temp"
            })

            var fName = this.focusSensorName(tempArray, this.state.focusName, names)
            var fValue = this.focusSensorValue(tempArray, fName)


            // save state
            this.setState({
                sensorNames: names,
                sensorLocations: locs,
                sensorMeasurementType: mtype,
                focusName: fName,
                focusValue: fValue,
                temperature: tempArray,
                days: days
           })

        }


        sensorAttrList(fArray, key) {
            var sensorAttributes = []
            for (var i=0; i<fArray.length; i++){
                if (sensorAttributes.includes(fArray[i][key])){
                    continue
                } else {
                    sensorAttributes.push(fArray[i][key])
                }
            }
            return sensorAttributes
        }


        focusSensorValue(fArray, sensorName) {
            // filter data by sensor name
            // then, take the most recent record (last record)
            var fValue = fArray.filter(el=> {
                 return el.name === sensorName
            })

            // treat undefined variable (occurs when filter returns no data)
            if (fValue.slice(-1)[0] == null) {
                fValue = "No data"
            } else {
                fValue = fValue.slice(-1)[0]["value"] + "°C"
            }
            return fValue
        }


        focusSensorName(fArray, sensorName, namesList) {
            // name of sensor with most recent record
            var startName = fArray.slice(-1)[0]["name"]

           // set sensor name to focus on
           var fName = (sensorName === "" & namesList.length > 1)
               ? startName
               : sensorName

           // treat undefined variable (occurs when filter returns no data)
           if (fName == null) {
               fName = "Select"
           }

           return fName
        }


        sevenDayHandle(){
            this.measurementsFilter(this.state.data, 7)
            this.setState({
                button7: "success", //change color of button7 to green
                button28: "primary",
                button365: "primary"
            })
        }

        twentyEightDayHandle(){
            this.measurementsFilter(this.state.data, 28)
            this.setState({
                button7: "primary",
                button28: "success", //change color of button28 to green
                button365: "primary"
           })
        }

        oneYearHandle(){
            this.measurementsFilter(this.state.data, 365)
            this.setState({
                 button7: "primary",
                 button28: "primary",
                 button365: "success" //change color of button365 to green
            })
        }

        dropdownSelectionHandle(sn, n){
            this.setState({
                focusName: sn[n],
                focusValue: this.focusSensorValue(this.state.temperature, sn[n])
            })
        }

        render() {
            let button7col = this.state.button7
            let button28col = this.state.button28
            let button365col = this.state.button365
            let sn = this.state.sensorNames

            let menuItems = []
                for (var i=0; i < this.state.sensorNames.length; i++){
                    var key = i.toString()
                    menuItems.push(<MenuItem key={key} eventKey={key}>
                        {this.state.sensorNames[i]}
                    </MenuItem>)
                }


            const buttonsInstance = (
                <div className="wrapper">
                     <ButtonToolbar>
                         <DropdownButton bsStyle="info" id="1" title={this.state.focusName}
                             onSelect = {this.dropdownSelectionHandle.bind(this, sn)}
                         >
                              {menuItems}
                         </DropdownButton>
                         <Button bsStyle={button7col}
                             onClick={this.sevenDayHandle.bind(this)}>
                                  7 days
                         </Button>
                         <Button bsStyle={button28col}
                             onClick={this.twentyEightDayHandle.bind(this)}>
                                  28 days
                         </Button>
                         <Button bsStyle={button365col}
                             onClick={this.oneYearHandle.bind(this)}>
                                  1 year
                         </Button>
                     </ButtonToolbar>
                </div>
            )

                return (
                    <div className="App">

                        <header className="App-header">
                            <h1 className="App-title">Garden Monitor</h1>
                            <p> {String(this.state.pageLoadDate)} </p>
                        </header>

                        {buttonsInstance}

                        <div className="TempContainer">
                            <h3 className="TempValue">{this.state.focusValue}</h3>
                        </div>
                    </div>
                )
            }
    }

    export default App

Edit App.css

.App {
  text-align: center;
}


.App-header {
  background-color: #222;
  height: 90px;
  padding-top: 5px;
  padding-bottom: 20px;
  color: white;
}

.App-title {
  font-size: 2em;
}

.form-actions {
  margin:0;
  background-color: transparent;
  text-align: center;
}

.wrapper {
  width: 100%;
  padding-top: 10px;
  display: flex;
  justify-content: center;
}

.TempValue {
  margin: 0;
}

.TempContainer {
  width: 200px;
  //height: 50px;
  //border-radius: 15px;
  //border-width: 3px;
  //border-style: solid;
  //border-color: black;
  margin: 0 auto;
  margin-top: 10px;
}