Shopping Cart
-
+
+
+ {{ item.title }}
+
+
+ {{ item.price | currency }} x {{ item.qty }}
+
+
+
+
+
+
+
+
+
Total: {{ total | currency }}
+
+
+
No items in the cart.
@@ -33,7 +72,11 @@
Shopping Cart
-
+
+
+
+
+
diff --git a/index.js b/index.js
index d0faddba..cfd2149b 100644
--- a/index.js
+++ b/index.js
@@ -4,9 +4,17 @@ var path = require('path');
var server = require('http').createServer(app);
var axios = require('axios');
var querystring = require('querystring');
+var Pusher = require('pusher');
require('dotenv').config();
+var pusher = new Pusher({
+ appId: process.env.PUSHER_APP_ID,
+ key: process.env.PUSHER_KEY,
+ secret: process.env.PUSHER_SECRET,
+ cluster: process.env.PUSHER_CLUSTER
+});
+
var bodyParser = require('body-parser');
app.use( bodyParser.json() );
@@ -31,6 +39,10 @@ app.get('/search/:query', function(req, res) {
;
});
+app.post('/cart_update', function(req, res) {
+ pusher.trigger('cart', 'update', req.body);
+});
+
app.use('/node_modules', express.static(path.join(__dirname, 'node_modules')));
app.use('/public', express.static(path.join(__dirname, 'public')));
diff --git a/package.json b/package.json
index 679e9eba..a584e3f6 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,8 @@
"body-parser": "~1.18.2",
"dotenv": "~2.0.0",
"express": "~4.16.3",
+ "pusher": "~1.5.1",
+ "pusher-js": "~4.2.2",
"querystring": "~0.2.0",
"scrollmonitor": "~1.2.0",
"vue": "~2.1.0",
diff --git a/public/script.js b/public/script.js
index a96bcad1..5a177150 100644
--- a/public/script.js
+++ b/public/script.js
@@ -1 +1,121 @@
-console.log('It works.');
+var PRICE = 9.99;
+var LOAD_NUM = 10;
+
+var pusher = new Pusher('[PUSHER_KEY]', {
+ cluster: '[PUSHER_CLUSTER]',
+ encrypted: true
+});
+
+new Vue({
+ el: '#app',
+ data: {
+ total: 0,
+ items: [],
+ results: [],
+ cart: [],
+ newSearch: 'anime',
+ lastSearch: '',
+ loading: false,
+ price: PRICE,
+ pusherUpdate: false
+ },
+ mounted: function() {
+ this.onSubmit();
+ var elem = document.getElementById('product-list-bottom');
+ var watcher = scrollMonitor.create(elem);
+ var vue = this;
+ watcher.enterViewport(function() {
+ vue.appendItems();
+ });
+ var channel = pusher.subscribe('cart');
+ channel.bind('update', function(data) {
+ vue.pusherUpdate = true;
+ vue.cart = data;
+ vue.total = 0;
+ for (var i = 0; i < vue.cart.length; i++) {
+ vue.total += PRICE * vue.cart[i].qty;
+ }
+ });
+ },
+ filters: {
+ currency: function(price) {
+ return '$'.concat(price.toFixed(2));
+ }
+ },
+ computed: {
+ noMoreItems: function() {
+ return this.results.length === this.items.length && this.results.length > 0;
+ }
+ },
+ watch: {
+ cart: {
+ handler: function(val) {
+ if (!this.pusherUpdate) {
+ this.$http.post('/cart_update', val);
+ } else {
+ this.pusherUpdate = false;
+ }
+ },
+ deep: true
+ }
+ },
+ methods: {
+ appendItems: function() {
+ if (this.items.length < this.results.length) {
+ var append = this.results.slice(this.items.length, this.items.length + LOAD_NUM);
+ this.items = this.items.concat(append);
+ }
+ },
+ onSubmit: function() {
+ if (this.newSearch.length) {
+ this.lastSearch = this.newSearch;
+ this.loading = true;
+ this.items = [];
+ this.results = [];
+ this.$http
+ .get('/search/'.concat(this.newSearch))
+ .then(function(res) {
+ this.loading = false;
+ this.results = res.data;
+ this.appendItems();
+ })
+ ;
+ }
+ },
+ addItem: function(index) {
+ var item = this.items[index];
+ var found = false;
+ for (var i = 0; i < this.cart.length; i++) {
+ if (this.cart[i].id === item.id) {
+ this.cart[i].qty++;
+ found = true;
+ }
+ }
+ if (!found) {
+ this.cart = this.cart.concat({
+ id: item.id,
+ title: item.title,
+ qty: 1,
+ price: PRICE
+ });
+ }
+ this.total += PRICE;
+ },
+ inc: function(item) {
+ item.qty++;
+ this.total += PRICE;
+ },
+ dec: function(item) {
+ item.qty--;
+ this.total -= PRICE;
+ if (item.qty <= 0) {
+ for (var i = 0; i < this.cart.length; i++) {
+ if (this.cart[i].id === item.id) {
+ this.cart.splice(i, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+});