Skip to content

Commit 36a9e01

Browse files
committed
Step 8 - Optimistic updating
1 parent cf2b592 commit 36a9e01

File tree

19 files changed

+1102
-1
lines changed

19 files changed

+1102
-1
lines changed

07-submit-email-form/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ None
1111

1212
## Next
1313

14-
Coming soon...
14+
Go to [Step 8 - Optimistic updating](https://github.com/benmvp/react-workshop/tree/master/08-optimistic-updating).
1515

1616
## Resources
1717

07-submit-email-form/src/containers/App.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ export default class EmailApp extends React.Component {
7676
body: JSON.stringify(newEmail)
7777
})
7878
.then((res) => res.json())
79+
.then(({success}) => {
80+
if (!success) {
81+
throw new Error('Unable to send email!');
82+
}
83+
})
7984
.then(() => this._getUpdateEmails())
8085
.catch((ex) => console.error(ex));
8186
}

08-optimistic-updating/.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Ignore built files
2+
src/dist/

08-optimistic-updating/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Step 8 - Optimistic updating
2+
3+
## Setup
4+
5+
None
6+
7+
## Tasks
8+
9+
- After `POST`ing new email, optimistically update the `emails` state prior to `GET`ting the actual server data
10+
11+
## Next
12+
13+
Coming soon...
14+
15+
## Resources
16+
17+
None

08-optimistic-updating/api-server.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
var fs = require('fs'),
2+
path = require('path'),
3+
express = require('express'),
4+
bodyParser = require('body-parser'),
5+
6+
assign = require('lodash/assign'),
7+
find = require('lodash/find'),
8+
findIndex = require('lodash/findIndex'),
9+
10+
app = express(),
11+
router = express.Router(),
12+
13+
// Using a JSON file as our "database"
14+
EMAILS_FILE = path.join(__dirname, 'data/emails.json'),
15+
16+
port = process.env.PORT || 9090;
17+
18+
function getEmails(callback) {
19+
fs.readFile(EMAILS_FILE, function(err, fileContents) {
20+
if (err) {
21+
console.log(err);
22+
process.exit(1);
23+
}
24+
25+
callback(JSON.parse(fileContents));
26+
});
27+
}
28+
29+
function saveEmails(emails, callback) {
30+
fs.writeFile(EMAILS_FILE, JSON.stringify(emails, null, 4), function(err) {
31+
if (err) {
32+
console.log(err);
33+
process.exit(1);
34+
}
35+
36+
callback();
37+
});
38+
}
39+
40+
app.use(bodyParser.json());
41+
app.use(bodyParser.urlencoded({extended: true}));
42+
43+
// allow for cross-origin API requests
44+
app.use(function(req, res, next) {
45+
res.header('Access-Control-Allow-Origin', '*');
46+
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
47+
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
48+
next();
49+
});
50+
51+
// routes that end in /emails
52+
router.route('/emails')
53+
54+
// create an email (accessed via POST to http://localhost:9090/emails)
55+
.post(function(req, res) {
56+
getEmails(function(emails) {
57+
var newEmail = assign({
58+
id: Date.now(),
59+
date: new Date() + '',
60+
unread: true
61+
}, req.body),
62+
newEmails = emails.concat(newEmail);
63+
64+
// write out file back to disk
65+
saveEmails(newEmails, function() {
66+
res.json({success: true});
67+
});
68+
});
69+
})
70+
71+
// get all the emails (access via GET from http://localhost:9090/emails)
72+
.get(function(req, res) {
73+
getEmails(function(emails) {
74+
// Return back the full list of emails
75+
res.setHeader('Cache-Control', 'no-cache');
76+
res.json(
77+
emails
78+
.filter(function(email) { return !email.deleted; })
79+
.sort(function(emailA, emailB) { return new Date(emailB.date) - new Date(emailA.date); })
80+
);
81+
});
82+
});
83+
84+
// routes that end in emails/:emailId
85+
router.route('/emails/:emailId')
86+
87+
// get the email with this id (accessed via GET from http://localhost:9090/emails/:emailId)
88+
.get(function(req, res) {
89+
getEmails(function(emails) {
90+
var emailIdToGet = +req.params.emailId,
91+
emailToGet = find(emails, function(email) {
92+
return email.id === emailIdToGet;
93+
});
94+
95+
res.json(emailToGet);
96+
});
97+
})
98+
99+
// update the email this id (accessed via PUT on http://localhost:9090/emails/:emailId)
100+
.put(function(req, res) {
101+
getEmails(function(emails) {
102+
var emailIdToUpdate = +req.params.emailId,
103+
104+
// make a new copy of the emails list, updating the appropriate email
105+
updatedEmails = emails.map(function(email) {
106+
if (email.id === emailIdToUpdate) {
107+
// make a copy of the email to update before updating
108+
return assign({}, email, {
109+
unread: !!req.body.unread
110+
});
111+
}
112+
113+
return email;
114+
});
115+
116+
saveEmails(updatedEmails, function() {
117+
res.json({success: true});
118+
});
119+
});
120+
})
121+
122+
// delete the email this id (accessed via PUT on http://localhost:9090/emails/:emailId)
123+
.delete(function(req, res) {
124+
getEmails(function(emails) {
125+
var emailIdToDelete = +req.params.emailId,
126+
127+
// make a new copy of the emails list, marking the appropriate email as deleted
128+
updatedEmails = emails.map(function(email) {
129+
if (email.id === emailIdToDelete) {
130+
// make a copy of the email to update before updating
131+
return assign({}, email, {
132+
deleted: true
133+
});
134+
}
135+
136+
return email;
137+
});
138+
139+
saveEmails(updatedEmails, function() {
140+
res.json({success: true});
141+
});
142+
});
143+
});
144+
145+
// Register the routes
146+
app.use('/', router);
147+
148+
app.get('/ping', function(req, res) {
149+
res.json({success: true});
150+
});
151+
152+
app.listen(port, function() {
153+
console.log('Server started: http://localhost:' + port + '/');
154+
});

0 commit comments

Comments
 (0)