mirror of https://github.com/fspc/workstand.git
Drew Larson
8 years ago
5 changed files with 311 additions and 5 deletions
@ -0,0 +1,110 @@ |
|||||
|
import React from 'react'; |
||||
|
import Dialog from 'material-ui/Dialog'; |
||||
|
import FlatButton from 'material-ui/FlatButton'; |
||||
|
import TextField from 'material-ui/TextField'; |
||||
|
import DatePicker from 'material-ui/DatePicker'; |
||||
|
import RaisedButton from 'material-ui/RaisedButton'; |
||||
|
import moment from 'moment-timezone'; |
||||
|
import Size from '../Size'; |
||||
|
import Source from '../Source'; |
||||
|
import Checkbox from 'material-ui/Checkbox'; |
||||
|
|
||||
|
/** |
||||
|
* A modal dialog can only be closed by selecting one of the actions. |
||||
|
*/ |
||||
|
export default class BikeModal extends React.Component { |
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
|
||||
|
this.state = { |
||||
|
open: props.open, |
||||
|
bike: undefined, |
||||
|
}; |
||||
|
} |
||||
|
componentWillReceiveProps(newProps) { |
||||
|
this.setState({ open: newProps.open || false, bike: newProps.bike || false }); |
||||
|
} |
||||
|
handleClose = () => { |
||||
|
this.setState({ open: false }); |
||||
|
}; |
||||
|
|
||||
|
render() { |
||||
|
const styles = { |
||||
|
block: { |
||||
|
maxWidth: 250, |
||||
|
}, |
||||
|
checkbox: { |
||||
|
marginBottom: 16, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const actions = [ |
||||
|
<FlatButton |
||||
|
label="Cancel" |
||||
|
primary |
||||
|
onTouchTap={this.handleClose} |
||||
|
/>, |
||||
|
<FlatButton |
||||
|
label="Submit" |
||||
|
primary |
||||
|
disabled |
||||
|
onTouchTap={this.handleClose} |
||||
|
/>, |
||||
|
]; |
||||
|
|
||||
|
let form; |
||||
|
|
||||
|
|
||||
|
if (this.state.bike !== undefined) { |
||||
|
const timezone = moment.tz.guess(); |
||||
|
const { |
||||
|
make, |
||||
|
price, |
||||
|
claimed_at, |
||||
|
claimed_by, |
||||
|
colour, |
||||
|
cpic_searched_at, |
||||
|
created_at, |
||||
|
size, |
||||
|
serial_number, |
||||
|
source, |
||||
|
stripped } = this.state.bike; |
||||
|
const createdAtFormatted = moment(created_at).tz(timezone).fromNow(); |
||||
|
|
||||
|
form = ( |
||||
|
<div> |
||||
|
<TextField label={'Blah'} value={make} /><TextField label="Price" value={price} /><br /> |
||||
|
<TextField label="Claimed on" value={claimed_at} /><TextField label="Claimed by" value={claimed_by} /><br /> |
||||
|
<TextField label="Colour" value={colour} /><br /> |
||||
|
<TextField label="CPIC Searched on" value={cpic_searched_at} /><br /> |
||||
|
<TextField label="Created at" value={createdAtFormatted} readOnly disabled /><br /> |
||||
|
<Size size={size} /> |
||||
|
<TextField label="Serial number" value={serial_number} /> |
||||
|
<Source source={source} /> |
||||
|
<div style={styles.block}> |
||||
|
<Checkbox |
||||
|
label="Stripped" |
||||
|
labelPosition="left" |
||||
|
style={styles.checkbox} |
||||
|
value={stripped} |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
<Dialog |
||||
|
title="Edit Bike" |
||||
|
actions={actions} |
||||
|
modal={true} |
||||
|
open={this.state.open} |
||||
|
> |
||||
|
{(form) ? form : <div>Unable to edit bike.</div>} |
||||
|
|
||||
|
</Dialog> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,104 @@ |
|||||
|
import React from 'react'; |
||||
|
import { polyFill } from 'es6-promise'; |
||||
|
import moment from 'moment-timezone'; |
||||
|
import fetch from 'isomorphic-fetch'; |
||||
|
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; |
||||
|
import FlatButton from 'material-ui/FlatButton'; |
||||
|
import { friendlySize } from '../Size'; |
||||
|
import BikeModal from '../BikeModal'; |
||||
|
|
||||
|
function checkStatus(response) { |
||||
|
if (response.status >= 200 && response.status < 300) { |
||||
|
return response; |
||||
|
} |
||||
|
const error = new Error(response.statusText); |
||||
|
error.response = response; |
||||
|
throw error; |
||||
|
} |
||||
|
|
||||
|
function parseJSON(response) { |
||||
|
return response.json(); |
||||
|
} |
||||
|
|
||||
|
export default class BikeTable extends React.Component { |
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
|
||||
|
this.state = { |
||||
|
bikes: [], |
||||
|
bikeModal: { |
||||
|
open: false, |
||||
|
bike: undefined, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
this.handleEditBike = this.handleEditBike.bind(this); |
||||
|
} |
||||
|
|
||||
|
componentDidMount() { |
||||
|
fetch('/api/v1/bikes/') |
||||
|
.then(checkStatus) |
||||
|
.then(parseJSON) |
||||
|
.then((data) => { |
||||
|
this.setState({ bikes: data }); |
||||
|
console.log('request succeeded with JSON response', data); |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.log('request failed', error); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
handleEditBike(bike) { |
||||
|
console.log('Bike edit!'); |
||||
|
this.setState({ |
||||
|
bikeModal: { |
||||
|
open: true, |
||||
|
bike, |
||||
|
}, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const bikeRows = this.state.bikes.map(bike => ( |
||||
|
<TableRow selectable={false} key={bike.id}> |
||||
|
<TableRowColumn>{friendlySize(bike.size)}</TableRowColumn> |
||||
|
<TableRowColumn>{bike.colour}</TableRowColumn> |
||||
|
<TableRowColumn>{bike.make}</TableRowColumn> |
||||
|
<TableRowColumn>{bike.serial_number}</TableRowColumn> |
||||
|
<TableRowColumn>{bike.state}</TableRowColumn> |
||||
|
<TableRowColumn>{bike.claimed_by}</TableRowColumn> |
||||
|
<TableRowColumn><FlatButton label="Edit" primary onTouchTap={this.handleEditBike.bind(null, bike)} /></TableRowColumn> |
||||
|
</TableRow> |
||||
|
)); |
||||
|
|
||||
|
return ( |
||||
|
<div className="mdl-grid"> |
||||
|
<div className="mdl-cell mdl-cell--12-col"> |
||||
|
<h3>Bikes</h3> |
||||
|
<Table selectable={false}> |
||||
|
<TableHeader adjustForCheckbox={false} displaySelectAll={false}> |
||||
|
<TableRow> |
||||
|
<TableHeaderColumn>Size</TableHeaderColumn> |
||||
|
<TableHeaderColumn>Colour</TableHeaderColumn> |
||||
|
<TableHeaderColumn>Make</TableHeaderColumn> |
||||
|
<TableHeaderColumn>Serial number</TableHeaderColumn> |
||||
|
<TableHeaderColumn>State</TableHeaderColumn> |
||||
|
<TableHeaderColumn>Claimed by</TableHeaderColumn> |
||||
|
<TableRowColumn /> |
||||
|
</TableRow> |
||||
|
</TableHeader> |
||||
|
<TableBody displayRowCheckbox={false}> |
||||
|
{bikeRows.length ? |
||||
|
bikeRows : |
||||
|
<TableRow> |
||||
|
<TableRowColumn>{'No members currently signed in.'}</TableRowColumn> |
||||
|
</TableRow> |
||||
|
} |
||||
|
</TableBody> |
||||
|
</Table> |
||||
|
<BikeModal bike={this.state.bikeModal.bike} open={this.state.bikeModal.open} /> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
import React, { PropTypes } from 'react'; |
||||
|
import SelectField from 'material-ui/SelectField'; |
||||
|
import MenuItem from 'material-ui/MenuItem'; |
||||
|
|
||||
|
const sizes = ['C', 'S', 'M', 'L', 'XL']; |
||||
|
|
||||
|
export const friendlySize = (size) => { |
||||
|
switch (size) { |
||||
|
case 'C': |
||||
|
return 'child'; |
||||
|
case 'S': |
||||
|
return 'small'; |
||||
|
case 'M': |
||||
|
return 'medium'; |
||||
|
case 'L': |
||||
|
return 'large'; |
||||
|
case 'XL': |
||||
|
return 'extra large'; |
||||
|
default: |
||||
|
return 'unknown'; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const Size = ({ size }) => { |
||||
|
const items = sizes.map(s => |
||||
|
<MenuItem value={s} primaryText={friendlySize(s)} />, |
||||
|
); |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
<SelectField |
||||
|
floatingLabelText="Size" |
||||
|
value={size} |
||||
|
onChange={undefined} |
||||
|
> |
||||
|
<MenuItem value={null} primaryText="" /> |
||||
|
{items} |
||||
|
</SelectField> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
Size.propTypes = { |
||||
|
size: PropTypes.string, |
||||
|
}; |
||||
|
|
||||
|
export default Size; |
@ -0,0 +1,44 @@ |
|||||
|
import React, { PropTypes } from 'react'; |
||||
|
import SelectField from 'material-ui/SelectField'; |
||||
|
import MenuItem from 'material-ui/MenuItem'; |
||||
|
|
||||
|
const sources = ['COS_BIKE_DIVERSION_PILOT', 'UOFS', 'DROP_OFF']; |
||||
|
|
||||
|
export const friendly = (s) => { |
||||
|
switch (s) { |
||||
|
case 'COS_BIKE_DIVERSION_PILOT': |
||||
|
return 'City of Saskatoon Bike Diversion Pilot'; |
||||
|
case 'UOFS': |
||||
|
return 'University of Saskatchewan'; |
||||
|
case 'DROP_OFF': |
||||
|
return 'Drop Off'; |
||||
|
default: |
||||
|
return undefined; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
const Source = ({ source }) => { |
||||
|
const items = sources.map(s => |
||||
|
<MenuItem value={s} primaryText={friendly(s)} />, |
||||
|
); |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
<SelectField |
||||
|
floatingLabelText="Source" |
||||
|
value={source} |
||||
|
onChange={undefined} |
||||
|
autoWidth={true} |
||||
|
> |
||||
|
<MenuItem value={null} primaryText="" /> |
||||
|
{items} |
||||
|
</SelectField> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
Source.propTypes = { |
||||
|
source: PropTypes.string, |
||||
|
}; |
||||
|
|
||||
|
export default Source; |
Loading…
Reference in new issue