diff --git a/bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx b/bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx
new file mode 100644
index 0000000..b5a5f5a
--- /dev/null
+++ b/bikeshop_project/assets/js/bikes/components/BikeModal/index.jsx
@@ -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 = [
+ ,
+ ,
+ ];
+
+ 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 = (
+
+ );
+ }
+
+ return (
+
+
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx b/bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx
new file mode 100644
index 0000000..bdefe7a
--- /dev/null
+++ b/bikeshop_project/assets/js/bikes/components/BikeTable/index.jsx
@@ -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 => (
+
+ {friendlySize(bike.size)}
+ {bike.colour}
+ {bike.make}
+ {bike.serial_number}
+ {bike.state}
+ {bike.claimed_by}
+
+
+ ));
+
+ return (
+
+
+
Bikes
+
+
+
+ Size
+ Colour
+ Make
+ Serial number
+ State
+ Claimed by
+
+
+
+
+ {bikeRows.length ?
+ bikeRows :
+
+ {'No members currently signed in.'}
+
+ }
+
+
+
+
+
+ );
+ }
+}
diff --git a/bikeshop_project/assets/js/bikes/components/Size/index.jsx b/bikeshop_project/assets/js/bikes/components/Size/index.jsx
new file mode 100644
index 0000000..42eb4d4
--- /dev/null
+++ b/bikeshop_project/assets/js/bikes/components/Size/index.jsx
@@ -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 =>
+ ,
+ );
+
+ return (
+
+
+
+ {items}
+
+
+ );
+};
+
+Size.propTypes = {
+ size: PropTypes.string,
+};
+
+export default Size;
diff --git a/bikeshop_project/assets/js/bikes/components/Source/index.jsx b/bikeshop_project/assets/js/bikes/components/Source/index.jsx
new file mode 100644
index 0000000..5ef46d2
--- /dev/null
+++ b/bikeshop_project/assets/js/bikes/components/Source/index.jsx
@@ -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 =>
+ ,
+ );
+
+ return (
+
+
+
+ {items}
+
+
+ );
+};
+
+Source.propTypes = {
+ source: PropTypes.string,
+};
+
+export default Source;
diff --git a/bikeshop_project/assets/js/bikes/index.jsx b/bikeshop_project/assets/js/bikes/index.jsx
index 6b0ab20..95aac39 100644
--- a/bikeshop_project/assets/js/bikes/index.jsx
+++ b/bikeshop_project/assets/js/bikes/index.jsx
@@ -1,6 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
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
// http://stackoverflow.com/a/34015469/988941
@@ -10,11 +13,9 @@ injectTapEventPlugin();
class App extends React.Component {
render() {
return (
-
+
+
+
);
}
}