mirror of
				https://github.com/fspc/workstand.git
				synced 2025-11-04 00:45:35 -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 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 (
 | 
			
		||||
      <div className="mdl-grid">
 | 
			
		||||
          <div className="mdl-cell mdl-cell--12-col">
 | 
			
		||||
              <h1>Bikes</h1>
 | 
			
		||||
          </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <MuiThemeProvider muiTheme={getMuiTheme()}>
 | 
			
		||||
        <BikeTable/>
 | 
			
		||||
      </MuiThemeProvider>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user