Browse Source

More reduxy

feature/bike-tracking
Drew Larson 8 years ago
parent
commit
1e5abbbf2c
  1. 2
      bikeshop_project/assets/js/bikes/actions.js
  2. 67
      bikeshop_project/assets/js/bikes/components/BikeForm/index.jsx
  3. 39
      bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx
  4. 13
      bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx
  5. 18
      bikeshop_project/assets/js/bikes/reducers.js

2
bikeshop_project/assets/js/bikes/actions.js

@ -8,3 +8,5 @@ export const setBikesFetchFailed = createAction('set bikes.fetchFailed');
export const setBikeSaved = createAction('set bike.saved'); export const setBikeSaved = createAction('set bike.saved');
export const setBikeIsSaving = createAction('set bike.isSaving'); export const setBikeIsSaving = createAction('set bike.isSaving');
export const setBikeSaveFailed = createAction('set bike.isSaving'); export const setBikeSaveFailed = createAction('set bike.isSaving');
export const editBike = createAction('edit bike');
export const createBike = createAction('create bike');

67
bikeshop_project/assets/js/bikes/components/BikeForm/index.jsx

@ -1,5 +1,5 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { Field, reduxForm } from 'redux-form'; import { Field, formValueSelector, reduxForm } from 'redux-form';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Checkbox from 'material-ui/Checkbox'; import Checkbox from 'material-ui/Checkbox';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
@ -87,9 +87,9 @@ const validate = (values) => {
const handleSubmit = data => false; const handleSubmit = data => false;
class BikeForm extends React.Component { class BikeForm extends React.Component {
constructor({ bike, editing = false }) { constructor({ bike, create }) {
super(); super();
if (editing) { if (!create) {
this.state = { this.state = {
bike, bike,
}; };
@ -139,11 +139,11 @@ class BikeForm extends React.Component {
const id = this.state.bike.id; const id = this.state.bike.id;
const data = JSON.stringify(this.state.bike); const data = JSON.stringify(this.state.bike);
const csrfToken = Cookies.get('csrftoken'); const csrfToken = Cookies.get('csrftoken');
const url = this.props.editing ? `/api/v1/bikes/${id}/` : '/api/v1/bikes/'; const url = this.props.create ? `/api/v1/bikes/${id}/` : '/api/v1/bikes/';
fetch(url, { fetch(url, {
credentials: 'same-origin', credentials: 'same-origin',
method: this.props.editing ? 'PUT' : 'POST', method: this.props.create ? 'PUT' : 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-CSRFToken': csrfToken, 'X-CSRFToken': csrfToken,
@ -160,20 +160,20 @@ class BikeForm extends React.Component {
} }
render() { render() {
const timezone = moment.tz.guess(); // const timezone = moment.tz.guess();
const { // const {
claimed_at, // claimed_at,
claimed_by, // claimed_by,
cpic_searched_at, // cpic_searched_at,
created_at, // created_at,
stolen, // stolen,
checked, // checked,
} = this.props.bike; // } = this.props.bike || {};
const editing = this.props.editing; const create = this.props.create;
const createdAtFormatted = (moment(created_at).isValid()) ? moment(created_at).tz(timezone).fromNow() : ''; // const createdAtFormatted = (moment(created_at).isValid()) ? moment(created_at).tz(timezone).fromNow() : '';
const claimedAtFormatted = (moment(claimed_at).isValid()) ? moment(claimed_at).tz(timezone).fromNow() : ''; // const claimedAtFormatted = (moment(claimed_at).isValid()) ? moment(claimed_at).tz(timezone).fromNow() : '';
const cpicSearchedAtFormatted = (moment(cpic_searched_at).isValid()) ? moment(cpic_searched_at).tz(timezone) // const cpicSearchedAtFormatted = (moment(cpic_searched_at).isValid()) ? moment(cpic_searched_at).tz(timezone)
.fromNow() : ''; // .fromNow() : '';
return ( return (
<div> <div>
@ -220,13 +220,12 @@ class BikeForm extends React.Component {
fullWidth fullWidth
/> />
</div> </div>
{editing && {!create &&
<div className="mdl-cell mdl-cell--6-col"> <div className="mdl-cell mdl-cell--6-col">
<Field <Field
name="created_at" name="created_at"
component={renderTextField} component={renderTextField}
floatingLabelText="Created at" floatingLabelText="Created at"
value={createdAtFormatted}
fullWidth fullWidth
readOnly readOnly
disabled disabled
@ -234,14 +233,13 @@ class BikeForm extends React.Component {
</div> </div>
} }
</div> </div>
{editing && {!create &&
<div className="mdl-grid"> <div className="mdl-grid">
<div className="mdl-cell mdl-cell--6-col"> <div className="mdl-cell mdl-cell--6-col">
<Field <Field
name="claimed_at" name="claimed_at"
component={renderTextField} component={renderTextField}
floatingLabelText="Claimed on" floatingLabelText="Claimed on"
value={claimedAtFormatted}
fullWidth fullWidth
disabled disabled
/> />
@ -259,10 +257,15 @@ class BikeForm extends React.Component {
</div> </div>
} }
{editing && {!create &&
<div className="content-grid mdl-grid" style={styles.bottom}> <div className="content-grid mdl-grid" style={styles.bottom}>
<div className="mdl-cell mdl-cell--6-col"> <div className="mdl-cell mdl-cell--6-col">
<TextField floatingLabelText="CPIC searched" value={cpicSearchedAtFormatted} disabled /> <Field
name="cpic_searched_at"
component={renderTextField}
floatingLabelText="CPIC searched"
disabled
/>
</div> </div>
<div className="mdl-cell mdl-cell--4-col"> <div className="mdl-cell mdl-cell--4-col">
<Field <Field
@ -271,13 +274,12 @@ class BikeForm extends React.Component {
label="Stolen" label="Stolen"
labelPosition="left" labelPosition="left"
style={styles.checkbox} style={styles.checkbox}
checked={stolen}
disabled disabled
readOnly readOnly
/> />
</div> </div>
<div className="mdl-cell mdl-cell--2-col"> <div className="mdl-cell mdl-cell--2-col">
<FlatButton label="Check" onTouchTap={this.handleCpicCheck} disabled={moment(cpic_searched_at).isValid()} primary /> <FlatButton label="Check" onTouchTap={this.handleCpicCheck} disabled={this.props.cpic_searched} primary />
</div> </div>
</div> </div>
} }
@ -292,11 +294,10 @@ class BikeForm extends React.Component {
{sourceMenuItems} {sourceMenuItems}
</Field> </Field>
</div> </div>
{editing && {!create &&
<div className="mdl-cell mdl-cell--4-col"> <div className="mdl-cell mdl-cell--4-col">
<div style={styles.block}> <div style={styles.block}>
<Field <Field
checked={checked}
name="stripped" name="stripped"
label="Stripped" label="Stripped"
labelPosition="left" labelPosition="left"
@ -324,14 +325,18 @@ BikeForm = reduxForm({
validate, validate,
})(BikeForm); })(BikeForm);
const selector = formValueSelector('BikeForm')
BikeForm = connect( BikeForm = connect(
state => ({ state => ({
initialValues: state.bikes.entities['1'], // pull initial values from account reducer initialValues: state.bikes.form.bike, // pull initial values from account reducer
create: state.bikes.form.create,
cpic_searched: selector(state.bikes.form.bike, 'cpic_searched_at'),
}), }),
)(BikeForm); )(BikeForm);
BikeForm.propTypes = { BikeForm.propTypes = {
editing: PropTypes.bool, create: PropTypes.bool,
handleClose: PropTypes.func, handleClose: PropTypes.func,
} }

39
bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx

@ -12,38 +12,23 @@ class BikeModal extends React.Component {
} }
render() { render() {
if (this.props.bike) { return (
const title = ( <Dialog
<div> title='Bike'
<h3>{this.props.bike ? 'Edit Bike' : 'Add Bike'}</h3> open={this.props.open}
</div> autoScrollBodyContent
); >
<BikeForm
return (<div> enableReinitialize
<Dialog />
title={title} }
open={this.props.open} </Dialog>
autoScrollBodyContent )
>
{ this.props.bike ?
<BikeForm
enableReinitialize
bike={this.props.bike}
bikes={this.props.bikes}
/> :
<div>Unable to edit bike.</div>
}
</Dialog>
</div>);
}
return null;
} }
} }
BikeModal.propTypes = { BikeModal.propTypes = {
open: PropTypes.bool, open: PropTypes.bool,
bike: PropTypes.object,
}; };
export default BikeModal; export default BikeModal;

13
bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx

@ -6,7 +6,7 @@ import ContentAdd from 'material-ui/svg-icons/content/add';
import React from 'react'; import React from 'react';
import { friendlySize } from '../Size'; import { friendlySize } from '../Size';
import BikeModal from '../BikeModal'; import BikeModal from '../BikeModal';
import { fetchBikes, setBike } from '../../actions'; import { fetchBikes, setBike, editBike } from '../../actions';
class BikeTableComponent extends React.Component { class BikeTableComponent extends React.Component {
constructor(props) { constructor(props) {
@ -27,15 +27,15 @@ class BikeTableComponent extends React.Component {
this.props.fetchBikes(); this.props.fetchBikes();
} }
handleOpen(id) { handleOpen(bike) {
this.setState({ this.setState({
...this.state, ...this.state,
bikeModal: { bikeModal: {
...this.state.bikeModal, ...this.state.bikeModal,
open: true, open: true,
bike: id,
}, },
}); });
this.props.editBike(bike);
} }
renderBikes(bikes) { renderBikes(bikes) {
@ -47,7 +47,7 @@ class BikeTableComponent extends React.Component {
<TableRowColumn>{bike.serial_number}</TableRowColumn> <TableRowColumn>{bike.serial_number}</TableRowColumn>
<TableRowColumn>{bike.state}</TableRowColumn> <TableRowColumn>{bike.state}</TableRowColumn>
<TableRowColumn>{bike.claimed_by}</TableRowColumn> <TableRowColumn>{bike.claimed_by}</TableRowColumn>
<TableRowColumn><FlatButton label="Edit" primary onTouchTap={(e) => this.handleOpen(bike.id)} /></TableRowColumn> <TableRowColumn><FlatButton label="Edit" primary onTouchTap={(e) => this.handleOpen(bike)} /></TableRowColumn>
</TableRow> </TableRow>
)); ));
@ -88,8 +88,6 @@ class BikeTableComponent extends React.Component {
</div> </div>
<BikeModal <BikeModal
open={this.state.bikeModal.open} open={this.state.bikeModal.open}
bike={this.state.bikeModal.bike}
bikes={this.props.bikes.entities}
/> />
</div> </div>
); );
@ -107,6 +105,9 @@ const mapDispatchToProps = dispatch => ({
fetchBikes: () => { fetchBikes: () => {
dispatch(fetchBikes()); dispatch(fetchBikes());
}, },
editBike: (bike) => {
dispatch(editBike(bike));
}
}); });
const BikeTable = connect(mapStateToProps, mapDispatchToProps)(BikeTableComponent); const BikeTable = connect(mapStateToProps, mapDispatchToProps)(BikeTableComponent);

18
bikeshop_project/assets/js/bikes/reducers.js

@ -1,4 +1,4 @@
import { setBikes, setBikesFetched, setBikesIsFetching, setBikesFetchFailed } from './actions'; import { setBikes, setBikesFetched, setBikesIsFetching, setBikesFetchFailed, createBike, editBike } from './actions';
import { handleActions } from 'redux-actions'; import { handleActions } from 'redux-actions';
export default handleActions({ export default handleActions({
@ -20,4 +20,18 @@ export default handleActions({
message: action.payload, message: action.payload,
}, },
}), }),
}, { entities: {}, isFetching: false, fetched: false, fetchFailed: undefined }); [editBike]: (state, action) => ({
...state,
form: {
bike: action.payload,
create: false,
},
}),
[createBike]: (state, action) => ({
...state,
form: {
bike: null,
create: true,
},
}),
}, { entities: {}, form: { bike: null, create: undefined }, isFetching: false, fetched: false, fetchFailed: undefined });

Loading…
Cancel
Save