[UNSTBLE] Fixed optimistic crop creation bug

pull/226/head
Rick Carlino 2015-10-01 11:25:56 -05:00
parent a1a61ae197
commit c9154e90f3
10 changed files with 65 additions and 51 deletions

View File

@ -7,11 +7,9 @@
component: 'PlantInventory',
tab: 'Plants'
},
middleMenu: {
global: {
plants: <%= raw(current_user.device.plants.to_json) %>,
selectedCrop: {}
},
rightMenu: {
selectedPlant: {}
}
};
</script>

View File

@ -7,7 +7,7 @@ export class CropInfo extends React.Component {
removeCrop() {
this.props.dispatch({type: "CROP_REMOVE_REQUEST",
payload: this.props.crop });
payload: this.props.plant });
}
render() {
@ -18,7 +18,7 @@ export class CropInfo extends React.Component {
<a href="#" onClick={ this.goBack.bind(this) }>
<i className="fa fa-arrow-left"></i>
</a>
Crop { this.props.crop._id || "" }
Crop { this.props.plant._id || "" }
</p>
</div>
</div>
@ -26,7 +26,7 @@ export class CropInfo extends React.Component {
<div className="crop-drag-info-tile">
<h6>Photos of this Crop</h6>
<img className="crop-drag-info-image"
src={this.props.crop.imgUrl || '/designer_icons/placeholder_berries.jpg'} />
src={this.props.plant.imgUrl || '/designer_icons/placeholder_berries.jpg'} />
</div>
</div>
<div>

View File

@ -9,7 +9,7 @@ const LEFT_MENU_CHOICES = {PlantInventory, PlantCatalog, PlantInfo, CropInfo}
export class DesignerMain extends React.Component {
transferableProps(name){
return _.merge({}, {dispatch: this.props.dispatch}, this.props[name]);
return _.merge({}, this.props.global, {dispatch: this.props.dispatch}, this.props[name]);
};
// Dynamically determine what to render on the left side of the designer,
@ -27,8 +27,8 @@ export class DesignerMain extends React.Component {
}
renderMiddle(){
let props = this.transferableProps("middleMenu");
return React.createElement(GardenMap, props);
return React.createElement(GardenMap,
this.transferableProps("middleMenu"));
}
render(){

View File

@ -1,12 +1,12 @@
export class MapPointView extends React.Component {
select() {
this.props.dispatch({type: "CROP_SELECT", payload: this.props.crop});
this.props.dispatch({type: "CROP_SELECT", payload: this.props.plant});
}
render() {
var style = {
position: 'absolute',
left: (this.props.crop.x - 20),
top: (this.props.crop.y - 40)
left: (this.props.plant.x - 20),
top: (this.props.plant.y - 40)
};
if (!!this.props.selected) { style.border = "1px solid green"; };
return <div onClick={ this.select.bind(this) }>
@ -16,11 +16,11 @@ export class MapPointView extends React.Component {
};
export class GardenMap extends React.Component {
crops() {
plants() {
return this.props.plants.map(
(p, k) => <MapPointView crop={ p }
(p, k) => <MapPointView plant={ p }
key={ k }
selected={ p._id && (this.props.selectedCrop._id === p._id) }
selected={ (this.props.selectedPlant._id === p._id) }
dispatch={ this.props.dispatch }/>
);
}
@ -28,7 +28,7 @@ export class GardenMap extends React.Component {
render() {
return <div>
<div id="drop-area">
{ this.crops() }
{ this.plants() }
</div>
</div>;
}

View File

@ -4,7 +4,7 @@ export class PlantCatalogTile extends React.Component {
showPlantInfo(){
this.props.dispatch({
type: 'PLANT_INFO_SHOW',
payload: this.props.crop
payload: this.props.plant
});
};
@ -14,14 +14,14 @@ export class PlantCatalogTile extends React.Component {
<div className="row">
<div className="small-12 columns">
<div className="small-header-wrapper">
<h5>{ this.props.crop.name }</h5>
<h5>{ this.props.plant.name }</h5>
</div>
</div>
</div>
<div className="row">
<div className="small-12 columns">
<div className="content-wrapper">
<p> <img src={this.props.crop.imgUrl} /> </p>
<p> <img src={this.props.plant.imgUrl} /> </p>
</div>
</div>
</div>
@ -34,7 +34,7 @@ export class PlantCatalog extends React.Component {
back() { this.props.dispatch({type: "INVENTORY_SHOW"}) }
render() {
var crops = Plant.fakePlants.map(
(crop, k) => <PlantCatalogTile crop={ crop }
(plant, k) => <PlantCatalogTile plant={ plant }
key={ k }
dispatch={ this.props.dispatch } />
);

View File

@ -18,7 +18,7 @@ export class PlantInfo extends React.Component {
<a href="#" onClick={ this.showCatalog.bind(this) }>
<i className="fa fa-arrow-left"></i>
</a>
{ this.props.crop.name }
{ this.props.plant.name }
</p>
</div>
</div>
@ -26,7 +26,7 @@ export class PlantInfo extends React.Component {
<div className="crop-drag-info-tile">
<h6>Plant Image</h6>
<img className="crop-drag-info-image"
src={this.props.crop.imgUrl}
src={this.props.plant.imgUrl}
onDragEnd={ this.drop.bind(this) }/>
<div className="crop-info-overlay">
To plant, drag and drop into map

View File

@ -109,8 +109,8 @@ export class Item extends React.Component {
render() {
return(
<li>
<a href="#"> {this.props.crop.name} </a>
<div>{this.props.crop.age} days old</div>
<a href="#"> {this.props.plant.name} </a>
<div>{this.props.plant.age} days old</div>
</li>);
}
};
@ -118,7 +118,7 @@ export class Item extends React.Component {
export class List extends React.Component {
render() {
var crops = this.props.plants.map(
(crop, k) => <Item crop={crop} key={ k } />
(plant, k) => <Item plant={plant} key={ k } />
);
return(<ul className="crop-inventory"> { crops } </ul>);

View File

@ -18,7 +18,7 @@ export class SpeciesInfo extends React.Component {
<a href="#" onClick={ this.showCatalog.bind(this) }>
<i className="fa fa-arrow-left"></i>
</a>
{ this.props.crop.name }
{ this.props.plant.name }
</p>
</div>
</div>
@ -26,7 +26,7 @@ export class SpeciesInfo extends React.Component {
<div className="crop-drag-info-tile">
<h6>Species Image</h6>
<img className="crop-drag-info-image"
src={this.props.crop.imgUrl}
src={this.props.plant.imgUrl}
onDragEnd={ this.drop.bind(this) }/>
<div className="crop-info-overlay">
To plant, drag and drop into map

View File

@ -13,18 +13,23 @@ actions.DEFAULT = function (s, a) {
};
actions.CROP_SELECT = function(s, a) {
var select_crop = update(s, {middleMenu: {selectedCrop: a.payload}});
var select_crop = update(s, {global: {selectedPlant: a.payload}});
var change_menu = actions.CROP_INFO_SHOW(select_crop, a);
return change_menu;
return _.merge({}, select_crop, change_menu);
};
actions.CROP_ADD_REQUEST = function (s, a) {
var req = $.ajax({method: "POST", url: "/api/plants", data: a.payload})
.done(function (plant) {
store.dispatch({type: "CROP_ADD_SUCCESS", payload: plant});
})
$.ajax({method: "POST", url: "/api/plants", data: a.payload})
.fail(function (a, b, c) { store.dispatch({type: "CROP_ADD_FAILURE"}) });
return s;
var plants = _.cloneDeep(s.global.plants);
var selectedPlant = _.cloneDeep(a.payload);
plants.push(selectedPlant);
return update(s, {
global: {
plants: plants,
selectedPlant: selectedPlant
}
});
};
actions.CROP_ADD_FAILURE = function (s = store.getState(), a) {
@ -32,18 +37,27 @@ actions.CROP_ADD_FAILURE = function (s = store.getState(), a) {
return s;
};
actions.CROP_ADD_SUCCESS = function (s = store.getState(), a) {
var new_array = s.middleMenu.plants.concat(a.payload);
return update(s, {middleMenu: {plants: new_array}});
actions.CROP_ADD_SUCCESS = function (s, a) {
var plants = _.cloneDeep(s.global.plants);
var selectedPlant = _.cloneDeep(a.payload);
plants.push(selectedPlant);
return update(s, {
global: {
plants: plants,
selectedPlant: selectedPlant
}
});
};
actions.CROP_REMOVE_REQUEST = function (s, a) {
$.ajax({
method: "DELETE",
url: "/api/plants/" + a.payload._id
}).fail(function () {
store.dispatch({type: "CROP_REMOVE_FAILURE"});
}).done(function () {
store.dispatch({type: "CROP_REMOVE_SUCCESS", payload: a.payload});
}).fail(function (a, b, c) { store.dispatch({type: "CROP_REMOVE_FAILURE"}) });
});
return s;
};
@ -53,18 +67,19 @@ actions.CROP_REMOVE_FAILURE = function (s = store.getState(), a) {
};
actions.CROP_REMOVE_SUCCESS = function (s = store.getState(), a) {
let oldArray = s.middleMenu.plants;
var newArray = _.filter(oldArray, (c) => c._id !== a.payload._id);
return update(s, {middleMenu: {plants: newArray}});
return update(s, {
global: {
plants: _.filter(s.global.plants, a.payload)
}
});
};
actions.PLANT_INFO_SHOW = function(s, a) {
// TODO: add type system to check for presence of `crop` Object?
let fragment = {
leftMenu: {
component: 'PlantInfo',
crop: a.payload
plant: a.payload
}
};
return update(s, fragment);
@ -72,13 +87,12 @@ actions.PLANT_INFO_SHOW = function(s, a) {
actions.CROP_INFO_SHOW = function(s, a) {
// TODO: add type system to check for presence of `crop` Object?
let fragment = {
leftMenu: {
component: 'CropInfo',
crop: a.payload
}
};
return update(s, fragment);
return update(s, {
leftMenu: {
component: 'CropInfo',
plant: a.payload
}
});
};
actions.CATALOG_SHOW = function(s, a){

View File

@ -3,6 +3,8 @@ import { isFSA } from 'flux-standard-action';
export function reducer(state, action) {
if (isFSA(action)){
console.log(action.type);
console.dir(state);
return (actions[action.type] || actions.DEFAULT)(state, action);
} else {
console.error("Action does not conform to 'flux-standard-action", action);