├── .gitignore ├── README.md ├── babel.config.js ├── custom.scss ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── Pages │ ├── Home.vue │ ├── ProductDetailPage.vue │ └── ShoppingCartPage.vue ├── assets │ ├── logo.png │ └── ss1.png ├── components │ ├── HelloWorld.vue │ ├── core │ │ ├── Footer.vue │ │ ├── Header.vue │ │ ├── LayoutMode.vue │ │ └── PageNotFound.vue │ ├── filters │ │ ├── BrandFilter.vue │ │ └── PriceFilter.vue │ ├── pagination │ │ └── Pagination.vue │ ├── products │ │ ├── Product.vue │ │ ├── ProductDetail.vue │ │ ├── ProductList.vue │ │ ├── ProductSlider.vue │ │ └── ProductSliderDots.vue │ └── shopping-cart │ │ ├── ShoppingCartContainer.vue │ │ └── ShoppingCartItem.vue ├── data │ ├── brands.js │ └── phones.js ├── filters │ ├── brandFilter.js │ ├── orderByFilter.js │ ├── paginationFilter.js │ ├── priceFormatter.js │ └── shortenTitle.js ├── main.js ├── store │ ├── index.js │ └── types.js └── utilities │ └── cumulativeOffset.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Here is the live demo CLICK TO SEE DEMO 2 | 3 | ![alt-text](https://github.com/TheCodersDream/React-Ecommerce-App-with-Redux/blob/master/ecm1-1.png) 4 | ![alt-text](https://github.com/TheCodersDream/React-Ecommerce-App-with-Redux/blob/master/ecm2-2.png) 5 | ![alt-text](https://github.com/TheCodersDream/React-Ecommerce-App-with-Redux/blob/master/ecm3.png) 6 | ![alt-text](https://github.com/TheCodersDream/React-Ecommerce-App-with-Redux/blob/master/ecm4.png) 7 | ![alt-text](https://github.com/TheCodersDream/React-Ecommerce-App-with-Redux/blob/master/ecm5.png) 8 | ![alt-text](./src/assets/ss1.png) 9 | 10 | 11 | # ecomerce 12 | 13 | ## Project setup 14 | ``` 15 | yarn install 16 | ``` 17 | 18 | ### Compiles and hot-reloads for development 19 | ``` 20 | yarn run serve 21 | ``` 22 | 23 | ### Compiles and minifies for production 24 | ``` 25 | yarn run build 26 | ``` 27 | 28 | ### Run your tests 29 | ``` 30 | yarn run test 31 | ``` 32 | 33 | ### Lints and fixes files 34 | ``` 35 | yarn run lint 36 | ``` 37 | 38 | ### Customize configuration 39 | See [Configuration Reference](https://cli.vuejs.org/config/). 40 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /custom.scss: -------------------------------------------------------------------------------- 1 | @import 'node_modules/bootstrap/scss/bootstrap'; 2 | @import 'node_modules/bootstrap-vue/src/index.scss'; 3 | 4 | 5 | html{ height:100%; } 6 | body{ min-height:100%; padding:0; margin:0; position:relative; } 7 | 8 | body::after{ content:''; display:block; height:100px; } 9 | 10 | footer{ 11 | position:absolute; 12 | bottom:0; 13 | width:100%; 14 | height:100px; 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ecomerce", 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 | }, 10 | "dependencies": { 11 | "bootstrap": "^4.3.1", 12 | "bootstrap-vue": "^2.0.0-rc.15", 13 | "vue": "^2.6.10", 14 | "vue-fragment": "latest", 15 | "vue-router": "^3.0.2", 16 | "vue-swal": "^1.0.0", 17 | "vuex": "^2.3.1" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "^3.5.0", 21 | "@vue/cli-plugin-eslint": "^3.5.0", 22 | "@vue/cli-service": "^3.5.0", 23 | "babel-eslint": "^10.0.1", 24 | "eslint": "^5.8.0", 25 | "eslint-plugin-vue": "^5.0.0", 26 | "node-sass": "^4.11.0", 27 | "sass-loader": "^7.1.0", 28 | "vue-template-compiler": "^2.5.21" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/essential", 37 | "eslint:recommended" 38 | ], 39 | "rules": {}, 40 | "parserOptions": { 41 | "parser": "babel-eslint" 42 | } 43 | }, 44 | "postcss": { 45 | "plugins": { 46 | "autoprefixer": {} 47 | } 48 | }, 49 | "browserslist": [ 50 | "> 1%", 51 | "last 2 versions", 52 | "not ie <= 8" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCoderDream/Vue-Ecommerce-App-with-Vuex/b44cac2b364c861c8dfc65a538e7c95004d17173/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ecomerce 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 49 | 50 | 90 | -------------------------------------------------------------------------------- /src/Pages/Home.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /src/Pages/ProductDetailPage.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /src/Pages/ShoppingCartPage.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCoderDream/Vue-Ecommerce-App-with-Vuex/b44cac2b364c861c8dfc65a538e7c95004d17173/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/ss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCoderDream/Vue-Ecommerce-App-with-Vuex/b44cac2b364c861c8dfc65a538e7c95004d17173/src/assets/ss1.png -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /src/components/core/Footer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /src/components/core/Header.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/components/core/LayoutMode.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 56 | -------------------------------------------------------------------------------- /src/components/core/PageNotFound.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/filters/BrandFilter.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 45 | 46 | 108 | -------------------------------------------------------------------------------- /src/components/filters/PriceFilter.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 69 | 70 | 128 | -------------------------------------------------------------------------------- /src/components/pagination/Pagination.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 96 | 97 | 100 | -------------------------------------------------------------------------------- /src/components/products/Product.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 105 | 106 | 181 | -------------------------------------------------------------------------------- /src/components/products/ProductDetail.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 67 | 68 | 71 | -------------------------------------------------------------------------------- /src/components/products/ProductList.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 64 | 65 | 68 | -------------------------------------------------------------------------------- /src/components/products/ProductSlider.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 69 | -------------------------------------------------------------------------------- /src/components/products/ProductSliderDots.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | 33 | 68 | -------------------------------------------------------------------------------- /src/components/shopping-cart/ShoppingCartContainer.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /src/components/shopping-cart/ShoppingCartItem.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 71 | 72 | 157 | -------------------------------------------------------------------------------- /src/data/brands.js: -------------------------------------------------------------------------------- 1 | export const brands = ["apple","huawei","meizu","samsung","vestel","xiaomi","asus"]; 2 | -------------------------------------------------------------------------------- /src/data/phones.js: -------------------------------------------------------------------------------- 1 | export const phones = [{ 2 | title: 'Apple iPhone 7 Plus 32 GB (Apple Türkiye Garantili)', 3 | category: 'phone', 4 | images: ['https://productimages.hepsiburada.net/s/18/280-413/9801258663986.jpg?v1', 'https://productimages.hepsiburada.net/s/18/280-413/9801258696754.jpg?v1', 'https://productimages.hepsiburada.net/s/18/280-413/9801258729522.jpg?v1', 'https://productimages.hepsiburada.net/s/18/280-413/9801258762290.jpg?v1'], 5 | brand: 'apple', 6 | price: 4241.499828399639, 7 | cpu: '1.3GHz Apple A6', 8 | camera: '8mp (3264x2448)', 9 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 10 | weight: '132 grams (4.7 ounces) with battery', 11 | display: '4.0 326 pixel density', 12 | battery: '1480 mAh', 13 | memory: '16GB, 32GB and RAM 1 GB', 14 | id: 0, 15 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 16 | }, { 17 | title: 'Huawei Mate 20 Lite 64 GB (Huawei Türkiye Garantili)', 18 | category: 'phone', 19 | images: ['https://productimages.hepsiburada.net/s/21/280-413/9933217792050.jpg?v1', 'https://productimages.hepsiburada.net/s/21/280-413/9933217628210.jpg?v1', 'https://productimages.hepsiburada.net/s/21/280-413/9933217660978.jpg?v1', 'https://productimages.hepsiburada.net/s/21/280-413/9933217693746.jpg?v1'], 20 | brand: 'huawei', 21 | price: 1823.6625483451157, 22 | cpu: '1.3GHz Apple A6', 23 | camera: '8mp (3264x2448)', 24 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 25 | weight: '132 grams (4.7 ounces) with battery', 26 | display: '4.0 326 pixel density', 27 | battery: '1480 mAh', 28 | memory: '16GB, 32GB and RAM 1 GB', 29 | id: 1, 30 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 31 | }, { 32 | title: 'Huawei P20 Lite 64 GB (Huawei Türkiye Garantili)', 33 | category: 'phone', 34 | images: ['https://productimages.hepsiburada.net/s/19/280-413/9826975907890.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9826975940658.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9826975973426.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9826976006194.jpg?v1'], 35 | brand: 'huawei', 36 | price: 7429.467511354926, 37 | cpu: '1.3GHz Apple A6', 38 | camera: '8mp (3264x2448)', 39 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 40 | weight: '132 grams (4.7 ounces) with battery', 41 | display: '4.0 326 pixel density', 42 | battery: '1480 mAh', 43 | memory: '16GB, 32GB and RAM 1 GB', 44 | id: 2, 45 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 46 | }, { 47 | title: 'Meizu 16TH 64 GB (Meizu Türkiye Garantili)', 48 | category: 'phone', 49 | images: ['https://productimages.hepsiburada.net/s/24/280-413/10094991409202.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10094991441970.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10094991474738.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10094991507506.jpg?v1'], 50 | brand: 'meizu', 51 | price: 5664.265944453384, 52 | cpu: '1.3GHz Apple A6', 53 | camera: '8mp (3264x2448)', 54 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 55 | weight: '132 grams (4.7 ounces) with battery', 56 | display: '4.0 326 pixel density', 57 | battery: '1480 mAh', 58 | memory: '16GB, 32GB and RAM 1 GB', 59 | id: 3, 60 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 61 | }, { 62 | title: 'Meizu X8 64 GB (Meizu Türkiye Garantili)', 63 | category: 'phone', 64 | images: ['https://productimages.hepsiburada.net/s/25/280-413/10108030091314.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082391818290.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082391851058.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082391883826.jpg?v1'], 65 | brand: 'meizu', 66 | price: 4596.99884783711, 67 | cpu: '1.3GHz Apple A6', 68 | camera: '8mp (3264x2448)', 69 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 70 | weight: '132 grams (4.7 ounces) with battery', 71 | display: '4.0 326 pixel density', 72 | battery: '1480 mAh', 73 | memory: '16GB, 32GB and RAM 1 GB', 74 | id: 4, 75 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 76 | }, { 77 | title: 'Samsung Galaxy A7 2018 64 GB (Samsung Türkiye Garantili)', 78 | category: 'phone', 79 | images: ['https://productimages.hepsiburada.net/s/22/280-413/9946187399218.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9946187431986.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9946187464754.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9946187497522.jpg?v1'], 80 | brand: 'samsung', 81 | price: 4108.082941215698, 82 | cpu: '1.3GHz Apple A6', 83 | camera: '8mp (3264x2448)', 84 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 85 | weight: '132 grams (4.7 ounces) with battery', 86 | display: '4.0 326 pixel density', 87 | battery: '1480 mAh', 88 | memory: '16GB, 32GB and RAM 1 GB', 89 | id: 5, 90 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 91 | }, { 92 | title: 'Samsung Galaxy J6 Plus 32 GB (Samsung Türkiye Garantili)', 93 | category: 'phone', 94 | images: ['https://productimages.hepsiburada.net/s/22/280-413/9941129494578.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9941129527346.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9941129560114.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9941129592882.jpg?v1'], 95 | brand: 'samsung', 96 | price: 4260.9529075338505, 97 | cpu: '1.3GHz Apple A6', 98 | camera: '8mp (3264x2448)', 99 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 100 | weight: '132 grams (4.7 ounces) with battery', 101 | display: '4.0 326 pixel density', 102 | battery: '1480 mAh', 103 | memory: '16GB, 32GB and RAM 1 GB', 104 | id: 6, 105 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 106 | }, { 107 | title: 'Vestel Venus Z20 (Vestel Garantili)', 108 | category: 'phone', 109 | images: ['https://productimages.hepsiburada.net/s/19/280-413/9841497047090.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9841497079858.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9841497112626.jpg?v1', 'https://productimages.hepsiburada.net/s/19/280-413/9841497145394.jpg?v1'], 110 | brand: 'vestel', 111 | price: 4730.962860489047, 112 | cpu: '1.3GHz Apple A6', 113 | camera: '8mp (3264x2448)', 114 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 115 | weight: '132 grams (4.7 ounces) with battery', 116 | display: '4.0 326 pixel density', 117 | battery: '1480 mAh', 118 | memory: '16GB, 32GB and RAM 1 GB', 119 | id: 7, 120 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 121 | }, { 122 | title: 'Xiaomi Mi 8 Lite 128 GB (İthalatçı Garantili)', 123 | category: 'phone', 124 | images: ['https://productimages.hepsiburada.net/s/22/280-413/9957349523506.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9957349556274.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9957349589042.jpg?v1', 'https://productimages.hepsiburada.net/s/22/280-413/9957349621810.jpg?v1'], 125 | brand: 'xiaomi', 126 | price: 5565.737301732921, 127 | cpu: '1.3GHz Apple A6', 128 | camera: '8mp (3264x2448)', 129 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 130 | weight: '132 grams (4.7 ounces) with battery', 131 | display: '4.0 326 pixel density', 132 | battery: '1480 mAh', 133 | memory: '16GB, 32GB and RAM 1 GB', 134 | id: 8, 135 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 136 | }, { 137 | title: 'Xiaomi Mi 8 Lite 64 GB (İthalatçı Garantili)', 138 | category: 'phone', 139 | images: ['https://productimages.hepsiburada.net/s/23/280-413/10051147202610.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10051147235378.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10051147268146.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10051147300914.jpg?v1'], 140 | brand: 'xiaomi', 141 | price: 5830.067673371856, 142 | cpu: '1.3GHz Apple A6', 143 | camera: '8mp (3264x2448)', 144 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 145 | weight: '132 grams (4.7 ounces) with battery', 146 | display: '4.0 326 pixel density', 147 | battery: '1480 mAh', 148 | memory: '16GB, 32GB and RAM 1 GB', 149 | id: 9, 150 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 151 | }, { 152 | title: 'Apple iPhone 7 32 GB (Apple Türkiye Garantili)', 153 | category: 'phone', 154 | images: ['https://productimages.hepsiburada.net/s/1/280-413/9502147641394.jpg?v1', 'https://productimages.hepsiburada.net/s/1/280-413/9502147674162.jpg?v1', 'https://productimages.hepsiburada.net/s/1/280-413/9502147706930.jpg?v1', 'https://productimages.hepsiburada.net/s/1/280-413/9502147739698.jpg?v1'], 155 | brand: 'apple', 156 | price: 1525.6236967422828, 157 | cpu: '1.3GHz Apple A6', 158 | camera: '8mp (3264x2448)', 159 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 160 | weight: '132 grams (4.7 ounces) with battery', 161 | display: '4.0 326 pixel density', 162 | battery: '1480 mAh', 163 | memory: '16GB, 32GB and RAM 1 GB', 164 | id: 10, 165 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 166 | }, { 167 | title: 'Samsung Galaxy S10 Plus 128 GB (Samsung Türkiye Garantili)', 168 | category: 'phone', 169 | images: ['https://productimages.hepsiburada.net/s/25/280-413/10107992703026.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107992735794.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107992768562.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107992801330.jpg?v1'], 170 | brand: 'samsung', 171 | price: 3429.3471420603028, 172 | cpu: '1.3GHz Apple A6', 173 | camera: '8mp (3264x2448)', 174 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 175 | weight: '132 grams (4.7 ounces) with battery', 176 | display: '4.0 326 pixel density', 177 | battery: '1480 mAh', 178 | memory: '16GB, 32GB and RAM 1 GB', 179 | id: 11, 180 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 181 | }, { 182 | title: 'Samsung Galaxy S10 128 GB (Samsung Türkiye Garantili)', 183 | category: 'phone', 184 | images: ['https://productimages.hepsiburada.net/s/25/280-413/10107307425842.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307458610.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307491378.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307524146.jpg?v1'], 185 | brand: 'samsung', 186 | price: 1017.7877018963508, 187 | cpu: '1.3GHz Apple A6', 188 | camera: '8mp (3264x2448)', 189 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 190 | weight: '132 grams (4.7 ounces) with battery', 191 | display: '4.0 326 pixel density', 192 | battery: '1480 mAh', 193 | memory: '16GB, 32GB and RAM 1 GB', 194 | id: 12, 195 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 196 | }, { 197 | title: 'Samsung Galaxy S10e 128 GB (Samsung Türkiye Garantili)', 198 | category: 'phone', 199 | images: ['https://productimages.hepsiburada.net/s/25/280-413/10107307032626.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307065394.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307098162.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10107307130930.jpg?v1'], 200 | brand: 'samsung', 201 | price: 3235.202225041739, 202 | cpu: '1.3GHz Apple A6', 203 | camera: '8mp (3264x2448)', 204 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 205 | weight: '132 grams (4.7 ounces) with battery', 206 | display: '4.0 326 pixel density', 207 | battery: '1480 mAh', 208 | memory: '16GB, 32GB and RAM 1 GB', 209 | id: 13, 210 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 211 | }, { 212 | title: 'Samsung Galaxy M20 32 GB (Samsung Türkiye Garantili)', 213 | category: 'phone', 214 | images: ['https://productimages.hepsiburada.net/s/25/280-413/10094999240754.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10094999273522.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10094999306290.jpg?v1', 'https://productimages.hepsiburada.net/s/25/280-413/10094999339058.jpg?v1'], 215 | brand: 'samsung', 216 | price: 5850.5748675199875, 217 | cpu: '1.3GHz Apple A6', 218 | camera: '8mp (3264x2448)', 219 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 220 | weight: '132 grams (4.7 ounces) with battery', 221 | display: '4.0 326 pixel density', 222 | battery: '1480 mAh', 223 | memory: '16GB, 32GB and RAM 1 GB', 224 | id: 14, 225 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 226 | }, { 227 | title: 'Samsung Galaxy S8 (Samsung Türkiye Garantili)', 228 | category: 'phone', 229 | images: ['https://productimages.hepsiburada.net/s/3/280-413/9604775739442.jpg?v1', 'https://productimages.hepsiburada.net/s/4/280-413/9665566703666.jpg?v1', 'https://productimages.hepsiburada.net/s/4/280-413/9665566736434.jpg?v1', 'https://productimages.hepsiburada.net/s/4/280-413/9665566769202.jpg?v1'], 230 | brand: 'samsung', 231 | price: 3207.2840718201587, 232 | cpu: '1.3GHz Apple A6', 233 | camera: '8mp (3264x2448)', 234 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 235 | weight: '132 grams (4.7 ounces) with battery', 236 | display: '4.0 326 pixel density', 237 | battery: '1480 mAh', 238 | memory: '16GB, 32GB and RAM 1 GB', 239 | id: 15, 240 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 241 | }, { 242 | title: 'Huawei P Smart 2019 64 GB (Huawei Türkiye Garantili)', 243 | category: 'phone', 244 | images: ['https://productimages.hepsiburada.net/s/23/280-413/10059934859314.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10059934892082.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10059934924850.jpg?v1', 'https://productimages.hepsiburada.net/s/23/280-413/10059934957618.jpg?v1'], 245 | brand: 'huawei', 246 | price: 5288.552334214134, 247 | cpu: '1.3GHz Apple A6', 248 | camera: '8mp (3264x2448)', 249 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 250 | weight: '132 grams (4.7 ounces) with battery', 251 | display: '4.0 326 pixel density', 252 | battery: '1480 mAh', 253 | memory: '16GB, 32GB and RAM 1 GB', 254 | id: 16, 255 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 256 | }, { 257 | title: 'Xiaomi Mi 8 128 GB (İthalatçı Garantili)', 258 | category: 'phone', 259 | images: ['https://productimages.hepsiburada.net/s/20/280-413/9873948540978.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9873948573746.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9873948606514.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9873948639282.jpg?v1'], 260 | brand: 'xiaomi', 261 | price: 1354.662450097338, 262 | cpu: '1.3GHz Apple A6', 263 | camera: '8mp (3264x2448)', 264 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 265 | weight: '132 grams (4.7 ounces) with battery', 266 | display: '4.0 326 pixel density', 267 | battery: '1480 mAh', 268 | memory: '16GB, 32GB and RAM 1 GB', 269 | id: 17, 270 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 271 | }, { 272 | title: 'Apple iPhone 6S Plus 32 GB (Apple Türkiye Garantili)', 273 | category: 'phone', 274 | images: ['https://productimages.hepsiburada.net/s/1/280-413/9489589993522.jpg?v1', 'https://productimages.hepsiburada.net/s/1/280-413/9489589927986.jpg?v1', 'https://productimages.hepsiburada.net/s/1/280-413/9489589960754.jpg?v1'], 275 | brand: 'apple', 276 | price: 5467.082548922358, 277 | cpu: '1.3GHz Apple A6', 278 | camera: '8mp (3264x2448)', 279 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 280 | weight: '132 grams (4.7 ounces) with battery', 281 | display: '4.0 326 pixel density', 282 | battery: '1480 mAh', 283 | memory: '16GB, 32GB and RAM 1 GB', 284 | id: 18, 285 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 286 | }, { 287 | title: 'Meizu 16 64 GB (Meizu Türkiye Garantili)', 288 | category: 'phone', 289 | images: ['https://productimages.hepsiburada.net/s/24/280-413/10082399387698.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082399420466.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082399453234.jpg?v1', 'https://productimages.hepsiburada.net/s/24/280-413/10082399486002.jpg?v1'], 290 | brand: 'meizu', 291 | price: 1173.3514841571446, 292 | cpu: '1.3GHz Apple A6', 293 | camera: '8mp (3264x2448)', 294 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 295 | weight: '132 grams (4.7 ounces) with battery', 296 | display: '4.0 326 pixel density', 297 | battery: '1480 mAh', 298 | memory: '16GB, 32GB and RAM 1 GB', 299 | id: 19, 300 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 301 | }, { 302 | title: 'Vestel Venüs E3 (Vestel Türkiye Garantili)', 303 | category: 'phone', 304 | images: ['https://productimages.hepsiburada.net/s/20/280-413/9885707108402.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9885707141170.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9885707173938.jpg?v1'], 305 | brand: 'vestel', 306 | price: 2371.8351283872053, 307 | cpu: '1.3GHz Apple A6', 308 | camera: '8mp (3264x2448)', 309 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 310 | weight: '132 grams (4.7 ounces) with battery', 311 | display: '4.0 326 pixel density', 312 | battery: '1480 mAh', 313 | memory: '16GB, 32GB and RAM 1 GB', 314 | id: 20, 315 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 316 | }, { 317 | title: 'Asus Zenfone Max Pro ZB602KL 64 GB (Asus Türkiye Garantili)', 318 | category: 'phone', 319 | images: ['https://productimages.hepsiburada.net/s/21/280-413/9924255121458.jpg?v1', 'https://productimages.hepsiburada.net/s/21/280-413/9924255154226.jpg?v1', 'https://productimages.hepsiburada.net/s/21/280-413/9924255186994.jpg?v1'], 320 | brand: 'asus', 321 | price: 2603.504706144322, 322 | cpu: '1.3GHz Apple A6', 323 | camera: '8mp (3264x2448)', 324 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 325 | weight: '132 grams (4.7 ounces) with battery', 326 | display: '4.0 326 pixel density', 327 | battery: '1480 mAh', 328 | memory: '16GB, 32GB and RAM 1 GB', 329 | id: 21, 330 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 331 | }, { 332 | title: 'Samsung Galaxy Note 9 128 GB (Samsung Türkiye Garantili)', 333 | category: 'phone', 334 | images: ['https://productimages.hepsiburada.net/s/20/280-413/9902572142642.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9902572175410.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9902572208178.jpg?v1', 'https://productimages.hepsiburada.net/s/20/280-413/9902572240946.jpg?v1'], 335 | brand: 'samsung', 336 | price: 1165.0255199945123, 337 | cpu: '1.3GHz Apple A6', 338 | camera: '8mp (3264x2448)', 339 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 340 | weight: '132 grams (4.7 ounces) with battery', 341 | display: '4.0 326 pixel density', 342 | battery: '1480 mAh', 343 | memory: '16GB, 32GB and RAM 1 GB', 344 | id: 22, 345 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 346 | }, { 347 | title: 'Huawei Mate 20 Lite Dual Sim 64 GB (İthalatçı Garantili)', 348 | category: 'phone', 349 | images: ['https://productimages.hepsiburada.net/s/21/280-413/9933217792050.jpg?v1', 350 | 'https://productimages.hepsiburada.net/s/21/280-413/9933217660978.jpg?v1', 351 | 'https://productimages.hepsiburada.net/s/21/280-413/9933217693746.jpg?v1', 352 | 'https://productimages.hepsiburada.net/s/21/280-413/9933217726514.jpg?v1'], 353 | brand: 'huawei', 354 | price: 2693.4407990587074, 355 | cpu: '1.3GHz Apple A6', 356 | camera: '8mp (3264x2448)', 357 | size: '124.4mm x 59.2mm x 8.97mm (4.9 x 2.33 x 0.35)', 358 | weight: '132 grams (4.7 ounces) with battery', 359 | display: '4.0 326 pixel density', 360 | battery: '1480 mAh', 361 | memory: '16GB, 32GB and RAM 1 GB', 362 | id: 23, 363 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet numquam aspernatur!' 364 | }]; 365 | 366 | -------------------------------------------------------------------------------- /src/filters/brandFilter.js: -------------------------------------------------------------------------------- 1 | export const brandFilter = (arr, brand) => { 2 | if(!brand) return arr; 3 | 4 | return arr.filter(product => brand.includes(product.brand)); 5 | }; -------------------------------------------------------------------------------- /src/filters/orderByFilter.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const orderByFilter = (arr, type ) => { 4 | if(!type) return arr; 5 | if(type === 'asc') { 6 | return arr.slice().sort((el1, el2) => el1.price - el2.price); 7 | } else { 8 | return arr.slice().sort((el1, el2) => el2.price - el1.price); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/filters/paginationFilter.js: -------------------------------------------------------------------------------- 1 | export const paginationPipe = (state,args) => { 2 | if (!args || !args.perPage || !args.currentPage) { 3 | return state; 4 | } 5 | const location = (args.perPage * (args.currentPage - 1)) || 0 ; 6 | 7 | return state.slice(location, location + args.perPage); 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /src/filters/priceFormatter.js: -------------------------------------------------------------------------------- 1 | export const formatMoney = (price) => { 2 | return price.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'); 3 | }; -------------------------------------------------------------------------------- /src/filters/shortenTitle.js: -------------------------------------------------------------------------------- 1 | export const shortenTitle = (title) => { 2 | return title.split(' (')[0]; 3 | }; -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import App from './App.vue' 4 | import '../custom.scss' 5 | 6 | Vue.config.devtools = true; 7 | import store from './store'; 8 | import {Plugin} from 'vue-fragment' 9 | import VueSwal from 'vue-swal' 10 | 11 | 12 | Vue.use(Plugin); 13 | Vue.use(VueSwal) 14 | 15 | 16 | 17 | Vue.use(VueRouter); 18 | //filters 19 | import {brandFilter} from "./filters/brandFilter"; 20 | import {formatMoney} from "./filters/priceFormatter"; 21 | import {paginationPipe} from "./filters/paginationFilter"; 22 | 23 | import Home from './Pages/Home'; 24 | import ShoppingCartPage from './Pages/ShoppingCartPage'; 25 | import ProductDetailPage from './Pages/ProductDetailPage'; 26 | import {shortenTitle} from "./filters/shortenTitle"; 27 | import {CLEAR_BRAND_FILTER, CLEAR_ORDER_BY_PRICE} from "./store/types"; 28 | 29 | Vue.config.productionTip = false; 30 | 31 | Vue.filter('brandFilter', brandFilter); 32 | Vue.filter('shortenTitle', shortenTitle) 33 | Vue.filter('priceFormatter', formatMoney); 34 | Vue.filter('pagination', paginationPipe); 35 | 36 | 37 | const routes = [ 38 | {path: '/', redirect: '/products'}, 39 | {path: '/products', component: Home,}, 40 | {path: '/products/:id', component: ProductDetailPage}, 41 | {path: '/cart', component: ShoppingCartPage} 42 | ]; 43 | 44 | const router = new VueRouter({routes}); 45 | new Vue({ 46 | render: h => h(App), 47 | store, 48 | router 49 | }).$mount('#app'); 50 | 51 | router.afterEach(() => { 52 | window.scrollTo(0,0); 53 | store.commit(CLEAR_BRAND_FILTER); 54 | store.commit(CLEAR_ORDER_BY_PRICE); 55 | }); 56 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import {phones} from "../data/phones"; 4 | import {brands} from "../data/brands"; 5 | import * as Types from "./types"; 6 | import {brandFilter} from "../filters/brandFilter"; 7 | import {orderByFilter} from "../filters/orderByFilter"; 8 | import {paginationPipe} from "../filters/paginationFilter"; 9 | 10 | Vue.use(Vuex); 11 | 12 | 13 | const store = new Vuex.Store({ 14 | state: { 15 | products: phones, 16 | brands: brands, 17 | cart: [], 18 | brandFilter : '', 19 | orderBy: '', 20 | perPage: 12, 21 | currentPage: 1, 22 | pagesToShow: 3, 23 | }, 24 | mutations: { 25 | [Types.ADD_PRODUCT_TO_CART] (state, product) { 26 | const cartItemIndex = state.cart.findIndex(item => item.id === product.id); 27 | 28 | if(cartItemIndex < 0) { 29 | state.cart.push({...product, quantity: 1}); 30 | } else { 31 | if(state.cart[cartItemIndex].quantity === 10) return void 0; 32 | state.cart[cartItemIndex].quantity++; 33 | } 34 | }, 35 | [Types.REMOVE_PRODUCT_FROM_CART] (state, id) { 36 | const cartItemIndex = state.cart.findIndex(item => item.id === id); 37 | 38 | state.cart.splice(cartItemIndex, 1); 39 | }, 40 | [Types.INCREMENT_CART_ITEM_QUANTITY] (state, id) { 41 | const cartItemIndex = state.cart.findIndex(item => item.id === id); 42 | window.console.log(state.cart[cartItemIndex]); 43 | if(state.cart[cartItemIndex].quantity === 10) return void 0; 44 | state.cart[cartItemIndex].quantity++; 45 | 46 | }, 47 | [Types.DECREMENT_CART_ITEM_QUANTITY] (state, id) { 48 | const cartItemIndex = state.cart.findIndex(item => item.id === id); 49 | if(state.cart[cartItemIndex].quantity === 1) return void 0; 50 | state.cart[cartItemIndex].quantity--; 51 | }, 52 | [Types.PREV_PAGE] (state) { 53 | state.currentPage--; 54 | }, 55 | [Types.NEXT_PAGE] (state) { 56 | state.currentPage++; 57 | }, 58 | [Types.GO_PAGE] (state, payload) { 59 | state.currentPage = payload; 60 | }, 61 | [Types.ORDER_BY_ASC] (state) { 62 | state.orderBy = 'asc' 63 | }, 64 | [Types.ORDER_BY_DESC] (state) { 65 | state.orderBy = 'desc'; 66 | }, 67 | [Types.CLEAR_ORDER_BY_PRICE] (state) { 68 | state.orderBy = ''; 69 | }, 70 | [Types.ADD_BRAND_TO_FILTER] (state, brand) { 71 | if(state.brandFilter.includes(brand)) return void 0; 72 | 73 | state.brandFilter += brand; 74 | }, 75 | [Types.REMOVE_BRAND_FROM_FILTER] (state, brand) { 76 | const reg = new RegExp(brand, 'gi'); 77 | state.brandFilter = state.brandFilter.replace(reg, ''); 78 | }, 79 | [Types.CLEAR_BRAND_FILTER] (state) { 80 | state.brandFilter = ''; 81 | } 82 | }, 83 | getters: { 84 | filterProducts(state) { 85 | const brands = state.brandFilter; 86 | const orderBy = state.orderBy; 87 | 88 | const filterByBrandArr = brandFilter(state.products, brands); 89 | const filterByOrderArr = orderByFilter(filterByBrandArr, orderBy); 90 | 91 | return filterByOrderArr; 92 | }, 93 | paginate(state, getters) { 94 | return paginationPipe(getters.filterProducts, {perPage:state.perPage, currentPage: state.currentPage}); 95 | }, 96 | totalItemCountAfterFilter(state, getters) { 97 | return getters.filterProducts.length; 98 | }, 99 | brandsCount(state) { 100 | const counts = {}; 101 | state.products.forEach(p => { 102 | counts[p.brand] = counts[p.brand] + 1 || 1; 103 | }); 104 | 105 | return counts; 106 | }, 107 | cartLength(state) { 108 | return state.cart.length; 109 | }, 110 | totalPrice(state) { 111 | return state.cart.reduce((count, curItem) => { 112 | return count + (curItem.quantity * curItem.price); 113 | }, 0); 114 | } 115 | } 116 | }); 117 | 118 | export default store; 119 | -------------------------------------------------------------------------------- /src/store/types.js: -------------------------------------------------------------------------------- 1 | export const ADD_PRODUCT_TO_CART = 'ADD_PRODUCT_TO_CART'; 2 | export const REMOVE_PRODUCT_FROM_CART = 'REMOVE_PRODUCT_FROM_CART'; 3 | export const INCREMENT_CART_ITEM_QUANTITY = 'INCREMENT_CART_ITEM_QUANTITY'; 4 | export const DECREMENT_CART_ITEM_QUANTITY = 'DECREMENT_CART_ITEM_QUANTITY'; 5 | 6 | export const ADD_BRAND_TO_FILTER = 'ADD_BRAND_TO_FILTER'; 7 | export const REMOVE_BRAND_FROM_FILTER = 'REMOVE_BRAND_FROM_FILTER'; 8 | export const CLEAR_BRAND_FILTER = 'CLEAR_BRAND_FILTER'; 9 | 10 | export const ORDER_BY_ASC = 'ORDER_BY_ASC'; 11 | export const ORDER_BY_DESC = 'ORDER_BY_DESC'; 12 | export const CLEAR_ORDER_BY_PRICE = 'CLEAR_ORDER_BY_PRICE'; 13 | 14 | export const PREV_PAGE = 'PREV_PAGE'; 15 | export const NEXT_PAGE = 'NEXT_PAGE'; 16 | export const GO_PAGE = 'GO_PAGE'; 17 | export const COUNT_ITEM = 'COUNT_ITEM'; 18 | -------------------------------------------------------------------------------- /src/utilities/cumulativeOffset.js: -------------------------------------------------------------------------------- 1 | export const cumulativeOffset = (element) => { 2 | let top = 0; 3 | let left = 0; 4 | 5 | do { 6 | top += element.offsetTop || 0; 7 | left += element.offsetLeft || 0; 8 | element = element.offsetParent; 9 | 10 | } while (element); 11 | 12 | 13 | return { 14 | top, 15 | left 16 | }; 17 | }; 18 | --------------------------------------------------------------------------------