├── .browserslistrc
├── public
├── robots.txt
├── favicon.ico
├── img
│ ├── bca.png
│ ├── mandiri.png
│ ├── unavailable.png
│ └── icons
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── mstile-150x150.png
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon-60x60.png
│ │ ├── apple-touch-icon-76x76.png
│ │ ├── apple-touch-icon-120x120.png
│ │ ├── apple-touch-icon-152x152.png
│ │ ├── apple-touch-icon-180x180.png
│ │ ├── msapplication-icon-144x144.png
│ │ └── safari-pinned-tab.svg
├── manifest.json
└── index.html
├── babel.config.js
├── tests
└── unit
│ ├── .eslintrc.js
│ └── example.spec.js
├── postcss.config.js
├── src
├── assets
│ ├── logo.png
│ └── logo.svg
├── plugins
│ ├── vuetify.js
│ ├── helper.js
│ └── axios.js
├── main.js
├── stores
│ ├── auth.js
│ ├── alert.js
│ ├── region.js
│ ├── dialog.js
│ └── cart.js
├── views
│ ├── Profile.vue
│ ├── About.vue
│ ├── Books.vue
│ ├── MyOrder.vue
│ ├── Categories.vue
│ ├── Category.vue
│ ├── Payment.vue
│ ├── Home.vue
│ ├── Book.vue
│ └── Checkout.vue
├── components
│ ├── BookItem.vue
│ ├── Alert.vue
│ ├── Search.vue
│ ├── Cart.vue
│ ├── HelloWorld.vue
│ ├── Login.vue
│ └── Register.vue
├── registerServiceWorker.js
├── store.js
├── router.js
└── App.vue
├── .env.development
├── .gitignore
├── .eslintrc.js
├── README.md
└── package.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | mocha: true
4 | }
5 | }
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/bca.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/bca.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/public/img/mandiri.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/mandiri.png
--------------------------------------------------------------------------------
/public/img/unavailable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/unavailable.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | VUE_APP_NAME=Vueshop
2 | VUE_APP_BACKEND_URL=http://larashop-api.test
3 | VUE_APP_API_URL=http://larashop-api.test
--------------------------------------------------------------------------------
/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laravel-vue-book/vueshop/HEAD/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/src/plugins/vuetify.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuetify from 'vuetify/lib';
3 |
4 | Vue.use(Vuetify);
5 |
6 | export default new Vuetify({
7 | icons: {
8 | iconfont: 'mdi',
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | /~
5 | package-lock.json*
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import './plugins/axios'
3 | import App from './App.vue'
4 | import router from './router'
5 | import store from './store'
6 | import './registerServiceWorker'
7 | import vuetify from './plugins/vuetify'
8 | import './plugins/helper'
9 |
10 | Vue.config.productionTip = false
11 |
12 | new Vue({
13 | router,
14 | store,
15 | vuetify,
16 | render: h => h(App)
17 | }).$mount('#app')
18 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | 'eslint:recommended'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 | parserOptions: {
15 | parser: 'babel-eslint'
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/unit/example.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { shallowMount } from '@vue/test-utils'
3 | import HelloWorld from '@/components/HelloWorld.vue'
4 |
5 | describe('HelloWorld.vue', () => {
6 | it('renders props.msg when passed', () => {
7 | const msg = 'new message'
8 | const wrapper = shallowMount(HelloWorld, {
9 | propsData: { msg }
10 | })
11 | expect(wrapper.text()).to.include(msg)
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/src/plugins/helper.js:
--------------------------------------------------------------------------------
1 | "use strict"
2 | import Vue from 'vue'
3 | const Helper = {
4 | install(Vue) {
5 | Vue.prototype.appName = process.env.VUE_APP_NAME
6 | Vue.prototype.getImage = function (image){
7 | if(image!=null && image.length>0 && image!=undefined){
8 | return process.env.VUE_APP_BACKEND_URL + "/images"+ image
9 | }
10 | return "/img/unavailable.png"
11 | }
12 | }
13 | }
14 |
15 | Vue.use(Helper)
--------------------------------------------------------------------------------
/src/stores/auth.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespaced: true,
3 | state: {
4 | user : {},
5 | },
6 | mutations: {
7 | set: (state, payload) => {
8 | state.user = payload
9 | },
10 | },
11 | actions: {
12 | set: ({commit}, payload) => {
13 | commit('set', payload)
14 | },
15 | },
16 | getters: {
17 | user : state => state.user,
18 | guest : state => Object.keys(state.user).length === 0,
19 | }
20 | }
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vueshop",
3 | "short_name": "vueshop",
4 | "icons": [
5 | {
6 | "src": "./img/icons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./img/icons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "start_url": "./index.html",
17 | "display": "standalone",
18 | "background_color": "#000000",
19 | "theme_color": "#4DBA87"
20 | }
21 |
--------------------------------------------------------------------------------
/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vueshop
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Run your unit tests
29 | ```
30 | npm run test:unit
31 | ```
32 |
33 | ### Customize configuration
34 | See [Configuration Reference](https://cli.vuejs.org/config/).
35 |
--------------------------------------------------------------------------------
/src/stores/alert.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespaced: true,
3 | state: {
4 | status : false,
5 | color : 'success', // warning, error
6 | text : ''
7 | },
8 | mutations: {
9 | set: (state, payload) => {
10 | state.status = payload.status
11 | state.text = payload.text
12 | state.color = payload.color
13 | },
14 | },
15 | actions: {
16 | set: ({commit}, payload) => {
17 | commit('set', payload)
18 | },
19 | },
20 | getters: {
21 | status : state => state.status,
22 | color : state => state.color,
23 | text : state => state.text
24 | }
25 | }
--------------------------------------------------------------------------------
/src/stores/region.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespaced: true,
3 | state: {
4 | provinces: [],
5 | cities: [],
6 | },
7 | mutations: {
8 | setProvinces: (state, value) => {
9 | state.provinces = value
10 | },
11 | setCities: (state, value) => {
12 | state.cities = value
13 | },
14 | },
15 | actions: {
16 | setProvinces: ({commit}, value) => {
17 | commit('setProvinces', value)
18 | },
19 | setCities: ({commit}, value) => {
20 | commit('setCities', value)
21 | },
22 | },
23 | getters: {
24 | provinces: state => state.provinces,
25 | cities: state => state.cities,
26 | }
27 | }
--------------------------------------------------------------------------------
/src/views/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Your Profile
4 |
5 |
6 |
7 |
8 |
9 | | {{ key }} |
10 | {{ value }} |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vueshop
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/BookItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
13 |
14 |
15 |
16 | mdi-cash
17 | Rp {{ book.price.toLocaleString('id-ID') }}
18 |
19 | mdi-eye {{ book.views }}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/stores/dialog.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespaced: true,
3 | state: {
4 | status : false,
5 | component : 'search', // search or login or other
6 | },
7 | mutations: {
8 | setStatus: (state, status) => {
9 | state.status = status
10 | },
11 | setComponent: (state, component) => {
12 | state.component = component
13 | },
14 | },
15 | actions: {
16 | setStatus: ({commit}, status) => {
17 | commit('setStatus', status)
18 | },
19 | setComponent: ({commit}, component) => {
20 | commit('setComponent', component)
21 | commit('setStatus', true)
22 | },
23 | },
24 | getters: {
25 | status : state => state.status,
26 | component : state => state.component,
27 | }
28 | }
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker'
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready () {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | )
12 | },
13 | registered () {
14 | console.log('Service worker has been registered.')
15 | },
16 | cached () {
17 | console.log('Content has been cached for offline use.')
18 | },
19 | updatefound () {
20 | console.log('New content is downloading.')
21 | },
22 | updated () {
23 | console.log('New content is available; please refresh.')
24 | },
25 | offline () {
26 | console.log('No internet connection found. App is running in offline mode.')
27 | },
28 | error (error) {
29 | console.error('Error during service worker registration:', error)
30 | }
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ text }}
4 |
5 | mdi-close-circle
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
7 |
8 |
9 | v-app
10 |
11 |
12 |
13 | | v-app-bar (Header) |
14 |
15 |
16 | |
17 | v-navigation-drawer (Side Menu)
18 | |
19 |
20 | v-content (Main Content)
21 | |
22 |
23 |
24 | | v-footer (Footer) |
25 |
26 |
27 |
28 | |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import cart from '@/stores/cart'
4 | import alert from '@/stores/alert'
5 | import auth from '@/stores/auth'
6 | import dialog from '@/stores/dialog'
7 | import region from '@/stores/region'
8 | import VuexPersist from 'vuex-persist'
9 |
10 | const vuexPersist = new VuexPersist({
11 | key: 'my-app',
12 | storage: localStorage
13 | })
14 |
15 | Vue.use(Vuex)
16 |
17 | export default new Vuex.Store({
18 | plugins: [vuexPersist.plugin],
19 | state: {
20 | prevUrl: '',
21 | payment: []
22 | },
23 | mutations: {
24 | setPrevUrl: (state, value) => {
25 | state.prevUrl = value
26 | },
27 | setPayment: (state, value) => {
28 | state.payment = value
29 | },
30 | },
31 | actions: {
32 | setPrevUrl: ({commit}, value) => {
33 | commit('setPrevUrl', value)
34 | },
35 | setPayment: ({commit}, value) => {
36 | commit('setPayment', value)
37 | },
38 | },
39 | getters: {
40 | prevUrl: state => state.prevUrl,
41 | payment: state => state.payment,
42 | },
43 | modules: {
44 | cart,
45 | alert,
46 | auth,
47 | dialog,
48 | region
49 | }
50 | })
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vueshop",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint",
9 | "test:unit": "vue-cli-service test:unit"
10 | },
11 | "dependencies": {
12 | "core-js": "^2.6.5",
13 | "register-service-worker": "^1.6.2",
14 | "vue": "^2.6.10",
15 | "vue-router": "^3.0.3",
16 | "vuetify": "^2.0.0",
17 | "vuex": "^3.0.1",
18 | "vuex-persist": "^2.0.1"
19 | },
20 | "devDependencies": {
21 | "@vue/cli-plugin-babel": "^3.9.0",
22 | "@vue/cli-plugin-eslint": "^3.9.0",
23 | "@vue/cli-plugin-pwa": "^3.9.0",
24 | "@vue/cli-plugin-unit-mocha": "^3.9.0",
25 | "@vue/cli-service": "^3.9.0",
26 | "@vue/test-utils": "1.0.0-beta.29",
27 | "axios": "^0.18.0",
28 | "babel-eslint": "^10.0.1",
29 | "chai": "^4.1.2",
30 | "eslint": "^5.16.0",
31 | "eslint-plugin-vue": "^5.0.0",
32 | "sass": "^1.17.4",
33 | "sass-loader": "^7.1.0",
34 | "stylus": "^0.54.5",
35 | "stylus-loader": "^3.0.2",
36 | "vue-cli-plugin-axios": "0.0.4",
37 | "vue-cli-plugin-vuetify": "^0.6.1",
38 | "vue-template-compiler": "^2.6.10",
39 | "vuetify-loader": "^1.2.2"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/views/Books.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | All Books
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
59 |
--------------------------------------------------------------------------------
/src/plugins/axios.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import Vue from 'vue';
4 | import axios from "axios";
5 |
6 | // Full config: https://github.com/axios/axios#request-config
7 | // axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
8 | // axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
9 | // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
10 |
11 | let config = {
12 | baseURL: process.env.VUE_APP_API_URL + '/v1',
13 | // baseURL: process.env.baseURL || process.env.apiUrl || ""
14 | // timeout: 60 * 1000, // Timeout
15 | // withCredentials: true, // Check cross-site Access-Control
16 | };
17 |
18 | const _axios = axios.create(config);
19 |
20 | _axios.interceptors.request.use(
21 | function(config) {
22 | // Do something before request is sent
23 | return config;
24 | },
25 | function(error) {
26 | // Do something with request error
27 | return Promise.reject(error);
28 | }
29 | );
30 |
31 | // Add a response interceptor
32 | _axios.interceptors.response.use(
33 | function(response) {
34 | // Do something with response data
35 | return response;
36 | },
37 | function(error) {
38 | // Do something with response error
39 | return Promise.reject(error);
40 | }
41 | );
42 |
43 | Plugin.install = function(Vue) {
44 | Vue.axios = _axios;
45 | window.axios = _axios;
46 | Object.defineProperties(Vue.prototype, {
47 | axios: {
48 | get() {
49 | return _axios;
50 | }
51 | },
52 | $axios: {
53 | get() {
54 | return _axios;
55 | }
56 | },
57 | });
58 | };
59 |
60 | Vue.use(Plugin)
61 |
62 | export default Plugin;
63 |
--------------------------------------------------------------------------------
/src/views/MyOrder.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Histori Belanja
4 |
5 |
6 |
7 |
8 |
9 | |
10 | Invoice: {{ item.invoice_number }}
11 | Rp. {{ item.total_bill.toLocaleString('id-ID') }}
12 | date: {{ item.updated_at }}. courier: {{ item.courier_service }}
13 | |
14 |
15 | {{ item.status }}
16 | |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/views/Categories.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | All Category
6 |
7 |
8 |
9 |
10 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
66 |
--------------------------------------------------------------------------------
/src/views/Category.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
12 |
13 |
14 |
15 |
16 |
17 | All Books
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
74 |
--------------------------------------------------------------------------------
/src/views/Payment.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Payment Information
4 |
5 |
6 |
7 | | Order ID | {{ payment.order_id }} |
8 | | Invoice Number | {{ payment.invoice_number }} |
9 | | Total Bill | Rp. {{ payment.total_bill.toLocaleString('id-ID') }} |
10 |
11 |
12 |
13 |
14 |
Transfer To
15 |
16 |
17 |
18 |
19 |  |
20 | BCA KCP abc No Rek 123 |
21 |
22 |
23 |  |
24 | BANK MANDIRI KCP xyz No Rek 456 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Finish
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | All Categories mdi-chevron-right
7 |
8 |
9 |
10 |
11 |
12 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | All Books mdi-chevron-right
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
73 |
--------------------------------------------------------------------------------
/src/components/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mdi-close
6 |
7 |
17 |
18 |
19 |
20 | Result search "{{ keyword }}"
21 |
22 |
23 |
27 | Sorry, but no results were found.
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/stores/cart.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespaced: true,
3 | state: {
4 | carts : [],
5 | },
6 | mutations: {
7 | insert: (state, payload) => {
8 | state.carts.push({
9 | id: payload.id,
10 | title: payload.title,
11 | cover: payload.cover,
12 | price: payload.price,
13 | weight: payload.weight,
14 | quantity: 1
15 | })
16 | },
17 | update: (state, payload) => {
18 | let idx = state.carts.indexOf(payload);
19 | state.carts.splice(idx,1,{
20 | id: payload.id,
21 | title: payload.title,
22 | cover: payload.cover,
23 | price: payload.price,
24 | weight: payload.weight,
25 | quantity: payload.quantity
26 | });
27 | if(payload.quantity<=0){
28 | state.carts.splice(idx,1)
29 | }
30 | },
31 | set: (state, payload) => {
32 | state.carts = payload
33 | },
34 | },
35 | actions: {
36 | add: ({state, commit}, payload) => {
37 | let cartItem = state.carts.find(item => item.id === payload.id)
38 | if(!cartItem){
39 | commit('insert', payload)
40 | }
41 | else{
42 | cartItem.quantity++
43 | commit('update', cartItem)
44 | }
45 | },
46 | remove: ({state, commit}, payload) => {
47 | let cartItem = state.carts.find(item => item.id === payload.id)
48 | if(cartItem){
49 | cartItem.quantity--
50 | commit('update', cartItem)
51 | }
52 | },
53 | set: ({commit}, payload) => {
54 | commit('set', payload)
55 | },
56 | },
57 | getters: {
58 | carts : state => state.carts,
59 | count : (state) => {
60 | return state.carts.length
61 | },
62 | totalPrice: (state) => {
63 | let total = 0
64 | state.carts.forEach(function(cart) {
65 | total += cart.price * cart.quantity
66 | })
67 | return total
68 | },
69 | totalQuantity: (state) => {
70 | let total = 0
71 | state.carts.forEach(function(cart) {
72 | total += cart.quantity
73 | })
74 | return total
75 | },
76 | totalWeight: (state) => {
77 | let total = 0
78 | state.carts.forEach(function(cart) {
79 | total += cart.weight
80 | })
81 | return total
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from './views/Home.vue'
4 | import store from './store'
5 |
6 | Vue.use(Router)
7 |
8 | //export default new Router({
9 | const router = new Router({
10 | mode: 'history',
11 | base: process.env.BASE_URL,
12 | routes: [
13 | {
14 | path: '/',
15 | name: 'home',
16 | component: Home
17 | },
18 | {
19 | path: '/about',
20 | name: 'about',
21 | // route level code-splitting
22 | // this generates a separate chunk (about.[hash].js) for this route
23 | // which is lazy-loaded when the route is visited.
24 | component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
25 | },
26 | {
27 | path: '/categories',
28 | name: 'categories',
29 | component: () => import( /* webpackChunkName: "categories" */ './views/Categories.vue')
30 | },
31 | {
32 | path: '/books',
33 | name: 'books',
34 | component: () => import( /* webpackChunkName: "books" */ './views/Books.vue')
35 | },
36 | {
37 | path: '/category/:slug',
38 | name: 'category',
39 | component: () => import( /* webpackChunkName: "category" */ './views/Category.vue')
40 | },
41 | {
42 | path: '/book/:slug',
43 | name: 'book',
44 | component: () => import( /* webpackChunkName: "book" */ './views/Book.vue')
45 | },
46 | {
47 | path: '/checkout',
48 | name: 'checkout',
49 | component: () => import( /* webpackChunkName: "checkout" */ './views/Checkout.vue'),
50 | meta: { auth: true }
51 | },
52 | {
53 | path: '/payment',
54 | name: 'payment',
55 | component: () => import( /* webpackChunkName: "payment" */ './views/Payment.vue'),
56 | meta: { auth: true }
57 | },
58 | {
59 | path: '/profile',
60 | name: 'profile',
61 | component: () => import( /* webpackChunkName: "profile" */ './views/Profile.vue'),
62 | meta: { auth: true }
63 | },
64 | {
65 | path: '/my-order',
66 | name: 'my-order',
67 | component: () => import( /* webpackChunkName: "my-order" */ './views/MyOrder.vue'),
68 | meta: { auth: true }
69 | },
70 | ]
71 | })
72 |
73 | router.beforeEach((to, from, next) => {
74 | // jika routing ada meta auth-nya maka
75 | if (to.matched.some(record => record.meta.auth)) {
76 | // jika user adalah guest
77 | if(store.getters['auth/guest']){
78 | // tampilkan pesan bahwa harus login dulu
79 | store.dispatch('alert/set', {
80 | status : true,
81 | text : 'Login first',
82 | color : 'error',
83 | })
84 | store.dispatch('setPrevUrl', to.path)
85 | // tampilkan form login
86 | store.dispatch('dialog/setComponent', 'login')
87 | }
88 | else{
89 | next()
90 | }
91 | }
92 | else{
93 | next()
94 | }
95 | })
96 |
97 | export default router;
--------------------------------------------------------------------------------
/src/views/Book.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | | mdi-account-tie Author |
20 | {{ book.author}} |
21 |
22 |
23 | | mdi-bullhorn Publisher |
24 | {{ book.publisher}} |
25 |
26 |
27 | | mdi-weight Weight |
28 | {{ book.weight }} kg |
29 |
30 |
31 | | mdi-format-list-bulleted Stock |
32 | {{ book.stock}} item |
33 |
34 |
35 | | mdi-eye Views |
36 | {{ book.views}} |
37 |
38 |
39 | | mdi-cash Price |
40 | Rp {{ book.price.toLocaleString('id-ID')}} |
41 |
42 |
43 |
44 | Description:
45 | {{ book.description }}
46 |
47 | Categories:
48 |
49 | {{ category.name }}
50 |
51 |
52 |
53 |
54 | mdi-cart-plus
55 | BUY
56 |
57 |
58 |
59 |
60 |
61 |
107 |
--------------------------------------------------------------------------------
/src/components/Cart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mdi-close
6 |
7 | Your Shopping Cart!
8 |
9 |
10 |
11 |
12 |
17 | Keranjang belanja kosong!
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Rp. {{ item.price.toLocaleString('id-ID') }}
33 | ({{ item.weight }} kg)
34 |
35 |
36 | mdi-minus-circle
37 |
38 | {{ item.quantity }}
39 |
40 | mdi-plus-circle
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Total Price ({{ totalQuantity }} items)
53 | Rp. {{ totalPrice.toLocaleString('id-ID') }}
54 |
55 |
56 |
57 | mdi-cart-arrow-right
58 | Checkout
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
14 |
15 |
16 |
17 |
18 | Welcome to Vuetify
19 |
20 |
21 | For help and collaboration with other Vuetify developers,
22 |
please join our online
23 | Discord Community
24 |
25 |
26 |
27 |
31 | What's next?
32 |
33 |
34 |
41 | {{ next.text }}
42 |
43 |
44 |
45 |
46 |
50 | Important Links
51 |
52 |
53 |
60 | {{ link.text }}
61 |
62 |
63 |
64 |
65 |
69 | Ecosystem
70 |
71 |
72 |
79 | {{ eco.text }}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
143 |
--------------------------------------------------------------------------------
/src/components/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mdi-close
6 |
7 | Login and Start Shopping!
8 |
9 |
10 |
11 |
12 |
19 |
29 |
30 |
31 |
36 | Login
37 | mdi-lock-open
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/components/Register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mdi-close
6 |
7 | Register!
8 |
9 |
10 |
11 |
12 |
13 |
21 |
28 |
38 |
44 |
45 |
50 | Register
51 | mdi-account-plus
52 |
53 |
54 | Reset
55 | mdi-lock-reset
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | {{ appName }}
10 |
11 |
12 |
13 |
14 | {{ countCart }}
15 |
16 | mdi-cart
17 |
18 |
19 |
28 |
29 |
30 |
31 | mdi-arrow-left-circle
32 |
33 |
34 |
35 |
36 |
37 | {{ countCart }}
38 |
39 | mdi-cart
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | mdi-lock
50 | Login
51 |
52 |
53 | mdi-account
54 | Register
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | {{ user.name }}
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
77 | {{ item.icon }}
78 |
79 | {{ item.title }}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | mdi-lock
89 | Logout
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | © {{ new Date().getFullYear() }} — Vueshop
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
150 |
--------------------------------------------------------------------------------
/src/views/Checkout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Shipping Address
4 |
5 |
6 |
7 |
8 |
14 |
15 |
22 |
23 |
29 |
30 |
39 |
40 |
50 |
51 |
52 |
53 |
54 | mdi-content-save
55 | Save
56 |
57 |
58 |
59 |
60 |
61 |
62 |
Your Shopping Cart
63 |
64 |
65 |
66 |
67 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Rp. {{ item.price.toLocaleString('id-ID') }}
78 | ({{ item.weight }} kg)
79 |
80 | {{ item.quantity }}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | Subtotal
90 |
91 | Rp. {{ totalPrice.toLocaleString('id-ID') }}
92 |
93 |
94 |
95 |
96 |
97 |
Courier
98 |
99 |
100 |
101 |
111 |
112 |
123 |
124 |
125 | Subtotal
126 |
127 | Rp. {{ shippingCost.toLocaleString('id-ID') }}
128 |
129 |
130 |
131 |
132 |
133 |
Total
134 |
135 |
136 |
137 |
138 | Total Bill ({{ totalQuantity }} items)
139 | {{ totalBill.toLocaleString('id-ID') }}
140 |
141 |
142 |
143 | mdi-cash
144 | Pay
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | Confirmation!
156 | If You continue, transaction will be processed
157 |
158 | Cancel
159 |
160 | Continue
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------