quitting react router

This commit is contained in:
Eric Hulburd
2016-03-02 12:07:31 -06:00
parent d650baab6d
commit 5b218f6518
17 changed files with 164 additions and 186 deletions

View File

@@ -25,7 +25,7 @@ module.exports = {
loader: 'json'
}, {
test: /\.rt/,
loader: "react-templates-loader"
loader: "react-templates-loader?targetVersion=0.14.0"
}
]
},

View File

@@ -1,6 +1,5 @@
import React from 'react';
import Templates from 'config/templates';
import House from './../../models/house';
import {RouteHelper} from './../routes';
class EnergyComponent extends React.Component {
@@ -8,34 +7,14 @@ class EnergyComponent extends React.Component {
constructor(props){
super(props);
var energy = this;
energy.state = {
loading_energy_data: true
};
}
componentDidMount(){
var energy = this,
house = energy.context.house;
if (!house || energy.context.loading_energy_data) return false;
house.setEnergyData()
.then(()=>{
energy.setState({loading_energy_data: false});
});
var energy = this;
}
componentDidUpdate(prev_props, prev_state, prev_context){
var energy = this,
house = energy.context.house;
if (!house) return false;
if (!prev_context.house ||
prev_context.house.data.id != energy.context.house.data.id ||
!house.matchesYearState(prev_props.params)) {
energy.setState({loading_energy_data: true});
house.setEnergyData()
.then(()=>{
energy.setState({loading_energy_data: false}); // will update graph or table.
});
}
var energy = this;
}
setParam(event){
@@ -43,19 +22,9 @@ class EnergyComponent extends React.Component {
param = event.target.dataset.param,
value = event.target.dataset.value,
update = {}, route_helper;
override[param] = value;
route_helper = new RouteHelper(energy.context.house, energy.props);
if (route_helper.routeUpdated()){
route_helper.updateHouseState();
energy.context.router.push(makeRoute(house, energy.props, override));
}
}
getChildContext(){
var layout = this;
return {
loading_energy_data: layout.state.loading_energy_data
};
update[param] = value;
route_helper = new RouteHelper(energy.props, update);
if (route_helper.routeUpdated()) route_helper.updateRoute();
}
render() {
@@ -64,13 +33,7 @@ class EnergyComponent extends React.Component {
}
}
EnergyComponent.childContextTypes = {
loading_energy_data: React.PropTypes.bool.isRequired
};
EnergyComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
router: React.PropTypes.object.isRequired
};

View File

@@ -1,5 +1,5 @@
<div id="energy_view">
<div class="alert alert-warning" rt-if="this.state.loading_energy_data">
<div class="alert alert-warning" rt-if="this.props.location.state.loading_energy_data">
Retrieving energy data...
</div>
<div rt-if="this.props.view === 'graph'">
@@ -8,13 +8,13 @@
<button
data-param="graph_attr"
data-value="consumption"
rt-class="{active: this.state.graph_attr === 'consumption'}"
rt-class="{active: this.props.params.graph_attr === 'consumption'}"
onClick="{this.setAttr}"
type="button" class="btn btn-primary">Consumption</button>
<button
data-param="graph_attr"
data-value="production"
rt-class="{active: this.state.graph_attr === 'production'}"
rt-class="{active: this.props.params.graph_attr === 'production'}"
onClick="{this.setGraphAttr}"
type="button" class="btn btn-primary">Production</button>
</div>

View File

@@ -7,26 +7,27 @@ import House from './../../../models/house';
class GraphComponent extends React.Component {
componentDidMount(){
var energy_graph = this,
house = energy_graph.context.house;
if (!energy_graph.context.loading_energy_data) energy_graph.updateGraph();
var energy_graph = this;
if (energy_graph.house) energy_graph.updateGraph();
}
get house(){
return this.props.location.state && this.props.location.state.house;
}
componentDidUpdate(prev_props, prev_state, prev_context){
var energy_graph = this,
house = energy_graph.context.house;
if (energy_graph.context.loading_energy_data) {return false;}
if (!prev_context.house ||
prev_context.loading_energy_data ||
prev_context.house.id != energy_graph.context.house.id) {
energy_graph.updateGraph();
}
var energy_graph = this;
if (energy_graph.shouldUpdateGraph(prev_props)) { energy_graph.updateGraph(); }
}
shouldUpdateGraph(prev_props){
var energy_graph = this;
return energy_graph.house && !prev_props.location.state.house ||
prev_props.location.state.house.id != energy_graph.house.id;
}
updateGraph(){
var energy_graph = this,
house = energy_graph.context.house,
graph_attr = energy_graph.props.params.graph_attr;
if (energy_graph.graph === undefined){
@@ -56,7 +57,7 @@ class GraphComponent extends React.Component {
css_class: '',
min_range: 0,
max_range: 150,
values: house.energy_data
values: energy_graph.house.energy_data
});
}
@@ -68,8 +69,6 @@ class GraphComponent extends React.Component {
}
GraphComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
loading_energy_data: React.PropTypes.bool.isRequired,
router: React.PropTypes.object.isRequired
};

View File

@@ -13,7 +13,6 @@ class TableComponent extends React.Component {
}
TableComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
router: React.PropTypes.object.isRequired
};

View File

@@ -1,4 +1,4 @@
<table id="energy_table" rt-if="this.context.house" class="table">
<table id="energy_table" rt-if="this.house" class="table">
<thead>
<tr>
<th></th>
@@ -8,7 +8,7 @@
</tr>
</thead>
<tbody>
<tr rt-repeat="energy_datum in this.context.house.energy_data" key="{energy_datum.scoped_id}">
<tr rt-repeat="energy_datum in this.house.energy_data" key="{energy_datum.scoped_id}">
<td></td>
<td>{energy_datum.day_to_s}</td>
<td>{energy_datum.consumption_to_s}</td>

View File

@@ -10,23 +10,26 @@ class HouseComponent extends React.Component {
constructor(props){
super(props);
this.renders = 0;
this.updates = 0;
}
get house(){
return this.props.location.state && this.props.location.state.house;
}
setParam(event){
var house_component = this,
house = house_component.context.house,
param = event.target.dataset.param,
value = event.target.dataset.value,
update = {}, route_helper;
update[param] = value;
route_helper = new RouteHelper(house, house_component.props, update);
if (route_helper.routeUpdated()){
route_helper.updateHouseState();
if (house_component.renders < 10){
house_component.context.router.push(route_helper.newRoute());
house_component.renders += 1;
}
}
route_helper = new RouteHelper(house_component.props, update);
if (route_helper.routeUpdated()) route_helper.updateRoute();
}
componentDidUpdate(){
this.updates += 1;
console.log(this.updates, ') HouseComponent#componentDidUpdate');
}
graphSelected(){
@@ -57,7 +60,6 @@ class HouseComponent extends React.Component {
};
HouseComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
router: React.PropTypes.object.isRequired
};

View File

@@ -31,16 +31,16 @@
type="button" class="btn btn-primary">Table</button>
</div>
<div rt-if="this.context.house">
<div rt-if="this.house">
<h4>Select dates:</h4>
<div class="btn-group">
<button
rt-repeat="year in this.context.house.years"
rt-repeat="year in this.house.years"
data-param="year"
data-value="{year}"
key="data-year-{year}"
class="btn-info btn btn-sm"
rt-class="{active: year == this.context.house.state.year}"
rt-class="{active: year == this.house.state.year}"
onClick="{this.setParam.bind(this)}">{year}</button>
</div>
</div><br/>

View File

@@ -12,8 +12,13 @@ class LayoutComponent extends React.Component {
this.state = {
houses: null,
house: null,
requesting_data: true
loading_house_data: true
};
this.updates = 0
}
get house(){
return this.props.location.state && this.props.location.state.house;
}
componentDidMount() {
@@ -22,30 +27,34 @@ class LayoutComponent extends React.Component {
var house = null;
if (layout.props.params.house_id != undefined){
house = houses.find((h)=>{ return h.data.id == layout.props.params.house_id; });
var route_helper = new RouteHelper(house, layout.props);
if (route_helper.paramsHaveDateState()) route_helper.updateHouseToParams();
}
layout.setState({
houses: houses,
requesting_data: false,
house: house });
loading_house_data: false
}, ()=>{
if (house){
var route_helper = new RouteHelper(layout.context.router, layout.props, {house: house});
route_helper.updateRoute();
}
});
});
}
componentDidUpdate(){
var layout = this;
this.updates += 1;
console.log(this.updates, ') LayoutComponent#componentDidUpdate');
}
setHouse(event){
var layout = this,
house_id = event.target.value,
old_house = layout.state.house,
house = layout.state.houses.find((house)=>{ return house.data.id == house_id });
if (!old_house || old_house.id != house_id){
var route_helper = new RouteHelper(house, layout.props);
route_helper.updateHouseToParams();
layout.setState({house: house}, ()=>{
if (layout.renders < 10){
layout.context.router.push(route_helper.newRoute());
layout.renders += 1
}
if (old_house) old_house.closeDb();
house_id = event.target.value;
if (!layout.house || layout.house.id != house_id){
House.ensureHouses().then((houses)=>{
var new_house = houses.find((h)=>{ return h.data.id == house_id }),
route_helper = new RouteHelper(layout.context.router, layout.props, {house: new_house});
route_helper.updateRoute();
});
}
}
@@ -63,11 +72,6 @@ class LayoutComponent extends React.Component {
});
}
getChildContext(){
var layout = this;
return {house: layout.state.house};
}
render() {
var layoutRt = Templates.forComponent('layout');
return layoutRt.call(this);
@@ -78,7 +82,4 @@ LayoutComponent.contextTypes = {
router: React.PropTypes.object.isRequired
};
LayoutComponent.childContextTypes = {
house: React.PropTypes.instanceOf(House)
};
export default LayoutComponent;

View File

@@ -1,11 +1,11 @@
<div id="layout">
<div class="alert alert-warning" rt-if="this.state.requesting_data">Retrieving houses...</div>
<div class="alert alert-warning" rt-if="this.state.loading_house_data">Retrieving houses...</div>
<h4>Select household:</h4>
<select id="houses_select" rt-if="this.state.houses" class="form-control" onChange="{this.setHouse.bind(this)}" value="{this.props.params.house_id}">
<option rt-repeat="house in this.state.houses" value="{house.data.id}" key="{house.scoped_id}">{house.data.name}</option>
</select>
<button rt-if="this.state.house" onClick="{this.refreshData.bind(this)}" class="btn btn-xs btn-default">Refresh House Data</button>
<button rt-if="this.house" onClick="{this.refreshData.bind(this)}" class="btn btn-xs btn-default">Refresh House Data</button>
{this.props.children}
</div>

View File

@@ -7,23 +7,28 @@ import SplineStackChart from './../../../d3/line/spline_stack';
class GraphComponent extends React.Component {
componentDidMount(){
var power_graph = this,
house = power_graph.context.house;
var power_graph = this;
power_graph.graph_title = ' ';
if (!power_graph.context.loading_power_data) power_graph.updateGraph();
if (power_graph.house) power_graph.updateGraph();
}
get house(){
return this.props.location.state && this.props.location.state.house;
}
componentDidUpdate(prev_props, prev_state, prev_context){
var power_graph = this,
house = power_graph.context.house;
if (power_graph.context.loading_power_data) {return false;}
if (!prev_context.house ||
prev_context.loading_power_data ||
prev_context.house.id != power_graph.context.house.id) {
var power_graph = this;
if (power_graph.shouldUpdateGraph(prev_props)) {
power_graph.updateGraph();
}
}
shouldUpdateGraph(prev_props){
var power_graph = this;
return (power_graph.house && !prev_props.location.state.house ||
prev_props.location.state.house.id != power_graph.props.location.state.house.id);
}
updateGraph(){
var power_graph = this,
house = power_graph.context.house;
@@ -83,8 +88,6 @@ class GraphComponent extends React.Component {
}
GraphComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
loading_power_data: React.PropTypes.bool.isRequired,
router: React.PropTypes.object.isRequired
};

View File

@@ -12,36 +12,43 @@ class PowerComponent extends React.Component {
constructor(props){
super(props);
var power = this;
power.state = {
loading_power_data: true };
power.updates = 0;
}
get house(){
console.log('PowerComponent#get house', this.props.location.state && this.props.location.state.house)
return this.props.location.state && this.props.location.state.house;
}
componentDidMount(){
var power = this,
house = power.context.house;
house = power.props.location.state.house;
console.log(this.updates, ') PowerComponent#componentDidMount')
console.log(this.house)
power.renders = 0;
if (!house) return false;
power.initDateRange();
house.setPowerData()
.then(()=>{
power.setState({loading_power_data: false }); });
}
componentDidUpdate(prev_props, prev_state, prev_context){
this.updates += 1
console.log(this.updates, ') PowerComponent#componentDidUpdate')
console.log(this.house)
var power = this,
house = power.context.house;
if (!house) return false;
var route_helper = new RouteHelper(house, power.props);
if ((!prev_context.house || prev_context.house.data.id != power.context.house.data.id) ||
!house.matchesPowerRange(prev_props.location.query['dates[]'] || [])) {
power.setState({loading_power_data: true});
house.setPowerData()
.then(()=>{
power.initDateRange();
power.setState({loading_power_data: false}); // will update graph or table.
});
} else if (!house.matchesMonthState(prev_props.params)) power.initDateRange();
route_helper = new RouteHelper(power.props);
if (!route_helper.house) return false;
if (power.shouldInitDateRange(prev_props)) {
power.initDateRange();
}
}
shouldInitDateRange(prev_props){
var power = this,
route_helper = new RouteHelper(power.props);
return !prev_props.location.state.house ||
prev_props.location.state.house.data.id != power.context.house.data.id ||
!route_helper.house.matchesPowerRange(prev_props.params, prev_props.location.query['dates[]'] || []);
}
initDateRange(){
@@ -69,8 +76,7 @@ class PowerComponent extends React.Component {
var power_range = [Math.round(min.getTime() / 1000), Math.round(max.getTime() / 1000)],
route_helper = new RouteHelper(house, power.props, {power_range: power_range});
route_helper.updateHouseState();
power.context.router.push(route_helper.newRoute());
route_helper.updateRoute();
}, 500);
};
power.date_range_slider.drawData({
@@ -95,25 +101,13 @@ class PowerComponent extends React.Component {
}
}
getChildContext(){
var layout = this;
return {
loading_power_data: layout.state.loading_power_data
};
}
render() {
var powerRt = Templates.forComponent('power');
return powerRt.call(this);
}
}
PowerComponent.childContextTypes = {
loading_power_data: React.PropTypes.bool.isRequired
};
PowerComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
router: React.PropTypes.object.isRequired
};

View File

@@ -1,16 +1,16 @@
<div id="power_view">
<div class="btn-group">
<button
rt-if="this.context.house"
rt-repeat="month in this.context.house.availableMonths()"
rt-if="this.house"
rt-repeat="month in this.house.availableMonths()"
data-param="month"
data-value="{month}"
key="data-month-{month}"
class="btn-warning btn btn-sm"
rt-class="{active: month === this.context.house.state.month}"
rt-class="{active: month === this.house.state.month}"
onClick="{this.setParam.bind(this)}">{month}</button>
</div>
<div class="alert alert-warning" rt-if="this.state.loading_power_data">
<div class="alert alert-warning" rt-if="this.props.location.state.loading_power_data">
Retrieving power data...
</div>
<div id="power_date_setter"></div>

View File

@@ -12,7 +12,6 @@ class TableComponent extends React.Component {
}
TableComponent.contextTypes = {
house: React.PropTypes.instanceOf(House),
router: React.PropTypes.object.isRequired
};

View File

@@ -42,13 +42,19 @@ export const ROUTES = [{
export class RouteHelper {
constructor(house, props, update){
constructor(router, props, update){
update = update || {};
var route_helper = this;
route_helper.house = house;
route_helper.props = props;
route_helper.router = router;
route_helper.update = update || {};
}
get house(){
var route_helper = this;
return route_helper.update.house || route_helper.props.location.state && route_helper.props.location.state.house;
}
get view(){
var route_helper = this;
return route_helper.update.view || (route_helper.tableSelected() ? 'table' : 'graph');
@@ -65,8 +71,13 @@ export class RouteHelper {
}
get power_range(){
var route_helper = this;
return route_helper.update.power_range || route_helper.props.location.query['dates[]'];
var route_helper = this,
range = route_helper.update.power_range || route_helper.props.location.query.dates;
if (range) {
range[0] = +range[0];
range[1] = +range[1];
}
return range;
}
get date_params(){
@@ -76,11 +87,22 @@ export class RouteHelper {
year: route_helper.update.year || route_helper.house.year };
}
get new_state(){
var route_helper = this;
return Object.keys(route_helper.update).reduce((state, key)=>{
if (['house'].indexOf(key) >= 0) state[key] = route_helper.update[key];
return state;
}, {});
}
// compare house state to updates or params.
routeUpdated(){
var route_helper = this,
house = route_helper.house;
return (route_helper.energySelected() && !house.matchesYearState(route_helper.date_params)) ||
(route_helper.powerSelected() && !house.matchesMonthState(route_helper.date_params) || !house.matchesPowerRange(route_helper.power_range));
(route_helper.powerSelected() && !house.matchesMonthState(route_helper.date_params) || !house.matchesPowerRange(route_helper.power_range)) &&
(!route_helper.update.view || route_helper.update.view !== route_helper.view);
}
// This will update the house state acccording to passed update parameters.
@@ -88,24 +110,25 @@ export class RouteHelper {
var route_helper = this,
house = route_helper.house;
house.setMonthState(route_helper.date_params, route_helper.update.power_range);
if (route_helper.energySelected()){
route_helper.router.push({state: {loading_energy_data: true}})
return house.setEnergyData().then(()=>{ return {loading_energy_data: false} });
} else if (route_helper.powerSelected()) {
route_helper.router.push({state: {loading_power_data: true}})
return house.setPowerData().then(()=>{ return {loading_power_data: false} });
} else return Promise.resolve({});
}
paramsHaveDateState(){
updateRoute(){
var route_helper = this;
return !!route_helper.props.params.year;
}
// This will update the house according to URL parameters.
updateHouseToParams(){
var route_helper = this,
house = route_helper.house,
power_range;
if (route_helper.props.location.query['dates[]']){
power_range = [];
power_range[0] = +route_helper.props.location.query['dates[]'][0];
power_range[1] = +route_helper.props.location.query['dates[]'][1];
}
house.setMonthState(route_helper.props.params, power_range);
return route_helper.updateHouseState()
.then((data_state)=>{
route_helper.router.push({
pathname: route_helper.newRoute(),
query: route_helper.newQuery(),
state: Object.assign(data_state, route_helper.new_state)
});
});
}
// should be run AFTER updateHouseState is called.
@@ -115,10 +138,16 @@ export class RouteHelper {
if (route_helper.dataset === 'energy'){
return `/houses/${house.data.id}/energy/${house.state.year}/${route_helper.graph_attr}/${route_helper.view}`;
} else {
return `/houses/${house.data.id}/power/${house.state.month}/${house.state.year}/${route_helper.view}?${jQuery.param({dates: house.state.power_range})}`;
return `/houses/${house.data.id}/power/${house.state.month}/${house.state.year}/${route_helper.view}`;
}
}
newQuery(){
var route_helper = this;
if (route_helper.dataset === 'power') return {dates: route_helper.house.state.power_range};
else return {};
}
graphSelected(){
return RouteHelper.graphSelected(this.props.routes);
}

View File

@@ -133,9 +133,9 @@ class House {
return params.month == house.state.month && params.year == house.state.year;
}
matchesPowerRange(dates){
matchesPowerRange(params, dates){
var house = this;
return house.state.power_range[0] == dates[0] && house.state.power_range[1] == dates[1];
return house.matchesMonthState(params) && house.state.power_range[0] == dates[0] && house.state.power_range[1] == dates[1];
}
offset_diff(unix){

View File

@@ -62,20 +62,9 @@ import logger from 'morgan';
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
// serve fonts in /assets/fonts
import assets from "connect-assets";
// TODO: These routes need to match references in the bootstrap and font awesome files.
app.use("/assets/fonts", express.static("bootstrap/dist/fonts"));
app.use("/assets/fonts", express.static("font-awesome/fonts"));
// serve compiled vendor assets and application.css.
app.use(assets({
paths: ["./../node_modules"],
build: true,
buildDir: false,
// compile: false,
compress: true
}));
// serve public static files.
dev_server.app.use('/', express.static(path.resolve(__dirname, 'public')));