From a24014552304ee57a20fba6b2782698065954deb Mon Sep 17 00:00:00 2001 From: Drew Larson Date: Thu, 23 Jun 2016 09:48:12 -0600 Subject: [PATCH] A better sign-in form. --- .../assets/js/components/Member.jsx | 20 +++ .../assets/js/components/Purpose.jsx | 18 +++ .../assets/js/components/SignIn.jsx | 116 ++++++++++++++++++ .../assets/js/components/SignedInList.jsx | 33 +++++ bikeshop_project/assets/js/index.jsx | 60 +-------- bikeshop_project/package.json | 1 + 6 files changed, 190 insertions(+), 58 deletions(-) create mode 100644 bikeshop_project/assets/js/components/Member.jsx create mode 100644 bikeshop_project/assets/js/components/Purpose.jsx create mode 100644 bikeshop_project/assets/js/components/SignIn.jsx create mode 100644 bikeshop_project/assets/js/components/SignedInList.jsx diff --git a/bikeshop_project/assets/js/components/Member.jsx b/bikeshop_project/assets/js/components/Member.jsx new file mode 100644 index 0000000..4e74554 --- /dev/null +++ b/bikeshop_project/assets/js/components/Member.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import AutoComplete from 'material-ui/AutoComplete'; + +export default class Member extends React.Component { + render () { + return ( + + ); + } +} \ No newline at end of file diff --git a/bikeshop_project/assets/js/components/Purpose.jsx b/bikeshop_project/assets/js/components/Purpose.jsx new file mode 100644 index 0000000..1ec1eeb --- /dev/null +++ b/bikeshop_project/assets/js/components/Purpose.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import SelectField from 'material-ui/SelectField'; +import MenuItem from 'material-ui/MenuItem'; + +export default class Purpose extends React.Component { + render () { + return ( + + + + + + + + ); + } +} + diff --git a/bikeshop_project/assets/js/components/SignIn.jsx b/bikeshop_project/assets/js/components/SignIn.jsx new file mode 100644 index 0000000..88ab55a --- /dev/null +++ b/bikeshop_project/assets/js/components/SignIn.jsx @@ -0,0 +1,116 @@ +import React from 'react'; +import RaisedButton from 'material-ui/RaisedButton'; +import { polyFill } from 'es6-promise'; +import fetch from 'isomorphic-fetch'; +import Purpose from './Purpose'; +import Member from './Member'; +import SignedInList from './SignedInList'; +import moment from 'moment'; + +export default class SignIn extends React.Component { + constructor (props) { + super(props); + this.state = { + members: [], + signOn: {purpose: 'FIX', member: undefined}, + error: '', + signedIn: [], + searchText: '' + }; + this.handleUpdate = this.handleUpdate.bind(this); + this.signIn = this.signIn.bind(this); + this.chooseMember = this.chooseMember.bind(this); + this.handlePurposeChoice = this.handlePurposeChoice.bind(this); + } + + handlePurposeChoice (event, index, value) { + this.setState({...this.state, signOn: {...this.state.signOn, purpose: value}}); + } + + handleUpdate (text, dataSource) { + const self = this; + self.setState({searchText: text}) + fetch(`//bikeshop.local/member/search/${text}/`) + .then((response) => { + if (response.status === 200) + return response.json(); + }) + .then((data) => { + if (data.results.length > 0) { + self.setState({ + ...this.state, + error: '', + members: data.results.map((result) => { + return {text: `${result.name}`, value: `${result.name} <${result.email}>`, id: result.id} + }) + }); + } else { + self.setState({...this.state, error: 'Member not found.'}) + } + }) + } + + signIn () { + const purpose = this.state.signOn.purpose; + const member = this.state.signOn.member; + + if (!this.state.signedIn.find((signedInMember) => {return signedInMember.id === member.id})) { + fetch('//bikeshop.local/member/signin/', { + method: 'post', + body: `id=${member.id}&purpose=${purpose}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).then((response) => { + if (response.status === 201) + return response.json(); + }).then((data) => { + const now = moment(); + const signedIn = this.state.signedIn; + signedIn.push({...member, purpose, at: now}); + this.setState({ + ...this.state, + signedIn: signedIn, + signOn: {purpose: 'FIX', member: undefined}, + searchText: '', + members: [] + }) + }); + } else { + this.setState({...this.state, error: 'Member already signed in.'}) + } + } + + chooseMember (chosenRequest, index) { + console.log(index); + const member = this.state.members[index]; + const purpose = this.state.signOn.purpose; + + this.setState({...this.state, signOn: {member, purpose}}); + } + + onUpdateSearchText(searchText, dataSource) { + this.setState({searchText: searchText}) + } + + render () { + return ( +
+ +
+ +
+ +
+
+ +
+ ); + } +} \ No newline at end of file diff --git a/bikeshop_project/assets/js/components/SignedInList.jsx b/bikeshop_project/assets/js/components/SignedInList.jsx new file mode 100644 index 0000000..73a15c5 --- /dev/null +++ b/bikeshop_project/assets/js/components/SignedInList.jsx @@ -0,0 +1,33 @@ +import React from 'react'; +import {List, ListItem} from 'material-ui/List'; + +export default class SignedInList extends React.Component { + constructor (props) { + super(props); + this.state = {tick: 0}; + this.componentDidMount = this.componentDidMount.bind(this); + this.componentWillUnmount = this.componentWillUnmount.bind(this); + this.tick = this.tick.bind(this); + } + componentDidMount () { + this.timer = setInterval(this.tick, 50); + } + componentWillUnmount () { + clearInterval(this.timer); + } + tick () { + this.setState({tick: this.state.tick++}); + } + render () { + let members = this.props.members.map((member) => { + return + }); + + return ( +
+

Members signed in

+ {members} +
+ ); + } +} \ No newline at end of file diff --git a/bikeshop_project/assets/js/index.jsx b/bikeshop_project/assets/js/index.jsx index 926af4d..c43f688 100644 --- a/bikeshop_project/assets/js/index.jsx +++ b/bikeshop_project/assets/js/index.jsx @@ -8,71 +8,15 @@ injectTapEventPlugin(); import getMuiTheme from 'material-ui/styles/getMuiTheme'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; -import AutoComplete from 'material-ui/AutoComplete'; -import { polyFill } from 'es6-promise'; -import fetch from 'isomorphic-fetch'; +import SignIn from './components/SignIn'; -class MemberAutoComplete extends React.Component { - - constructor (props) { - super(props); - this.state = {members: [], error: '' }; - this.handleUpdate = this.handleUpdate.bind(this); - this.signIn = this.signIn.bind(this); - // this.filter = this.filter.bind(this); - } - - handleUpdate (text, dataSource) { - let self = this; - fetch(`//bikeshop.local/member/search/${text}/`) - .then((response) => { - if (response.status === 200) - return response.json(); - }) - .then((data) => { - console.log(data.results); - if (data.results.length > 0) { - self.setState({ - error: '', - members: data.results.map((result) => { - return {text: `${result.name}`, value: `${result.name} <${result.email}>`, id: result.id} - }) - }); - } else { - self.setState({error: 'Member not found.'}) - } - // self.setState({members: data.results}) - }) - } - - handleFilter (searchText, key) { - console.log(searchText); - console.log(key); - } - - signIn (chosenRequest, idx) { - console.log(chosenRequest) - console.log(this.state.members[idx]) - } - - render () { - return - } -} class App extends React.Component { render () { return ( - + ) } diff --git a/bikeshop_project/package.json b/bikeshop_project/package.json index 0ef2b49..b1c7982 100644 --- a/bikeshop_project/package.json +++ b/bikeshop_project/package.json @@ -21,6 +21,7 @@ "i": "^0.3.5", "isomorphic-fetch": "^2.2.1", "material-ui": "^0.15.0", + "moment": "^2.13.0", "node-sass": "^3.4.2", "normalize.css": "^4.1.1", "postcss-loader": "^0.9.1",