├── .gitignore ├── LICENSE ├── README.md ├── auth ├── .babelrc ├── README.md ├── components │ ├── auth.vue │ ├── protected.vue │ ├── require_auth.js │ ├── signin.vue │ └── signup.vue ├── controllers │ └── auth.js ├── index.html ├── models │ └── user.js ├── package-lock.json ├── package.json ├── server.js ├── services │ └── passport.js ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ └── index.js └── webpack.config.js ├── counter ├── .babelrc ├── README.md ├── components │ └── counter.vue ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ └── index.js └── webpack.config.js ├── firestore ├── .babelrc ├── README.md ├── components │ └── simple-todo.vue ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ ├── firestore.js │ └── index.js └── webpack.config.js ├── gallery ├── .babelrc ├── README.md ├── components │ ├── image-form.vue │ └── images.vue ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ └── index.js └── webpack.config.js ├── shopping-cart ├── .babelrc ├── README.md ├── components │ ├── cart.vue │ └── products.vue ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── main.js │ └── router.js ├── store │ └── index.js └── webpack.config.js ├── simple-todo ├── .babelrc ├── README.md ├── components │ └── simple-todo.vue ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ └── index.js └── webpack.config.js ├── starter-files ├── .babelrc ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ └── main.js ├── store │ └── index.js └── webpack.config.js └── todo ├── .babelrc ├── README.md ├── components └── todo.vue ├── index.html ├── package-lock.json ├── package.json ├── src ├── App.vue ├── assets │ └── logo.png └── main.js ├── store └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # Editor directories and files 6 | .idea 7 | *.suo 8 | *.ntvs* 9 | *.njsproj 10 | *.sln 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ademola Adegbuyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vuex Examples 2 | 3 | > This project aims to touch various aspects of Vuex while building several projects. 4 | 5 | ## Contents 6 | 7 | - [Projects](#projects) 8 | - [Getting Started](#getting-started) 9 | - [Running each project](#running-each-project) 10 | 11 | ### Projects 12 | 13 | Browse through each project by going through the folders as listed below. 14 | 15 | - **Starter Files**: Where it all begins 16 | - **Auth**: An Auth example with Vuex 17 | - **Counter**: A simple counter implementation with Vuex 18 | - **Firestore**: A Simple FireStore implementation with Vuex 19 | - **Gallery**: An Image Gallery implementation with Vuex 20 | - **Simple Todo**: A Simple Todo implementation with Vuex 21 | - **Shopping Cart**: A Shopping Cart implementation with Vuex 22 | - **Todo**: A better todo app implementation with Vuex 23 | - [_Make request_](https://github.com/ooade/vuex-examples/issues/new) 24 | 25 | ### Getting Started 26 | 27 | - Clone the Repo: `git clone https://github.com/ooade/vuex-examples.git` 28 | 29 | ### Running each project 30 | 31 | ```bash 32 | # install dependencies 33 | npm --prefix install 34 | 35 | # serve with hot reload at localhost:8080 36 | npm --prefix run dev 37 | 38 | # build for production with minification 39 | npm --prefix run build 40 | ``` 41 | 42 | Example: To run the auth project 43 | 44 | ```bash 45 | npm --prefix auth install 46 | npm --prefix auth run dev 47 | npm --prefix auth run build 48 | ``` 49 | 50 | > Happy Coding! 51 | 52 | ## License 53 | 54 | MIT 55 | -------------------------------------------------------------------------------- /auth/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { "modules": false }]], 3 | "plugins": ["@babel/plugin-syntax-object-rest-spread"] 4 | } 5 | -------------------------------------------------------------------------------- /auth/README.md: -------------------------------------------------------------------------------- 1 | # Auth Example 2 | 3 | > An Auth example with Vuex which uses express, jwt and passport :smile: 4 | 5 | > [View App](https://vuex-auth.now.sh) -------------------------------------------------------------------------------- /auth/components/auth.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | 30 | 31 | 51 | -------------------------------------------------------------------------------- /auth/components/protected.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /auth/components/require_auth.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | 4 | import store from '../store' 5 | 6 | export default (to, from, next) => { 7 | // verify token ;) 8 | axios 9 | .get('/auth/verify', { headers: { auth: localStorage.token } }) 10 | .then(res => { 11 | // user is auth :) 12 | store.commit('AuthUser') 13 | next() 14 | }) 15 | .catch(err => { 16 | // send user to login page :( 17 | next('/login') 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /auth/components/signin.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 35 | 36 | -------------------------------------------------------------------------------- /auth/components/signup.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /auth/controllers/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jwt-simple') 2 | const User = require('../models/user') 3 | 4 | function tokenForUser(user) { 5 | const timeStamp = new Date().getTime() 6 | return jwt.encode({ sub: user.id, iat: timeStamp }, 'VueJS') 7 | } 8 | 9 | exports.signin = (req, res, next) => { 10 | //User has already had their email and password auth'd 11 | //req.user is passed on from passort 12 | res.send({ token: tokenForUser(req.user) }) 13 | } 14 | 15 | exports.signup = (req, res, next) => { 16 | const email = req.body.email 17 | const password = req.body.password 18 | 19 | if (!email || !password) { 20 | return res.status(422).send('You must provide email and password') 21 | } 22 | 23 | User.findOne({ email }, (err, existingUser) => { 24 | if (err) { 25 | return next(err) 26 | } 27 | 28 | if (existingUser) { 29 | return res.status(422).send('Email is in use') 30 | } 31 | 32 | const user = new User({ email, password }) 33 | 34 | user.save(err => { 35 | if (err) { 36 | return next(err) 37 | } 38 | 39 | res.json({ token: tokenForUser(user) }) 40 | }) 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /auth/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /auth/models/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Schema = mongoose.Schema 3 | const bcrypt = require('bcrypt-nodejs') 4 | 5 | const userSchema = new Schema({ 6 | email: { type: String, unique: true, lowercase: true }, 7 | password: String 8 | }) 9 | 10 | //OnSave Encrypt Password 11 | userSchema.pre('save', function(next) { 12 | const user = this 13 | 14 | bcrypt.genSalt(10, (err, salt) => { 15 | if (err) { 16 | return next(err) 17 | } 18 | 19 | bcrypt.hash(user.password, salt, null, (err, hash) => { 20 | if (err) { 21 | return next(err) 22 | } 23 | 24 | user.password = hash 25 | next() 26 | }) 27 | }) 28 | }) 29 | 30 | userSchema.methods.comparePassword = function(candidatePassword, callback) { 31 | bcrypt.compare(candidatePassword, this.password, (err, isMatch) => { 32 | if (err) { 33 | return callback(err) 34 | } 35 | 36 | callback(null, isMatch) 37 | }) 38 | } 39 | 40 | const ModelClass = mongoose.model('user', userSchema) 41 | 42 | module.exports = ModelClass 43 | -------------------------------------------------------------------------------- /auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development node server.js", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "node server.js" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.16.2", 14 | "bcrypt-nodejs": "0.0.3", 15 | "body-parser": "^1.18.2", 16 | "express": "^4.16.3", 17 | "jwt-simple": "^0.5.1", 18 | "mongoose": "^5.1.4", 19 | "passport": "^0.4.0", 20 | "passport-jwt": "^4.0.0", 21 | "passport-local": "^1.0.0", 22 | "vue": "^2.5.17", 23 | "vue-router": "^2.8.1", 24 | "vuex": "^2.5.0" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.1.2", 28 | "@babel/plugin-syntax-object-rest-spread": "^7.0.0", 29 | "@babel/preset-env": "^7.1.0", 30 | "babel-loader": "^8.0.4", 31 | "cross-env": "^3.0.0", 32 | "css-loader": "^1.0.0", 33 | "file-loader": "^2.0.0", 34 | "html-webpack-plugin": "^3.2.0", 35 | "vue-loader": "^15.4.2", 36 | "vue-style-loader": "^4.1.2", 37 | "vue-template-compiler": "^2.5.17", 38 | "webpack": "^4.20.2", 39 | "webpack-cli": "^3.1.2", 40 | "webpack-dev-middleware": "^3.4.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /auth/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const mongoose = require('mongoose'); 4 | const passport = require('passport'); 5 | 6 | const app = express(); 7 | 8 | const MONGO_URI = 9 | process.env.NODE_ENV === 'development' 10 | ? 'mongodb://localhost:27017/auth' 11 | : 'mongodb://heroku_x4xnglm7:em5c6br38p6molbe25j3qfqod6@ds011880.mlab.com:11880/heroku_x4xnglm7'; 12 | 13 | mongoose.connect(MONGO_URI); 14 | 15 | if (process.env.NODE_ENV === 'development') { 16 | const webpack = require('webpack'); 17 | const webpackDevMiddleware = require('webpack-dev-middleware'); 18 | const config = require('./webpack.config'); 19 | const compiler = webpack(config); 20 | 21 | app.use( 22 | webpackDevMiddleware(compiler, { 23 | noInfo: true, 24 | publicPath: config.output.publicPath, 25 | writeToDisk: filePath => { 26 | return /.*\.html$/.test(filePath); 27 | } 28 | }) 29 | ); 30 | } 31 | 32 | app.use(bodyParser.json()); 33 | 34 | const Auth = require('./controllers/auth'); 35 | require('./services/passport'); 36 | 37 | const requireAuth = passport.authenticate('jwt', { session: false }); 38 | const requireSignin = passport.authenticate('local', { session: false }); 39 | 40 | app.post('/auth/signin', requireSignin, Auth.signin); 41 | app.post('/auth/signup', Auth.signup); 42 | app.get('/auth/verify', requireAuth); 43 | 44 | app.use('/dist', express.static(process.cwd() + '/dist')); 45 | 46 | app.use((req, res) => res.sendFile(__dirname + '/dist/index.html')); 47 | 48 | app.listen(3000, () => console.log('Server Listening on PORT 3000')); 49 | -------------------------------------------------------------------------------- /auth/services/passport.js: -------------------------------------------------------------------------------- 1 | const passport = require('passport') 2 | const User = require('../models/user') 3 | const JwtStrategy = require('passport-jwt').Strategy 4 | const ExtractJwt = require('passport-jwt').ExtractJwt 5 | const LocalStrategy = require('passport-local') 6 | 7 | const localOptions = { usernameField: 'email' } 8 | const localLogin = new LocalStrategy(localOptions, (email, password, done) => { 9 | User.findOne({ email }, (err, user) => { 10 | if (err) { 11 | return done(err) 12 | } 13 | if (!user) { 14 | return done(null, false) 15 | } 16 | 17 | user.comparePassword(password, (err, isMatch) => { 18 | if (err) { 19 | return done(err) 20 | } 21 | if (!isMatch) { 22 | return done(null, false) 23 | } 24 | 25 | return done(null, user) 26 | }) 27 | }) 28 | }) 29 | 30 | const jwtOptions = { 31 | jwtFromRequest: ExtractJwt.fromHeader('auth'), 32 | secretOrKey: 'VueJS' 33 | } 34 | 35 | const jwtLogin = new JwtStrategy(jwtOptions, (payload, done) => { 36 | User.findById(payload.sub, (err, user) => { 37 | if (err) { 38 | return done(err, false) 39 | } 40 | 41 | if (user) { 42 | done(null, user) 43 | } else { 44 | done(null, false) 45 | } 46 | }) 47 | }) 48 | 49 | passport.use(jwtLogin) 50 | passport.use(localLogin) 51 | -------------------------------------------------------------------------------- /auth/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 53 | -------------------------------------------------------------------------------- /auth/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/auth/src/assets/logo.png -------------------------------------------------------------------------------- /auth/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | import Auth from '../components/auth.vue' 5 | import Protected from '../components/protected.vue' 6 | import RequireAuth from '../components/require_auth' 7 | 8 | Vue.use(Router) 9 | 10 | const router = new Router({ 11 | mode: 'history', 12 | routes: [ 13 | { path: '/auth', component: Auth }, 14 | { 15 | path: '/protected', 16 | component: Protected, 17 | beforeEnter: RequireAuth 18 | }, 19 | { path: '/*', component: Auth } 20 | ] 21 | }) 22 | 23 | import App from './App.vue' 24 | import store from '../store' 25 | 26 | new Vue({ 27 | el: '#app', 28 | store, 29 | router, 30 | render: h => h(App) 31 | }) 32 | -------------------------------------------------------------------------------- /auth/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import axios from 'axios' 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | authenticated: false, 10 | authError: null 11 | }, 12 | mutations: { 13 | AuthUser(state) { 14 | state.authenticated = true 15 | state.authError = null 16 | }, 17 | AuthError(state, e) { 18 | state.authError = e 19 | } 20 | }, 21 | actions: { 22 | signin({ commit }, { email, password }) { 23 | axios 24 | .post('/auth/signin', { 25 | email, 26 | password 27 | }) 28 | .then(res => saveToken(res.data.token, commit)) 29 | .catch(({ response }) => { 30 | commit('AuthError', response.data) 31 | }) 32 | }, 33 | signup({ commit }, { email, password }) { 34 | axios 35 | .post('/auth/signup', { 36 | email, 37 | password 38 | }) 39 | .then(res => saveToken(res.data.token, commit)) 40 | .catch(({ response }) => { 41 | commit('AuthError', response.data) 42 | }) 43 | } 44 | } 45 | }) 46 | 47 | function saveToken(token, cb) { 48 | localStorage.setItem('token', token) 49 | 50 | // user is auth ^_^ 51 | cb('AuthUser') 52 | } 53 | -------------------------------------------------------------------------------- /auth/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | publicPath: '/dist/', 11 | filename: '[name].bundle.js', 12 | chunkFilename: '[name].bundle.js' 13 | }, 14 | optimization: { 15 | splitChunks: { 16 | chunks: 'all' 17 | } 18 | }, 19 | mode: process.env.NODE_ENV, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.vue$/, 24 | loader: 'vue-loader' 25 | }, 26 | { 27 | test: /\.js$/, 28 | loader: 'babel-loader', 29 | exclude: /node_modules/ 30 | }, 31 | { 32 | test: /\.css$/, 33 | use: ['vue-style-loader', 'css-loader'] 34 | }, 35 | { 36 | test: /\.(png|jpg|gif|svg)$/, 37 | loader: 'file-loader', 38 | options: { 39 | name: '[name].[ext]?[hash]' 40 | } 41 | } 42 | ] 43 | }, 44 | resolve: { 45 | alias: { 46 | vue$: 'vue/dist/vue.esm.js' 47 | } 48 | }, 49 | performance: { 50 | hints: 'warning' 51 | }, 52 | plugins: [ 53 | new VueLoaderPlugin(), 54 | new HtmlWebpackPlugin({ 55 | title: 'Auth - Vuex Examples', 56 | template: path.join(__dirname, 'index.html') 57 | }) 58 | ], 59 | devtool: '#eval-source-map' 60 | }; 61 | 62 | if (process.env.NODE_ENV === 'production') { 63 | module.exports.devtool = '#source-map'; 64 | // http://vue-loader.vuejs.org/en/workflow/production.html 65 | module.exports.plugins = (module.exports.plugins || []).concat([ 66 | new webpack.DefinePlugin({ 67 | 'process.env': { 68 | NODE_ENV: '"production"' 69 | } 70 | }), 71 | new webpack.LoaderOptionsPlugin({ 72 | minimize: true 73 | }) 74 | ]); 75 | } 76 | -------------------------------------------------------------------------------- /counter/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /counter/README.md: -------------------------------------------------------------------------------- 1 | # Counter Example using Vuex 2 | 3 | > A Simple Counter Implementation with Vuex 4 | 5 | > [View App](https://vuex-counter.surge.sh) -------------------------------------------------------------------------------- /counter/components/counter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | 27 | -------------------------------------------------------------------------------- /counter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Counter - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /counter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"/index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-counter.surge.sh" 12 | }, 13 | "dependencies": { 14 | "superstatic": "^6.0.3", 15 | "vue": "^2.5.17", 16 | "vuex": "^2.5.0" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.1.2", 20 | "@babel/preset-env": "^7.1.0", 21 | "babel-loader": "^8.0.4", 22 | "cross-env": "^3.0.0", 23 | "css-loader": "^1.0.0", 24 | "file-loader": "^2.0.0", 25 | "html-webpack-plugin": "^3.2.0", 26 | "vue-loader": "^15.4.2", 27 | "vue-style-loader": "^4.1.2", 28 | "vue-template-compiler": "^2.5.17", 29 | "webpack": "^4.20.2", 30 | "webpack-cli": "^3.1.2", 31 | "webpack-dev-server": "^3.1.9" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /counter/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 59 | -------------------------------------------------------------------------------- /counter/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/counter/src/assets/logo.png -------------------------------------------------------------------------------- /counter/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | import App from './App.vue'; 4 | import store from '../store'; 5 | 6 | new Vue({ 7 | el: '#app', 8 | store, 9 | render: h => h(App) 10 | }); 11 | -------------------------------------------------------------------------------- /counter/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | count: 0 9 | }, 10 | mutations: { 11 | add(state, payload) { 12 | // If we get a payload, add it to count 13 | // Else, just add one to count 14 | payload ? (state.count += payload) : state.count++; 15 | }, 16 | subtract(state, payload) { 17 | payload ? (state.count -= payload) : state.count--; 18 | } 19 | }, 20 | actions: { 21 | addThreeAsync({ commit }) { 22 | setTimeout(() => commit('add', 3), 3000); 23 | } 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /counter/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /firestore/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /firestore/README.md: -------------------------------------------------------------------------------- 1 | # Simple Todo 2 | 3 | > A Simple FireStore implementation with Vuex 4 | 5 | > [View App](https://vuex-firestore.surge.sh) 6 | -------------------------------------------------------------------------------- /firestore/components/simple-todo.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /firestore/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FireStore - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /firestore/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"/index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-firestore.surge.sh" 12 | }, 13 | "dependencies": { 14 | "firebase": "^5.5.5", 15 | "superstatic": "^6.0.3", 16 | "vue": "^2.5.17", 17 | "vuex": "^2.5.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.1.2", 21 | "@babel/preset-env": "^7.1.0", 22 | "babel-loader": "^8.0.4", 23 | "cross-env": "^3.0.0", 24 | "css-loader": "^1.0.0", 25 | "file-loader": "^2.0.0", 26 | "html-webpack-plugin": "^3.2.0", 27 | "vue-loader": "^15.4.2", 28 | "vue-style-loader": "^4.1.2", 29 | "vue-template-compiler": "^2.5.17", 30 | "webpack": "^4.20.2", 31 | "webpack-cli": "^3.1.2", 32 | "webpack-dev-server": "^3.1.9" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /firestore/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 59 | -------------------------------------------------------------------------------- /firestore/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/firestore/src/assets/logo.png -------------------------------------------------------------------------------- /firestore/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import App from './App.vue' 4 | import store from '../store' 5 | 6 | new Vue({ 7 | el: '#app', 8 | store, 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /firestore/store/firestore.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase' 2 | require('firebase/firestore') 3 | import store from './' 4 | 5 | firebase.initializeApp({ 6 | apiKey: 'ENTER_API_KEY', 7 | authDomain: 'ENTER_AUTH_DOMAIN', 8 | projectId: 'ENTER_PROJECT_ID' 9 | }) 10 | 11 | const db = firebase.firestore() 12 | const todos = db.collection('todos') 13 | 14 | // Getting Real time feeds 15 | todos.onSnapshot(querySnapshot => { 16 | const myTodos = [] 17 | querySnapshot.forEach(doc => { 18 | myTodos.push({ id: doc.id, ...doc.data() }) 19 | }) 20 | store.commit('watchTodos', myTodos) 21 | }) 22 | 23 | export default { 24 | fetchTodos: () => { 25 | return todos.get() 26 | }, 27 | 28 | addTodo: text => { 29 | return todos.add({ text }) 30 | }, 31 | 32 | removeTodo: id => { 33 | return todos.doc(id).delete() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /firestore/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import firestore from './firestore'; 4 | 5 | Vue.use(Vuex); 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | todos: [] 10 | }, 11 | mutations: { 12 | watchTodos(state, todos) { 13 | state.todos = todos; 14 | }, 15 | removeTodo(state, todo) { 16 | state.todos.splice(state.todos.indexOf(todo), 1); 17 | } 18 | }, 19 | actions: { 20 | addTodo({ commit }, text) { 21 | firestore.addTodo(text); 22 | }, 23 | removeTodo({ commit }, todo) { 24 | firestore.removeTodo(todo.id); 25 | commit('removeTodo', todo); 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /firestore/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /gallery/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /gallery/README.md: -------------------------------------------------------------------------------- 1 | # Image Gallery 2 | 3 | > An Image Gallery implementation with Vuex 4 | 5 | > [Server](https://github.com/ooade/vuex-examples-server) 6 | 7 | > [View App](https://vuex-gallery.surge.sh) 8 | -------------------------------------------------------------------------------- /gallery/components/image-form.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 28 | -------------------------------------------------------------------------------- /gallery/components/images.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | 23 | 65 | 66 | -------------------------------------------------------------------------------- /gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Gallery - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /gallery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"/index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-gallery.surge.sh" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.16.2", 15 | "pimg": "^1.0.0", 16 | "superstatic": "^6.0.3", 17 | "vue": "^2.5.17", 18 | "vue-router": "^2.7.0", 19 | "vuex": "^2.5.0" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.1.2", 23 | "@babel/preset-env": "^7.1.0", 24 | "babel-loader": "^8.0.4", 25 | "cross-env": "^3.0.0", 26 | "css-loader": "^1.0.0", 27 | "file-loader": "^2.0.0", 28 | "html-webpack-plugin": "^3.2.0", 29 | "vue-loader": "^15.4.2", 30 | "vue-style-loader": "^4.1.2", 31 | "vue-template-compiler": "^2.5.17", 32 | "webpack": "^4.20.2", 33 | "webpack-cli": "^3.1.2", 34 | "webpack-dev-server": "^3.1.9" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /gallery/src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | 33 | 69 | -------------------------------------------------------------------------------- /gallery/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/gallery/src/assets/logo.png -------------------------------------------------------------------------------- /gallery/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueImage from 'pimg/dist/vue'; 3 | 4 | import App from './App.vue'; 5 | import store from '../store'; 6 | 7 | Vue.component('vue-image', VueImage); 8 | 9 | new Vue({ 10 | el: '#app', 11 | store, 12 | render: h => h(App) 13 | }); 14 | -------------------------------------------------------------------------------- /gallery/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import axios from 'axios' 4 | 5 | Vue.use(Vuex) 6 | 7 | const URL = 'https://vuex-server.herokuapp.com' 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | loading: false, 12 | temp_images: [], 13 | images: [] 14 | }, 15 | mutations: { 16 | tempSaveImages(state, e) { 17 | const images = Array.from(e.target.files) 18 | state.temp_images.unshift(...images) 19 | }, 20 | addImage(state, payload) { 21 | state.images.unshift(payload) 22 | }, 23 | removeImage(state, payload) { 24 | state.images.splice( 25 | state.images.findIndex(image => image._id === payload._id), 26 | 1 27 | ) 28 | axios.delete(`${URL}/api/images`, { 29 | data: payload 30 | }) 31 | }, 32 | toggleLoading(state) { 33 | state.loading = !state.loading 34 | } 35 | }, 36 | actions: { 37 | fetchImages({ state, commit }) { 38 | commit('toggleLoading') 39 | axios.get(`${URL}/api/images`).then(res => { 40 | commit('toggleLoading') 41 | state.images = res.data 42 | }) 43 | }, 44 | uploadImages({ state, commit }, e) { 45 | commit('toggleLoading') 46 | state.temp_images.map(image => { 47 | const data = new FormData() 48 | data.append('file', image) 49 | axios.post(`${URL}/api/images`, data).then(res => { 50 | commit('toggleLoading') 51 | e.target.reset() 52 | state.temp_images = [] 53 | commit('addImage', res.data) 54 | }) 55 | }) 56 | } 57 | } 58 | }) 59 | -------------------------------------------------------------------------------- /gallery/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /shopping-cart/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | # Shopping Cart 2 | 3 | > A Shopping Cart implementation with Vuex 4 | 5 | > [View App](https://vuex-shopping-cart.surge.sh) 6 | -------------------------------------------------------------------------------- /shopping-cart/components/cart.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 48 | 49 | 93 | 94 | -------------------------------------------------------------------------------- /shopping-cart/components/products.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 55 | 56 | 83 | -------------------------------------------------------------------------------- /shopping-cart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shopping Cart - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /shopping-cart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-shopping-cart.surge.sh" 12 | }, 13 | "dependencies": { 14 | "superstatic": "^6.0.3", 15 | "vue": "^2.5.17", 16 | "vue-router": "^2.7.0", 17 | "vuex": "^2.5.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.1.2", 21 | "@babel/preset-env": "^7.1.0", 22 | "babel-loader": "^8.0.4", 23 | "cross-env": "^3.0.0", 24 | "css-loader": "^1.0.0", 25 | "file-loader": "^2.0.0", 26 | "html-webpack-plugin": "^3.2.0", 27 | "vue-loader": "^15.4.2", 28 | "vue-style-loader": "^4.1.2", 29 | "vue-template-compiler": "^2.5.17", 30 | "webpack": "^4.20.2", 31 | "webpack-cli": "^3.1.2", 32 | "webpack-dev-server": "^3.1.9" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shopping-cart/src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | 33 | 59 | -------------------------------------------------------------------------------- /shopping-cart/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/shopping-cart/src/assets/logo.png -------------------------------------------------------------------------------- /shopping-cart/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import App from './App.vue' 4 | import store from '../store' 5 | import router from './router' 6 | 7 | new Vue({ 8 | el: '#app', 9 | store, 10 | router, 11 | render: h => h(App) 12 | }) 13 | -------------------------------------------------------------------------------- /shopping-cart/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | // get components 7 | import products from '../components/products.vue' 8 | import cart from '../components/cart.vue' 9 | 10 | // initialize router with the respective routes 11 | export default new Router({ 12 | mode: 'history', 13 | routes: [ 14 | { 15 | component: products, 16 | path: '/products' 17 | }, 18 | { 19 | component: cart, 20 | path: '/cart' 21 | } 22 | ] 23 | }) 24 | -------------------------------------------------------------------------------- /shopping-cart/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | const URI = 'https://c0rs.herokuapp.com/https://www.datakick.org/api/items' 7 | 8 | export default new Vuex.Store({ 9 | state: { 10 | cart: [], 11 | products: [] 12 | }, 13 | mutations: { 14 | addProduct({ products }, product) { 15 | products.push(product) 16 | }, 17 | addToCart({ cart, products }, product) { 18 | const itemIndex = cart.findIndex(item => item.id === product.id) 19 | 20 | if (itemIndex === -1) { 21 | cart.push({ ...product, count: 1 }) 22 | } else { 23 | cart[itemIndex].count++ 24 | } 25 | 26 | product.remaining > 1 27 | ? product.remaining-- 28 | : products.splice(products.indexOf(product), 1) 29 | }, 30 | deductItemCount({ cart }, product) { 31 | const itemIndex = cart.findIndex(item => item.id === product.id) 32 | 33 | cart[itemIndex].count > 1 34 | ? cart[itemIndex].count-- 35 | : cart.splice(itemIndex, 1) 36 | }, 37 | removeItem({ cart }, product) { 38 | const itemIndex = cart.findIndex(item => item.id === product.id) 39 | 40 | cart.splice(itemIndex, 1) 41 | }, 42 | clearCart(state) { 43 | state.cart = [] 44 | } 45 | }, 46 | actions: { 47 | fetchProducts({ commit, getters }) { 48 | fetch(URI) 49 | .then(res => res.json()) 50 | .then(data => { 51 | // Get the last 50 products 52 | const products = data.slice(50) 53 | 54 | products.forEach(product => { 55 | // Commit only non-existing products with a size 56 | if ( 57 | !getters.brandNames.includes(product.brand_name) && 58 | product.size 59 | ) { 60 | commit('addProduct', { 61 | brand_name: product.brand_name, 62 | name: product.name, 63 | id: product.gtin14, 64 | remaining: 10, 65 | price: 66 | Math.floor(parseInt(product.size) * 5 / Math.random()) * 10 67 | }) 68 | } 69 | }) 70 | }) 71 | } 72 | }, 73 | getters: { 74 | brandNames: state => state.products.map(product => product.brand_name), 75 | 76 | totalAmount: state => { 77 | let amount = 0 78 | 79 | state.cart.forEach(item => (amount += item.price * item.count)) 80 | 81 | return amount 82 | } 83 | } 84 | }) 85 | -------------------------------------------------------------------------------- /shopping-cart/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /simple-todo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /simple-todo/README.md: -------------------------------------------------------------------------------- 1 | # Simple Todo 2 | 3 | > A Simple Todo implementation with Vuex 4 | 5 | > [View App](https://vuex-simple-todo.surge.sh) 6 | -------------------------------------------------------------------------------- /simple-todo/components/simple-todo.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 45 | -------------------------------------------------------------------------------- /simple-todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Simple Todo - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /simple-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-simple-todo.surge.sh" 12 | }, 13 | "dependencies": { 14 | "superstatic": "^6.0.3", 15 | "vue": "^2.5.17", 16 | "vuex": "^2.5.0" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.1.2", 20 | "@babel/preset-env": "^7.1.0", 21 | "babel-loader": "^8.0.4", 22 | "cross-env": "^3.0.0", 23 | "css-loader": "^1.0.0", 24 | "file-loader": "^2.0.0", 25 | "html-webpack-plugin": "^3.2.0", 26 | "vue-loader": "^15.4.2", 27 | "vue-style-loader": "^4.1.2", 28 | "vue-template-compiler": "^2.5.17", 29 | "webpack": "^4.20.2", 30 | "webpack-cli": "^3.1.2", 31 | "webpack-dev-server": "^3.1.9" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /simple-todo/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 59 | -------------------------------------------------------------------------------- /simple-todo/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/simple-todo/src/assets/logo.png -------------------------------------------------------------------------------- /simple-todo/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import App from './App.vue' 4 | import store from '../store' 5 | 6 | new Vue({ 7 | el: '#app', 8 | store, 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /simple-todo/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | todos: [] 9 | }, 10 | mutations: { 11 | addTodo(state, text) { 12 | state.todos.push({ text }) 13 | }, 14 | removeTodo(state, todo) { 15 | state.todos.splice(state.todos.indexOf(todo), 1) 16 | } 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /simple-todo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /starter-files/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /starter-files/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /starter-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 10 | }, 11 | "dependencies": { 12 | "vue": "^2.5.17", 13 | "vuex": "^2.5.0" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.1.2", 17 | "@babel/preset-env": "^7.1.0", 18 | "babel-loader": "^8.0.4", 19 | "cross-env": "^3.0.0", 20 | "css-loader": "^1.0.0", 21 | "file-loader": "^2.0.0", 22 | "html-webpack-plugin": "^3.2.0", 23 | "vue-loader": "^15.4.2", 24 | "vue-style-loader": "^4.1.2", 25 | "vue-template-compiler": "^2.5.17", 26 | "webpack": "^4.20.2", 27 | "webpack-cli": "^3.1.2", 28 | "webpack-dev-server": "^3.1.9" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /starter-files/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 56 | -------------------------------------------------------------------------------- /starter-files/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/starter-files/src/assets/logo.png -------------------------------------------------------------------------------- /starter-files/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import App from './App.vue' 4 | import store from '../store' 5 | 6 | new Vue({ 7 | el: '#app', 8 | store, 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /starter-files/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | // 9 | }, 10 | mutations: { 11 | // 12 | }, 13 | actions: { 14 | // 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /starter-files/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | -------------------------------------------------------------------------------- /todo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /todo/README.md: -------------------------------------------------------------------------------- 1 | # Todo 2 | 3 | > A todo app implementation with Vuex 4 | -------------------------------------------------------------------------------- /todo/components/todo.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 72 | 73 | 97 | -------------------------------------------------------------------------------- /todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Todo - Vuex Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-examples", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "Ademola Adegbuyi ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 10 | "start": "superstatic /dist -p 3000 --host 0.0.0.0 --gzip -c '{\"rewrites\": [{\"source\":\"**\",\"destination\":\"index.html\"}],\"headers\":[{\"source\":\"**\",\"headers\":[{\"key\":\"Cache-Control\",\"value\":\"max-age=86400\"}]}]}'", 11 | "push-surge": "npm run -s build && surge ./ -d vuex-todo.surge.sh" 12 | }, 13 | "dependencies": { 14 | "superstatic": "^6.0.3", 15 | "vue": "^2.5.17", 16 | "vuex": "^2.5.0" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.1.2", 20 | "@babel/preset-env": "^7.1.0", 21 | "babel-loader": "^8.0.4", 22 | "cross-env": "^3.0.0", 23 | "css-loader": "^1.0.0", 24 | "file-loader": "^2.0.0", 25 | "html-webpack-plugin": "^3.2.0", 26 | "vue-loader": "^15.4.2", 27 | "vue-style-loader": "^4.1.2", 28 | "vue-template-compiler": "^2.5.17", 29 | "webpack": "^4.20.2", 30 | "webpack-cli": "^3.1.2", 31 | "webpack-dev-server": "^3.1.9" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /todo/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 59 | -------------------------------------------------------------------------------- /todo/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooade/vuex-examples/906af29fff752a8ab800f2a97ddcb5df0b95022b/todo/src/assets/logo.png -------------------------------------------------------------------------------- /todo/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import App from './App.vue' 4 | import store from '../store' 5 | 6 | new Vue({ 7 | el: '#app', 8 | store, 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /todo/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | todos: [] 9 | }, 10 | mutations: { 11 | addTodo({ todos }, text) { 12 | todos.push({ 13 | text, 14 | completed: false 15 | }) 16 | }, 17 | removeTodo: ({ todos }, todo) => { 18 | todos.splice(todos.indexOf(todo), 1) 19 | }, 20 | markTodo({ todos }, todo) { 21 | todos[todos.indexOf(todo)].completed = !todo.completed 22 | }, 23 | markAllTodo({ todos }, completed) { 24 | todos.forEach(todo => (todo.completed = completed)) 25 | }, 26 | clearCompleted({ todos }) { 27 | todos.map( 28 | todo => (todo.completed ? todos.splice(todos.indexOf(todo), 1) : null) 29 | ) 30 | } 31 | }, 32 | getters: { 33 | all: state => state.todos, 34 | completed: state => state.todos.filter(todo => todo.completed), 35 | pending: state => state.todos.filter(todo => !todo.completed) 36 | } 37 | }) 38 | -------------------------------------------------------------------------------- /todo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: './src/main.js', 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: '[name].bundle.js', 11 | chunkFilename: '[name].bundle.js' 12 | }, 13 | optimization: { 14 | splitChunks: { 15 | chunks: 'all' 16 | } 17 | }, 18 | mode: process.env.NODE_ENV, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader' 24 | }, 25 | { 26 | test: /\.js$/, 27 | loader: 'babel-loader', 28 | exclude: /node_modules/ 29 | }, 30 | { 31 | test: /\.css$/, 32 | use: ['vue-style-loader', 'css-loader'] 33 | }, 34 | { 35 | test: /\.(png|jpg|gif|svg)$/, 36 | loader: 'file-loader', 37 | options: { 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | resolve: { 44 | alias: { 45 | vue$: 'vue/dist/vue.esm.js' 46 | } 47 | }, 48 | devServer: { 49 | historyApiFallback: true, 50 | noInfo: true, 51 | hot: true 52 | }, 53 | performance: { 54 | hints: 'warning' 55 | }, 56 | plugins: [ 57 | new VueLoaderPlugin(), 58 | new HtmlWebpackPlugin({ 59 | template: path.join(__dirname, 'index.html') 60 | }) 61 | ], 62 | devtool: '#eval-source-map' 63 | }; 64 | 65 | if (process.env.NODE_ENV === 'production') { 66 | module.exports.devtool = '#source-map'; 67 | // http://vue-loader.vuejs.org/en/workflow/production.html 68 | module.exports.plugins = (module.exports.plugins || []).concat([ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: '"production"' 72 | } 73 | }), 74 | new webpack.LoaderOptionsPlugin({ 75 | minimize: true 76 | }) 77 | ]); 78 | } 79 | --------------------------------------------------------------------------------