Skip to content

Commit 2f30526

Browse files
committed
can add contacts now
1 parent 8016dfb commit 2f30526

File tree

7 files changed

+29268
-12
lines changed

7 files changed

+29268
-12
lines changed

app/components/NewContactForm.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/** @jsx React.DOM */
2+
var React = require('react');
3+
var Navigation = require('react-router').Navigation;
4+
5+
var NewContactForm = module.exports = React.createClass({
6+
7+
mixins: [Navigation],
8+
9+
handleSubmit: function(event) {
10+
event.preventDefault();
11+
var first = this.refs.first.getDOMNode().value;
12+
var last = this.refs.last.getDOMNode().value;
13+
this.transitionTo('createContact', {}, {first: first, last: last});
14+
},
15+
16+
render: function() {
17+
return (
18+
<form
19+
action="/add-user"
20+
onSubmit={this.handleSubmit}
21+
>
22+
<p>
23+
<input ref="first" name="first" placeholder="first name"
24+
/> <input ref="last" name="last" placeholder="last name"
25+
/> <button type="submit">Add</button>
26+
</p>
27+
</form>
28+
);
29+
}
30+
});
31+

app/handlers/CreateContact.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/** @jsx React.DOM */
2+
var React = require('react');
3+
var api = require('../utils/api');
4+
var ContactStore = require('../stores/ContactStore');
5+
6+
var CreateContact = module.exports = React.createClass({
7+
8+
statics: {
9+
willTransitionTo: function(transition, params, query) {
10+
transition.wait(
11+
api.post('/contacts', {contact: query}).then(function(data) {
12+
ContactStore.add(data.contact);
13+
transition.redirect('contact', {id: data.contact.id});
14+
})
15+
);
16+
}
17+
},
18+
19+
render: function() {
20+
return null;
21+
}
22+
23+
});
24+

app/handlers/Root.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,59 @@
22
var React = require('react');
33
var api = require('../utils/api');
44
var Link = require('react-router').Link;
5+
var NewContactForm = require('../components/NewContactForm');
6+
var ContactStore = require('../stores/ContactStore');
57

68
var Root = module.exports = React.createClass({
79

810
statics: {
911
getRouteProps: function() {
10-
var preloadedData = ENV.CLIENT && window.ROUTER_PROPS.root;
11-
return preloadedData || {
12-
contactData: api.get('/contacts')
12+
return {
13+
contacts: ContactStore.getAll()
1314
};
1415
}
1516
},
1617

18+
getInitialState: function() {
19+
return {
20+
contacts: this.props.contacts
21+
};
22+
},
23+
24+
componentWillReceiveProps: function(newProps) {
25+
// because we have to put it on state, we have to get the new props
26+
this.setState({contacts: newProps.contacts});
27+
},
28+
1729
renderContacts: function() {
18-
if (!this.props.contactData) return null;
19-
var contacts = this.props.contactData.contacts;
30+
if (!this.props.contacts)
31+
return null;
32+
33+
var contacts = this.state.contacts.records;
2034
return contacts.map(function(contact) {
2135
return <li key={contact.id}>
2236
<Link to="contact" params={{id: contact.id}}>{contact.first} {contact.last}</Link>
2337
</li>;
2438
});
2539
},
2640

41+
componentDidMount: function() {
42+
ContactStore.addChangeListener(this.handleContactsChange);
43+
},
44+
45+
componentWillUnmount: function() {
46+
ContactStore.removeChangeListener(this.handleContactsChange);
47+
},
48+
49+
handleContactsChange: function() {
50+
this.setState({contactData: ContactStore.getAll()});
51+
},
52+
2753
render: function() {
2854
return (
2955
<div>
3056
<h1>Address Book</h1>
57+
<NewContactForm/>
3158
<ul>
3259
{this.renderContacts()}
3360
</ul>

app/routes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = (
1010
<Route name="root" path="/" handler={require('./handlers/Root')}>
1111
<DefaultRoute handler={require('./handlers/Home')} />
1212
<Route name="contact" path="contact/:id" handler={require('./handlers/Contact')} />
13+
<Route name="createContact" handler={require('./handlers/CreateContact')} />
1314
</Route>
1415
</Routes>
1516
);

app/stores/ContactStore.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
var Promise = require('when');
2+
var api = require('../utils/api');
3+
var EventEmitter = require('events').EventEmitter;
4+
var k = function() {};
5+
var mergeInto = require('react/lib/mergeInto');
6+
7+
var _events = new EventEmitter();
8+
9+
var _state = {
10+
loaded: false,
11+
records: []
12+
};
13+
14+
if (ENV.CLIENT && window.ROUTER_PROPS.root) {
15+
mergeInto(_state, window.ROUTER_PROPS.root.contacts);
16+
}
17+
18+
exports.getAll = function() {
19+
if (_state.loaded) {
20+
// MUST BE SYNC. Otherwise we render one the client once while waiting for
21+
// the promise and then the checksum doesn't match up
22+
return _state;
23+
}
24+
25+
return api.get('/contacts').then(function(data) {
26+
_state.loaded = true;
27+
_state.records = data.contacts;
28+
return _state;
29+
});
30+
};
31+
32+
exports.add = ENV.CLIENT ? function(contact) {
33+
_state.records.push(contact);
34+
_events.emit('change');
35+
} : k;
36+
37+
exports.addChangeListener = function(fn) {
38+
_events.on('change', fn);
39+
};
40+
41+
exports.removeChangeListener = function(fn) {
42+
_events.off('change', fn);
43+
};
44+

app/utils/api.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ exports.get = function(url) {
77
});
88
};
99

10+
exports.post = function(url, data) {
11+
return axios.post(HOST+url, data).then(function(res) {
12+
return res.data;
13+
});
14+
};
15+

public/js/main.js

Lines changed: 29130 additions & 7 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)