diff --git a/package.json b/package.json index 8225082..c047b7b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "A simple API layer to model an inventory", "main": "server.js", "scripts": { + "server": "nodemon server --ignore public/ --ignore store/", "test": " " }, "author": "jbkly", @@ -14,5 +15,8 @@ "inert": "^3.2.0", "joi": "^8.0.2", "vision": "^4.0.1" + }, + "devDependencies": { + "nodemon": "^1.9.0" } } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..02bd95d Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index a7b365b..b2e090f 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ Inventory Demo - + diff --git a/public/js/app.js b/public/js/app.js index 012330e..849c678 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,120 +1,118 @@ -// const CommentBox = React.createClass({ -// loadCommentsFromServer: function() { -// $.ajax({ -// url: this.props.url, -// dataType: 'json', -// cache: false, -// success: data => this.setState({data}), -// error: (xhr, status, err) => console.error(this.props.url, status, err.toString()) -// }); -// }, -// handleCommentSubmit: function(comment) { -// // optimistically update UI before hearing back from server -// var comments = this.state.data; -// comment.id = Date.now(); // create a temporary id, will be replaced by the server-gen id -// var newComments = comments.concat([comment]); -// this.setState({data: newComments}); +const InventorySystem = React.createClass({ + loadInventory: function() { + $.ajax({ + url: this.props.url, + dataType: 'json', + cache: false, + success: reply => this.setState({data: reply.data}), + error: (xhr, status, err) => console.error(this.props.url, status, err.toString()) + }); + }, + handleAddToInventory: function(item) { + // optimistically update UI before hearing back from server + let items = this.state.data; + let updatedItems = Object.assign(items); + updatedItems[item.label] = item; + this.setState({data: updatedItems}); -// $.ajax({ -// url: this.props.url, -// dataType: 'json', -// type: 'POST', -// data: comment, -// success: data => this.setState({data}), -// error: (xhr, status, err) => {r -// this.setState({data: comments}); -// console.errer(this.props.url, status, err.toString()) -// } -// }); -// }, -// getInitialState: function() { -// return {data: []}; -// }, -// componentDidMount: function() { -// this.loadCommentsFromServer(); -// setInterval(this.loadCommentsFromServer, this.props.pollInterval); -// }, -// render: function() { -// return ( -//
-//

Comments

-// -// -//
-// ); -// } -// }); + $.ajax({ + url: this.props.url, + dataType: 'json', + type: 'POST', + data: item, + success: reply => this.setState({data: reply.data}), + error: (xhr, status, err) => { + this.setState({data: items}); + console.errer(this.props.url, status, err.toString()) + } + }); + }, + getInitialState: function() { + return {data: []}; + }, + componentDidMount: function() { + this.loadInventory(); + setInterval(this.loadInventory, this.props.pollInterval); + }, + render: function() { + return ( +
+

Inventory System

+ + +
+ ); + } +}); -// const CommentList = React.createClass({ -// render: function() { -// var commentNodes = this.props.data.map(function(comment) { -// return ( -// {comment.text} -// ); -// }); -// return ( -//
-// {commentNodes} -//
-// ); -// } -// }); +const ItemList = React.createClass({ + render: function() { + let itemList = Array.from(Object.keys(this.props.data), key => { + let item = this.props.data[key]; + return ( + {item.label} + ); + }); + return ( +
+ {itemList} +
+ ); + } +}); -// const CommentForm = React.createClass({ -// getInitialState: function() { -// return {author: '', text: ''}; -// }, -// handleAuthorChange: function(e) { -// this.setState({author: e.target.value}); -// }, -// handleTextChange: function(e) { -// this.setState({text: e.target.value}); -// }, -// handleSubmit: function(e) { -// e.preventDefault(); -// let author = this.state.author.trim(); -// let text = this.state.text.trim(); -// if (!text || !author) return; -// this.props.onCommentSubmit({author, text}); -// this.setState({author: '', text: ''}); -// }, -// render: function() { -// return ( -//
-// -// -// -//
-// ); -// } -// }); +const AddItemForm = React.createClass({ + getInitialState: function() { + return {label: '', type: '', expiration: ''}; + }, + handleLabelChange: function(e) { + this.setState({label: e.target.value}); + }, + handleTypeChange: function(e) { + this.setState({type: e.target.value}); + }, + handleSubmit: function(e) { + e.preventDefault(); + let label = this.state.label.trim(); + let type = this.state.type.trim(); + if (!type || !label) return; + this.props.onAddItem({label, type}); + this.setState({label: '', type: '', expiration: ''}); + }, + render: function() { + return ( +
+ + + +
+ ); + } +}); -// const Comment = React.createClass({ -// rawMarkup: function() { -// var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); -// return { __html: rawMarkup }; -// }, -// render: function() { -// return ( -//
-//

{this.props.author}

-// -//
-// ); -// } -// }); +const Item = React.createClass({ + render: function() { + return ( +
+

{this.props.label}

+

Type: {this.props.type}

+

Expires: {this.props.expiration}

+
+ ); + } +}); -// ReactDOM.render( -// , -// document.getElementById('content') -// ); +ReactDOM.render( + , + document.getElementById('content') +); diff --git a/server.js b/server.js index 3ef0d0f..b52dca6 100644 --- a/server.js +++ b/server.js @@ -75,14 +75,6 @@ const routes = [ server.route(routes); -server.start((err) => { - if (err) { - console.log(err); - } else { - console.log('server running at: ', server.info.uri); - } -}); - function getItems(request, reply) { fs.readFile(INVENTORY, (err, data) => { let response = err || { @@ -100,10 +92,11 @@ function addItem(request, reply) { console.error(err); return reply(err).code(500); } + let items = JSON.parse(data), - label = encodeURIComponent(request.params.label), - type = encodeURIComponent(request.params.type), - expiration = encodeURIComponent(request.params.expiration) || Date.now() + 300000; // 5min + label = request.payload.label, + type = request.payload.type, + expiration = parseInt(request.payload.expiration, 10) || Date.now() + 300000; // 5min if (items[label]) { return reply('Item by that label is already in inventory').code(409); @@ -124,7 +117,7 @@ function addItem(request, reply) { function removeItem(request, reply) { fs.readFile(INVENTORY, (err, data) => { - let label = encodeURIComponent(request.params.label); + let label = decodeURIComponent(request.params.label); if (err) { console.error(err); return reply(err).code(500); diff --git a/store/items.json b/store/items.json index 10e6c38..5c77f9b 100644 --- a/store/items.json +++ b/store/items.json @@ -13,5 +13,15 @@ "label": "Pizza", "type": "Italian", "expiration": 1456109060070 + }, + "Croissant-wich": { + "label": "Croissant-wich", + "type": "French-murican", + "expiration": 9283374098374099000 + }, + "Bison Burger": { + "label": "Bison Burger", + "type": "native murican", + "expiration": 1456375061762 } }