mirror of
				https://github.com/fspc/workstand.git
				synced 2025-10-31 08:25:35 -04:00 
			
		
		
		
	A better sign-in form.
This commit is contained in:
		
							parent
							
								
									b614a2b1a6
								
							
						
					
					
						commit
						a240145523
					
				
							
								
								
									
										20
									
								
								bikeshop_project/assets/js/components/Member.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								bikeshop_project/assets/js/components/Member.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| import React from 'react'; | ||||
| import AutoComplete from 'material-ui/AutoComplete'; | ||||
| 
 | ||||
| export default class Member extends React.Component { | ||||
|     render () { | ||||
|         return ( | ||||
|             <AutoComplete | ||||
|                 dataSource={this.props.members} | ||||
|                 onUpdateInput={this.props.handleUpdate.bind(this)} | ||||
|                 openOnFocus={true} | ||||
|                 filter={AutoComplete.noFilter} | ||||
|                 onNewRequest={this.props.signIn.bind(this)} | ||||
|                 errorText={this.props.error} | ||||
|                 hintText="Search members" | ||||
|                 searchText={this.props.searchText} | ||||
|                  | ||||
|             /> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								bikeshop_project/assets/js/components/Purpose.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								bikeshop_project/assets/js/components/Purpose.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -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 ( | ||||
|             <SelectField value={this.props.default} onChange={this.props.handleChange.bind(this)}> | ||||
|                 <MenuItem value={'VOLUNTEER'} primaryText="Volunteer" /> | ||||
|                 <MenuItem value={'FIX'} primaryText="Fix" /> | ||||
|                 <MenuItem value={'WORKSHOP'} primaryText="Workshop" /> | ||||
|                 <MenuItem value={'DONATE'} primaryText="Donate" /> | ||||
|                 <MenuItem value={'STAFF'} primaryText="Staff" /> | ||||
|             </SelectField> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										116
									
								
								bikeshop_project/assets/js/components/SignIn.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								bikeshop_project/assets/js/components/SignIn.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -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 ( | ||||
|             <div> | ||||
|                 <Member | ||||
|                     handleUpdate={this.handleUpdate} | ||||
|                     signIn={this.chooseMember} | ||||
|                     error={this.state.error} | ||||
|                     members={this.state.members} | ||||
|                     searchText={this.state.searchText} | ||||
|                 /> | ||||
|                 <br /> | ||||
|                 <Purpose handleChange={this.handlePurposeChoice} default={this.state.signOn.purpose}  /> | ||||
|                 <div> | ||||
|                     <RaisedButton onClick={this.signIn} label="Sign-in" /> | ||||
|                 </div> | ||||
|                 <br /> | ||||
|                 <SignedInList members={this.state.signedIn} /> | ||||
|             </div> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								bikeshop_project/assets/js/components/SignedInList.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								bikeshop_project/assets/js/components/SignedInList.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -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 <ListItem key={member.id} primaryText={member.text} secondaryText={`${member.purpose} – ${member.at.fromNow()}`} /> | ||||
|         }); | ||||
|          | ||||
|         return ( | ||||
|             <div> | ||||
|                 <h3>Members signed in</h3> | ||||
|                 {members} | ||||
|             </div> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -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 <AutoComplete | ||||
|             dataSource={this.state.members} | ||||
|             onUpdateInput={this.handleUpdate} | ||||
|             openOnFocus={true} | ||||
|             filter={AutoComplete.noFilter} | ||||
|             onNewRequest={this.signIn} | ||||
|             errorText={this.state.error} | ||||
|         /> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class App extends React.Component { | ||||
|     render () { | ||||
|         return ( | ||||
|             <MuiThemeProvider muiTheme={getMuiTheme()}> | ||||
|                 <MemberAutoComplete /> | ||||
|                 <SignIn /> | ||||
|             </MuiThemeProvider> | ||||
|         ) | ||||
|     } | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user