mirror of
https://github.com/fspc/workstand.git
synced 2026-09-16 16:41:38 -04:00
Refactor member list to be searchable (#27)
Trigger! * Added members API endpoint. * Stubbed out member table. Search is broken. * Better, faster member search! * Add add member button.
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import ContentAdd from 'material-ui/svg-icons/content/add';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import FloatingActionButton from 'material-ui/FloatingActionButton';
|
||||
import moment from 'moment';
|
||||
import { polyFill } from 'es6-promise';
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
import React from 'react';
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
|
||||
import Member from './Member';
|
||||
import Purpose from './Purpose';
|
||||
import SignedInList from './SignedInList';
|
||||
|
||||
|
||||
export default class SignIn extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -132,6 +135,7 @@ export default class SignIn extends React.Component {
|
||||
searchText={this.state.searchText}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mdl-cell mdl-cell--4-col">
|
||||
<Purpose
|
||||
handleChange={this.handlePurposeChoice}
|
||||
@@ -139,7 +143,6 @@ export default class SignIn extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mdl-grid">
|
||||
<div className="mdl-cell mdl-cell--2-col mdl-cell--10-offset">
|
||||
<RaisedButton onClick={this.signIn} label="Sign-in" />
|
||||
@@ -147,6 +150,9 @@ export default class SignIn extends React.Component {
|
||||
</div>
|
||||
<div className="mdl-grid">
|
||||
<SignedInList members={this.state.signedIn} />
|
||||
<FloatingActionButton href="/members/new/">
|
||||
<ContentAdd />
|
||||
</FloatingActionButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import React from 'react';
|
||||
import { polyFill } from 'es6-promise';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import { Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle } from 'material-ui/Toolbar';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
|
||||
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 MemberTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
members: [],
|
||||
searchText: '',
|
||||
filteredMembers: [],
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
this.handleUpdate = this.handleUpdate.bind(this);
|
||||
this.handleSearch = this.handleSearch.bind(this);
|
||||
this.clearSearch = this.clearSearch.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
fetch('/api/v1/members/')
|
||||
.then(checkStatus)
|
||||
.then(parseJSON)
|
||||
.then((data) => {
|
||||
this.setState({ members: data });
|
||||
console.log('request succeeded with JSON response', data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('request failed', error);
|
||||
});
|
||||
}
|
||||
|
||||
handleUpdate(event, value) {
|
||||
this.setState({ ...this.state, searchText: value });
|
||||
}
|
||||
|
||||
clearSearch() {
|
||||
this.setState({
|
||||
...this.state,
|
||||
searchText: '',
|
||||
});
|
||||
}
|
||||
|
||||
handleSearch() {
|
||||
const value = this.state.searchText.trim();
|
||||
const self = this;
|
||||
|
||||
fetch(`/members/search/${value}/`)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
}
|
||||
throw new Error('Bad response from server');
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.results.length > 0) {
|
||||
self.setState({
|
||||
...this.state,
|
||||
error: '',
|
||||
filteredMembers: this.state.members.filter((member) => {
|
||||
const ids = data.results.map(m => m.id);
|
||||
console.log(ids);
|
||||
|
||||
if (ids.indexOf(member.id) !== -1) {
|
||||
return member;
|
||||
}
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
self.setState({ ...this.state, error: 'Member not found.' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const memberRows = this.state.members.map(member => (
|
||||
<TableRow selectable={false} key={member.id}>
|
||||
<TableRowColumn>{member.first_name}</TableRowColumn>
|
||||
<TableRowColumn>{member.last_name}</TableRowColumn>
|
||||
<TableRowColumn>{member.email}</TableRowColumn>
|
||||
<TableRowColumn><FlatButton label="Edit" href={`/members/edit/${member.id}`} primary /></TableRowColumn>
|
||||
</TableRow>
|
||||
));
|
||||
|
||||
const filteredMemberRows = this.state.filteredMembers.map(member => (
|
||||
<TableRow selectable={false} key={member.id}>
|
||||
<TableRowColumn>{member.first_name}</TableRowColumn>
|
||||
<TableRowColumn>{member.last_name}</TableRowColumn>
|
||||
<TableRowColumn>{member.email}</TableRowColumn>
|
||||
<TableRowColumn><FlatButton label="Edit" href={`/members/edit/${member.id}`} primary /></TableRowColumn>
|
||||
</TableRow>
|
||||
));
|
||||
|
||||
|
||||
return (
|
||||
<div className="mdl-grid">
|
||||
<div className="mdl-cell mdl-cell--12-col">
|
||||
<h3>Members</h3>
|
||||
<Toolbar>
|
||||
<ToolbarGroup>
|
||||
<TextField
|
||||
hintText="ma@example.com OR name"
|
||||
floatingLabelText="Search for member"
|
||||
onChange={this.handleUpdate}
|
||||
value={this.state.searchText}
|
||||
/>
|
||||
<RaisedButton label="Search" primary onClick={this.handleSearch} />
|
||||
<RaisedButton label="Clear" onClick={this.clearSearch} secondary />
|
||||
</ToolbarGroup>
|
||||
</Toolbar>
|
||||
<Table selectable={false}>
|
||||
<TableHeader adjustForCheckbox={false} displaySelectAll={false}>
|
||||
<TableRow>
|
||||
<TableHeaderColumn>First name</TableHeaderColumn>
|
||||
<TableHeaderColumn>Last Name</TableHeaderColumn>
|
||||
<TableHeaderColumn>Email</TableHeaderColumn>
|
||||
<TableHeaderColumn />
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody displayRowCheckbox={false}>
|
||||
{filteredMemberRows.length ?
|
||||
filteredMemberRows : undefined
|
||||
}
|
||||
{memberRows.length && !this.state.searchText ?
|
||||
memberRows :
|
||||
<TableRow>
|
||||
<TableRowColumn>{'Members loading.'}</TableRowColumn>
|
||||
</TableRow>
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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 MemberTable from './components/MemberTable';
|
||||
|
||||
// Needed for onTouchTap
|
||||
// http://stackoverflow.com/a/34015469/988941
|
||||
injectTapEventPlugin();
|
||||
|
||||
|
||||
const App = () => (
|
||||
<MuiThemeProvider muiTheme={getMuiTheme()}>
|
||||
<div>
|
||||
<h1>Members</h1>
|
||||
<MemberTable />
|
||||
</div>
|
||||
</MuiThemeProvider>
|
||||
);
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
Reference in New Issue
Block a user