mirror of
https://github.com/fspc/workstand.git
synced 2025-02-28 11:33:24 -05: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