mirror of
https://github.com/fspc/workstand.git
synced 2025-02-23 09:13:23 -05:00
Partial Bike table and edit modal.
This commit is contained in:
parent
7bb1f80435
commit
ea0b2b1052
110
bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx
Normal file
110
bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx
Normal file
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
104
bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx
Normal file
104
bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx
Normal file
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
bikeshop_project/assets/js/bikes/components/Size/index.jsx
Normal file
47
bikeshop_project/assets/js/bikes/components/Size/index.jsx
Normal file
@ -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;
|
44
bikeshop_project/assets/js/bikes/components/Source/index.jsx
Normal file
44
bikeshop_project/assets/js/bikes/components/Source/index.jsx
Normal file
@ -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;
|
@ -1,6 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import injectTapEventPlugin from 'react-tap-event-plugin';
|
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
|
import getMuiTheme from 'material-ui/styles/getMuiTheme';
|
||||||
|
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
||||||
|
import BikeTable from './components/BikeTable';
|
||||||
|
|
||||||
// Needed for onTouchTap
|
// Needed for onTouchTap
|
||||||
// http://stackoverflow.com/a/34015469/988941
|
// http://stackoverflow.com/a/34015469/988941
|
||||||
@ -10,11 +13,9 @@ injectTapEventPlugin();
|
|||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="mdl-grid">
|
<MuiThemeProvider muiTheme={getMuiTheme()}>
|
||||||
<div className="mdl-cell mdl-cell--12-col">
|
<BikeTable/>
|
||||||
<h1>Bikes</h1>
|
</MuiThemeProvider>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user