├── .gitattributes
├── .gitignore
├── README.md
├── angularjs-material-seed
├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
│ ├── app.routes.ts
│ ├── app.ts
│ ├── app
│ │ ├── directives
│ │ │ └── directives
│ │ │ │ ├── directives.component.ts
│ │ │ │ ├── directives.html
│ │ │ │ ├── directives.module.ts
│ │ │ │ ├── directives.routes.ts
│ │ │ │ └── directives.service.ts
│ │ ├── expressions
│ │ │ ├── array
│ │ │ │ ├── array.component.ts
│ │ │ │ ├── array.html
│ │ │ │ ├── array.module.ts
│ │ │ │ ├── array.routes.ts
│ │ │ │ └── array.service.ts
│ │ │ ├── number
│ │ │ │ ├── number.component.ts
│ │ │ │ ├── number.html
│ │ │ │ ├── number.module.ts
│ │ │ │ ├── number.routes.ts
│ │ │ │ └── number.service.ts
│ │ │ ├── object
│ │ │ │ ├── object.component.ts
│ │ │ │ ├── object.html
│ │ │ │ ├── object.module.ts
│ │ │ │ ├── object.routes.ts
│ │ │ │ └── object.service.ts
│ │ │ └── string
│ │ │ │ ├── string.component.ts
│ │ │ │ ├── string.html
│ │ │ │ ├── string.module.ts
│ │ │ │ ├── string.routes.ts
│ │ │ │ └── string.service.ts
│ │ ├── home
│ │ │ ├── home.component.ts
│ │ │ ├── home.html
│ │ │ ├── home.module.ts
│ │ │ ├── home.routes.ts
│ │ │ └── home.service.ts
│ │ ├── main
│ │ │ ├── main.component.ts
│ │ │ ├── main.html
│ │ │ └── main.module.ts
│ │ └── settings
│ │ │ ├── settings.component.ts
│ │ │ ├── settings.html
│ │ │ ├── settings.module.ts
│ │ │ └── settings.routes.ts
│ ├── assets
│ │ ├── angularjs-material.png
│ │ ├── favicon.ico
│ │ └── material-icons.woff2
│ ├── index.html
│ └── style.scss
├── tsconfig.json
└── webpack.config.js
├── assets
└── star.png
├── package-lock.json
└── shopping-cart
├── .gitignore
├── README.md
├── client
├── assets
│ ├── Database-Architecture.txt
│ ├── customers.json
│ ├── desserts.json
│ └── shopping-cart.png
├── css
│ ├── favicon.ico
│ ├── material-icons.woff2
│ └── style.css
├── js
│ ├── app.js
│ ├── app.service.js
│ ├── home.controller.js
│ ├── menu.controller.js
│ ├── products.controller.js
│ └── ui-bootstrap-2.5.0.min.js
├── uploads
│ ├── img-2852020-1590684956674.jpg
│ └── iphone-11-pro-27-5-2020-1590551435418.jpg
└── views
│ ├── index.html
│ └── pages
│ ├── home.html
│ └── products.html
├── package-lock.json
├── package.json
├── server.js
└── utils
├── config.js
├── db.js
├── helper.js
├── product.js
├── routes.js
└── socket.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | coverage
--------------------------------------------------------------------------------
/angularjs-material-seed/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = tab
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | spaces_around_brackets = inside
11 | max_line_length = 1000
12 |
13 | spaces_around_brackets = inside
14 | max_line_length = 1000
15 |
16 | [*.md]
17 | max_line_length = off
18 | trim_trailing_whitespace = false
19 |
--------------------------------------------------------------------------------
/angularjs-material-seed/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/angularjs-material-seed/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Pradeep Kumar
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 |
--------------------------------------------------------------------------------
/angularjs-material-seed/README.md:
--------------------------------------------------------------------------------
1 | # AngularJs-Material Seed App
2 |
3 | Ready to go template to get started with AngularJs, Material, Typescript, SCSS and Webpack.
4 |
5 | Includes:
6 | * Predefined sidenav with hammerjs-support
7 | * Offline Material Icons
8 | * Home and Settings page as AngularJs 1.6 components with their own modules
9 | * Multiple theme configuration
10 |
11 | ## Demo
12 | [link](#)
13 |
14 | ## Usage
15 | Start Live Dev Server
16 | ```js
17 | npm start
18 | ```
19 |
20 | Build Project and deploy to "dist":
21 | ```js
22 | npm run build:prod
23 | ```
24 |
25 | ## Project Output
26 |
27 | 
28 |
29 |
30 | ## References
31 |
32 | * [AngularJS V1.7x](https://code.angularjs.org/snapshot-stable/docs/tutorial/step_00)
33 | * [AngularJS Material](https://material.angularjs.org/latest/)
34 | * [HammerJS](https://hammerjs.github.io/)
35 | * [Sass](https://sass-lang.com/)
36 | * [Webpack](https://webpack.js.org/)
37 | * [Typescript](https://www.typescriptlang.org/)
38 |
--------------------------------------------------------------------------------
/angularjs-material-seed/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angularjs-webpack-typescript",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack-dev-server --port 4200 --mode development --open",
8 | "build": "webpack --mode development",
9 | "build:prod": "webpack --mode production",
10 | "test": "karma start karma.conf.js",
11 | "test-single-run": "npm test -- --single-run",
12 | "preupdate-webdriver": "npm install",
13 | "update-webdriver": "webdriver-manager update --gecko false",
14 | "preprotractor": "npm run update-webdriver",
15 | "protractor": "protractor e2e-tests/protractor.conf.js"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "dependencies": {
20 | "@types/angular": "1.6.54",
21 | "@types/angular-material": "1.1.68",
22 | "@types/node": "12.0.10",
23 | "@uirouter/angularjs": "1.0.20",
24 | "angular": "^1.8.0",
25 | "angular-animate": "^1.8.0",
26 | "angular-aria": "^1.8.0",
27 | "angular-hammer": "2.2.0",
28 | "angular-material": "1.1.19",
29 | "hammerjs": "2.0.8"
30 | },
31 | "devDependencies": {
32 | "angular-mocks": "^1.8.0",
33 | "clean-webpack-plugin": "^3.0.0",
34 | "copy-webpack-plugin": "^5.0.3",
35 | "css-loader": "1.0.0",
36 | "file-loader": "3.0.1",
37 | "html-loader": "0.5.5",
38 | "html-webpack-plugin": "^3.2.0",
39 | "jasmine-core": "^3.5.0",
40 | "karma": "^5.1.0",
41 | "karma-chrome-launcher": "^3.1.0",
42 | "karma-firefox-launcher": "^1.3.0",
43 | "karma-jasmine": "^3.3.1",
44 | "live-server": "^1.2.1",
45 | "mini-css-extract-plugin": "^0.7.0",
46 | "ngtemplate-loader": "2.0.1",
47 | "node-sass": "4.12.0",
48 | "protractor": "^5.4.4",
49 | "sass-loader": "7.1.0",
50 | "style-loader": "0.23.1",
51 | "ts-loader": "5.3.2",
52 | "typescript": "3.5.2",
53 | "uglifyjs-webpack-plugin": "^2.1.3",
54 | "url-loader": "1.1.2",
55 | "webpack": "4.35.0",
56 | "webpack-bundle-analyzer": "3.3.2",
57 | "webpack-cli": "3.3.5",
58 | "webpack-dev-server": "3.7.2"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider) {
2 | $urlRouterProvider.otherwise('/');
3 | }
4 | routes.$inject = ['$urlRouterProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 | import * as ngAnimate from 'angular-animate';
3 | import * as ngAria from 'angular-aria';
4 | import * as ngMaterial from 'angular-material';
5 | import * as uiRouter from '@uirouter/angularjs';
6 | import { routes } from './app.routes';
7 | import 'angular-material/angular-material.scss';
8 | import 'hammerjs';
9 | import * as hmTouchEvents from 'angular-hammer';
10 |
11 | import './style.scss';
12 |
13 | import mainModule from './app/main/main.module';
14 | import settingsModule from './app/settings/settings.module';
15 | import homeModule from './app/home/home.module';
16 | import numberModule from './app/expressions/number/number.module';
17 | import objectModule from './app/expressions/object/object.module';
18 | import stringModule from './app/expressions/string/string.module';
19 | import arrayModule from './app/expressions/array/array.module';
20 | import directivesModule from './app/directives/directives/directives.module';
21 |
22 |
23 | angular.module("app", [
24 | uiRouter.default,
25 | ngAnimate, ngAria,
26 | ngMaterial,
27 | hmTouchEvents,
28 | mainModule,
29 | settingsModule,
30 | homeModule,
31 | numberModule,
32 | stringModule,
33 | objectModule,
34 | arrayModule,
35 | directivesModule
36 | ]);
37 | angular.module("app").config(routes);
38 |
39 | angular.module("app").config(["$mdThemingProvider", function ($mdThemingProvider) {
40 | $mdThemingProvider.theme("blue")
41 | .primaryPalette("blue")
42 | .accentPalette("red");
43 |
44 | $mdThemingProvider.theme("green")
45 | .primaryPalette("teal")
46 | .accentPalette("red");
47 |
48 | $mdThemingProvider.alwaysWatchTheme(true);
49 | }]);
50 |
51 | //https://docs.angularjs.org/guide/production
52 | angular.module("app").config(['$compileProvider', function ($compileProvider) {
53 | $compileProvider.debugInfoEnabled(true);
54 | $compileProvider.commentDirectivesEnabled(false);
55 | $compileProvider.cssClassDirectivesEnabled(false);
56 | }]);
57 |
58 | angular.bootstrap(document, ["app"]);
59 |
60 | //https://github.com/vsternbach/angularjs-typescript-webpack
61 | //http://ryanmullins.github.io/angular-hammer/
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/directives/directives/directives.component.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as angular from 'angular';
3 |
4 | class DirectivesCtrl {
5 |
6 | constructor(private $scope: any) { }
7 | }
8 |
9 | export default {
10 | bindings: { title: "=" },
11 | templateUrl: require("./directives.html"),
12 | controller: DirectivesCtrl
13 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/directives/directives/directives.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NgAPP Directives
6 |
7 |
8 |
9 |
10 | some button
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/directives/directives/directives.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './directives.routes';
4 | import directivesComponent from './directives.component';
5 | import { DirectivesService } from './directives.service';
6 |
7 | export default angular.module('ng-app', [])
8 | .config(routes)
9 | .component("directives", directivesComponent)
10 | .service('directivesService', DirectivesService)
11 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/directives/directives/directives.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'directives', url: '/directives', component: 'directives' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/directives/directives/directives.service.ts:
--------------------------------------------------------------------------------
1 | export class DirectivesService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/array/array.component.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as angular from 'angular';
3 |
4 | class ArrayCtrl {
5 |
6 | constructor(private $scope: any) {
7 |
8 | }
9 |
10 | }
11 |
12 | export default {
13 | bindings: { text: "@" }, /** Reading an attribute as text **/
14 | templateUrl: require("./array.html"),
15 | controller: ArrayCtrl
16 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/array/array.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Array Expressions
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Student Marks
14 |
15 | Physics: {{marks[0] }}
16 | Chemistry: {{marks[1] }}
17 | Mathematics: {{marks[2] }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/array/array.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './array.routes';
4 | import arrayComponent from './array.component';
5 | import { ArrayService } from './array.service';
6 |
7 | export default angular.module('array', [])
8 | .config(routes)
9 | .component("array", arrayComponent)
10 | .service('arrayService', ArrayService)
11 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/array/array.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'array', url: '/array', component: 'array' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/array/array.service.ts:
--------------------------------------------------------------------------------
1 | export class ArrayService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/number/number.component.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as angular from 'angular';
3 |
4 | class NumberCtrl {
5 | sum = 0;
6 | constructor(private $scope: any) {
7 |
8 | }
9 |
10 | getResult() {
11 | this.sum = this.$scope.user.number1 + this.$scope.user.number2;
12 | this.$scope.result = "Total is: "+ this.sum;
13 | }
14 | }
15 |
16 | export default {
17 | bindings: { title: "=" },
18 | templateUrl: require("./number.html"),
19 | controller: NumberCtrl
20 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/number/number.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Number Expressions
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Add
23 |
24 |
25 |
26 | {{result}}
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/number/number.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './number.routes';
4 | import numberComponent from './number.component';
5 | import { NumberService } from './number.service';
6 |
7 | export default angular.module('number', [])
8 | .config(routes)
9 | .component("number", numberComponent)
10 | .service('numberService', NumberService)
11 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/number/number.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'number', url: '/number', component: 'number' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/number/number.service.ts:
--------------------------------------------------------------------------------
1 | export class NumberService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/object/object.component.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as angular from 'angular';
3 |
4 | class ObjectCtrl {
5 |
6 | constructor(private $scope: any) {
7 |
8 | }
9 |
10 | initHeaders() {
11 | return [
12 | {
13 | contentField : 'date',
14 | contentFilter: {
15 | filter : 'date',
16 | pattern: 'dd/MM/yyyy'
17 | },
18 | contentType : 'text',
19 | label : 'Date',
20 | sortableField: true
21 | }, {
22 | contentField : 'label',
23 | contentFilter: {
24 | filter: 'uppercase'
25 | },
26 | contentType : 'text',
27 | label : 'Label',
28 | sortableField: true
29 | }, {
30 | contentField : 'amount',
31 | contentType : 'input',
32 | label : 'Amount',
33 | sortableField: true
34 | }
35 | ];
36 | }
37 |
38 | initContent() {
39 | return [
40 | {
41 | amount: 10.0,
42 | date : new Date().getMilliseconds(),
43 | label : 'Task 1'
44 | }, {
45 | amount: 20.0,
46 | date : new Date().getMilliseconds(),
47 | label : 'Task 2'
48 | }, {
49 | amount: 90.0,
50 | date : new Date().getMilliseconds(),
51 | label : 'Task 3'
52 | }, {
53 | amount: 60.0,
54 | date : new Date().getMilliseconds(),
55 | label : 'Task 4'
56 | }, {
57 | amount: 70.0,
58 | date : new Date().getMilliseconds(),
59 | label : 'Task 5'
60 | }, {
61 | amount: 30.0,
62 | date : new Date().getMilliseconds(),
63 | label : 'Task 6'
64 | }, {
65 | amount: 50.0,
66 | date : new Date().getMilliseconds(),
67 | label : 'Task 7'
68 | }, {
69 | amount: 80.0,
70 | date : new Date().getMilliseconds(),
71 | label : 'Task 8'
72 | }, {
73 | amount: 5.0,
74 | date : new Date().getMilliseconds(),
75 | label : 'Task 9'
76 | }
77 | ];
78 | }
79 | }
80 |
81 | export default {
82 | bindings: { text: "@" }, /** Reading an attribute as text **/
83 | templateUrl: require("./object.html"),
84 | controller: ObjectCtrl
85 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/object/object.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Object Expressions
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Student Name: {{ student.name }}
14 |
Percentage: {{ student.percent }}
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/object/object.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './object.routes';
4 | import objectComponent from './object.component';
5 | import { ObjectService } from './object.service';
6 |
7 | export default angular.module('object', [])
8 | .config(routes)
9 | .component("object", objectComponent)
10 | .service('objectService', ObjectService)
11 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/object/object.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'object', url: '/object', component: 'object' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/object/object.service.ts:
--------------------------------------------------------------------------------
1 | export class ObjectService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/string/string.component.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as angular from 'angular';
3 |
4 | class StringCtrl {
5 |
6 | constructor(private $scope: any) {
7 |
8 | }
9 |
10 | getResult() {
11 | this.$scope.result = 'You full name is: ' +this.$scope.user.firstName + ' ' +this.$scope.user.lastName;
12 | }
13 | }
14 |
15 | export default {
16 | bindings: { text: "@" }, /** Reading an attribute as text **/
17 | templateUrl: require("./string.html"),
18 | controller: StringCtrl
19 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/string/string.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | String Expressions
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Result
23 |
24 |
25 |
26 | {{result}}
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/string/string.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './string.routes';
4 | import stringComponent from './string.component';
5 | import { StringService } from './string.service';
6 |
7 | export default angular.module('string', [])
8 | .config(routes)
9 | .component("string", stringComponent)
10 | .service('stringService', StringService)
11 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/string/string.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'string', url: '/string', component: 'string' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/expressions/string/string.service.ts:
--------------------------------------------------------------------------------
1 | export class StringService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 |
2 | class HomeCtrl {
3 | static $inject = [];
4 | constructor() {
5 | this.test = "some binding";
6 | }
7 |
8 | test: string;
9 |
10 | testClick() {
11 | alert("you clicked the button")
12 | }
13 |
14 | folders = [
15 | { title: "list item 1", icon: "folder", updated: new Date('1/1/16') },
16 | { title: "list item 2", icon: "folder", updated: new Date('1/1/16') },
17 | { title: "list item 3", icon: "folder", updated: new Date('1/1/16') },
18 | ];
19 | }
20 |
21 | export default {
22 | bindings: {},
23 | templateUrl: require("./home.html"),
24 | controller: HomeCtrl
25 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/home/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Home Page
6 |
7 |
8 |
9 |
10 | some button
11 |
12 |
13 |
14 |
15 |
16 | Folders
17 |
18 | {{folder.icon}}
19 |
20 |
{{folder.title}}
21 |
{{folder.updated | date}}
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | import { routes } from './home.routes';
4 |
5 | import homeComponent from './home.component';
6 | import { HomeService } from './home.service';
7 |
8 | export default angular.module('home', [])
9 | .config(routes)
10 | .component("home", homeComponent)
11 | .service('homeService', HomeService)
12 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/home/home.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $urlRouterProvider.otherwise('/');
3 |
4 | $stateProvider.state({ name: 'home', url: '/', component: 'home' });
5 | }
6 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/home/home.service.ts:
--------------------------------------------------------------------------------
1 | export class HomeService {
2 | constructor() {
3 | }
4 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/main/main.component.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 |
3 | class MainCtrl {
4 |
5 | constructor(
6 | private $scope: ng.IScope,
7 | private $mdSidenav: ng.material.ISidenavService,
8 | private $location: ng.ILocationService
9 | ) {
10 | this.$scope.$on('update-theme', (event, args) => {
11 | this.currentTheme = args;
12 | });
13 |
14 | this.$scope.$on('$viewContentLoaded', () => {
15 | document.getElementById('pages').classList.add('pages-sidenav');
16 | this.openNav();
17 | });
18 | }
19 | $onInit() {
20 | }
21 |
22 | currentTheme = "green";
23 | menus = [
24 | {
25 | title: 'Expressions',
26 | icon: 'list',
27 | active: false,
28 | type: 'dropdown',
29 | submenus: [
30 | {
31 | title: 'Number Expressions',
32 | icon: 'settings_ethernet',
33 | path: 'number'
34 | },
35 | {
36 | title: 'String Expressions',
37 | icon: 'settings_ethernet',
38 | path: 'string'
39 | },
40 | {
41 | title: 'Object Expressions',
42 | icon: 'settings_ethernet',
43 | path: 'object'
44 | },
45 | {
46 | title: 'Array Expressions',
47 | icon: 'settings_ethernet',
48 | path: 'array'
49 | }
50 | ]
51 | },
52 | {
53 | title: 'Directives',
54 | icon: 'list',
55 | active: false,
56 | type: 'dropdown',
57 | submenus: [
58 | {
59 | title: 'Directives',
60 | icon: 'settings_ethernet',
61 | path: 'directives'
62 | }
63 | ]
64 | }
65 | ];
66 |
67 | sideNav() {
68 | document.getElementById('pages').classList.toggle('pages-sidenav');
69 | }
70 |
71 | toggleNav() {
72 | this.$mdSidenav("left").toggle();
73 | }
74 |
75 | openNav() {
76 | this.$mdSidenav("left").open();
77 | }
78 |
79 | closeNav() {
80 | this.$mdSidenav("left").close();
81 | }
82 |
83 | goTo(link: string) {
84 | this.$mdSidenav("left").open();
85 | this.$location.path(link);
86 | }
87 | }
88 |
89 | MainCtrl.$inject = ["$scope", "$mdSidenav", "$location", "$mdComponentRegistry", "$log", "$mdMedia", "$timeout"];
90 |
91 | export default {
92 | bindings: { title: "=" },
93 | templateUrl: require("./main.html"),
94 | controller: MainCtrl
95 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/main/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{item.icon}}
15 | {{item.title}}
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
{{$ctrl.title}}
32 |
33 | menu
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/main/main.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 | import mainComponent from './main.component';
3 |
4 | export default angular.module('main', [])
5 | .component("main", mainComponent)
6 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/settings/settings.component.ts:
--------------------------------------------------------------------------------
1 | class SettingsCtrl {
2 | static $inject = ['$rootScope'];
3 | constructor(private $rootScope: ng.IRootScopeService) {
4 | }
5 |
6 | theme: string = "green";
7 | themes: Array = ["blue", "green"];
8 |
9 | updateTheme() {
10 | this.$rootScope.$broadcast("update-theme", this.theme);
11 | }
12 | }
13 |
14 | export default {
15 | bindings: {},
16 | templateUrl: require("./settings.html"),
17 | controller: SettingsCtrl
18 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/settings/settings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Settings Page
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{theme}}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/settings/settings.module.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 | import settingsComponent from './settings.component';
3 | import { routes } from './settings.routes';
4 |
5 | export default angular.module('settings', [])
6 | .config(routes)
7 | .component("settings", settingsComponent)
8 | .name;
--------------------------------------------------------------------------------
/angularjs-material-seed/src/app/settings/settings.routes.ts:
--------------------------------------------------------------------------------
1 | export function routes($urlRouterProvider, $stateProvider) {
2 | $stateProvider.state({ name: 'settings', url: '/settings', component: 'settings' });
3 | }
4 | routes.$inject = ['$urlRouterProvider', '$stateProvider'];
--------------------------------------------------------------------------------
/angularjs-material-seed/src/assets/angularjs-material.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/angularjs-material.png
--------------------------------------------------------------------------------
/angularjs-material-seed/src/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/favicon.ico
--------------------------------------------------------------------------------
/angularjs-material-seed/src/assets/material-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/angularjs-material-seed/src/assets/material-icons.woff2
--------------------------------------------------------------------------------
/angularjs-material-seed/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularJs Webpack Typescript
6 |
7 |
8 |
9 |
10 |
11 | Loading...
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/angularjs-material-seed/src/style.scss:
--------------------------------------------------------------------------------
1 | [ng-cloak] {
2 | display: none !important;
3 | }
4 |
5 | @font-face {
6 | font-family: 'Material Icons';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url(./assets/material-icons.woff2) format('woff2');
10 | }
11 |
12 | .material-icons {
13 | font-family: 'Material Icons';
14 | font-weight: normal;
15 | font-style: normal;
16 | font-size: 24px;
17 | line-height: 1;
18 | letter-spacing: normal;
19 | text-transform: none;
20 | display: inline-block;
21 | white-space: nowrap;
22 | word-wrap: normal;
23 | direction: ltr;
24 | font-feature-settings: 'liga';
25 | -webkit-font-feature-settings: 'liga';
26 | -webkit-font-smoothing: antialiased;
27 | }
28 |
29 | [ng-cloak] {
30 | display: none !important;
31 | }
32 |
33 | .splash {
34 | display: none;
35 | }
36 |
37 | [ng-cloak].splash {
38 | display: block !important;
39 | }
40 |
41 | .md-sidenav-left, md-sidenav {
42 | top: 71px;
43 | border-radius: 4px;
44 | }
45 |
46 | md-sidenav {
47 | max-width: 240px;
48 | }
49 |
50 | md-toolbar:not(.md-menu-toolbar) {
51 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12);
52 | }
53 |
54 | md-backdrop.md-opaque {
55 | opacity: 0;
56 | }
57 |
58 | md-toolbar.md-tall {
59 | height: 0px;
60 | min-height: 0px;
61 | max-height: 0px;
62 | }
63 |
64 | .pages-sidenav {
65 | padding-left: 16%;
66 | transition-duration: 0.6s;
67 | -webkit-transition-duration: 0.6s;
68 | }
69 |
70 | .submenus-text {
71 | padding-left: 2px;
72 | font-size: 14px;
73 | }
74 |
75 | md-list-item .md-list-item-inner {
76 | border-bottom: 0.1px solid;
77 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "sourceMap": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "removeComments": false,
9 | "noImplicitAny": false,
10 | "lib": [
11 | "es2015",
12 | "dom"
13 | ]
14 | },
15 | "exclude": [
16 | "node_modules"
17 | ]
18 | }
--------------------------------------------------------------------------------
/angularjs-material-seed/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const HtmlWebpackPlugin = require("html-webpack-plugin");
4 | const MiniCssExtractPlugin = require("mini-css-extract-plugin");
5 | const CopyWebpackPlugin = require('copy-webpack-plugin');
6 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
8 |
9 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
10 |
11 | module.exports = (env, argv) => {
12 |
13 | return {
14 | context: path.resolve(__dirname, './src'),
15 |
16 | entry: {
17 | app: './app.ts'
18 | },
19 |
20 | output: {
21 | filename: '[name].[contenthash].bundle.js',
22 | chunkFilename: '[name].[contenthash].bundle.js',
23 | path: path.resolve(__dirname, 'dist'),
24 | },
25 |
26 | devtool: 'source-map',
27 |
28 | resolve: { extensions: ['.ts', '.js'] },
29 |
30 | module: {
31 | rules: [
32 | {
33 | test: /\.ts?$/,
34 | loader: 'ts-loader',
35 | options: { transpileOnly: true }
36 | },
37 | {
38 | test: /\.html$/,
39 | exclude: `${path.join(__dirname, "/src/index.html")}`,
40 | use: [
41 | { loader: 'ngtemplate-loader?relativeTo=' + (path.resolve(__dirname, './src')) },
42 | { loader: 'html-loader' }
43 | ]
44 | },
45 | {
46 | test: /\.scss$/,
47 | use: [
48 | MiniCssExtractPlugin.loader,
49 | "css-loader",
50 | "sass-loader"
51 | ]
52 | },
53 | { test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, loader: 'file-loader?name=assets/[name].[ext]' },
54 | ]
55 | },
56 |
57 | plugins: [
58 | new webpack.ProgressPlugin(),
59 | new CleanWebpackPlugin(),
60 | new HtmlWebpackPlugin({
61 | template: "./index.html",
62 | filename: "index.html",
63 | chunksSortMode: "manual",
64 | chunks: ['vendors', 'app'],
65 | }),
66 | new MiniCssExtractPlugin({
67 | filename: "style.[contenthash].css",
68 | chunkFilename: "style.[contenthash].css"
69 | }),
70 | new CopyWebpackPlugin([
71 | { from: 'assets', to: 'assets' }
72 | ])
73 | //new BundleAnalyzerPlugin()
74 | ],
75 |
76 | optimization: {
77 | splitChunks: {
78 | cacheGroups: {
79 | commons: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all" }
80 | }
81 | },
82 | minimizer: [
83 | new UglifyJsPlugin({
84 | uglifyOptions: {
85 | output: {
86 | comments: false
87 | }
88 | }
89 | })
90 | ]
91 | }
92 | }
93 | };
--------------------------------------------------------------------------------
/assets/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/assets/star.png
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "@angular/upgrade": {
6 | "version": "9.1.3",
7 | "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-9.1.3.tgz",
8 | "integrity": "sha512-VtnURviY4qZPALI6vz5tJdSuJY5Ltj3P7ZVTZ2XE2wk2oC9piGlNrkF912HFG4uN2uxoxwX2TFSD5wkMIcLTWQ=="
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/shopping-cart/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # IDEs and editors
7 | /.idea
8 | .project
9 | .classpath
10 | .c9/
11 | *.launch
12 | .settings/
13 | *.sublime-workspace
14 |
15 | # IDE - VSCode
16 | .vscode/*
17 | !.vscode/settings.json
18 | !.vscode/tasks.json
19 | !.vscode/launch.json
20 | !.vscode/extensions.json
21 |
--------------------------------------------------------------------------------
/shopping-cart/README.md:
--------------------------------------------------------------------------------
1 | ## Shopping Cart
2 |
3 |
4 |
5 |
6 |
7 | #### Project Description
8 |
9 | > Shopping application developed on AngularJS, AngularJS Material, NodeJS and MySQL.
10 |
11 |
12 |
13 | #### Installation & Setup
14 |
15 | 1. `Run install`
16 | 2. `node server.js`
17 |
18 |
19 | #### Tools and Technologies
20 |
21 | - Technology: AngularJS, HTML, SCSS, NodeJS
22 | - Middleware: ExpressJS
23 | - Database : MySQL
24 |
25 |
26 |
27 |
28 | #### Resources
29 |
30 | * [AngularJS v1.7x](https://code.angularjs.org/snapshot-stable/docs/tutorial/step_00)
31 | * [AngularJS Material](https://material.angularjs.org/latest/)
32 | * [HammerJS](https://hammerjs.github.io/)
33 | * [Sass](https://sass-lang.com/)
34 | * [Webpack](https://webpack.js.org/)
35 | * [Typescript](https://www.typescriptlang.org/)
36 |
37 |
38 | #### Project Output
39 |
40 |
41 |
--------------------------------------------------------------------------------
/shopping-cart/client/assets/Database-Architecture.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * Table Structure
3 | *
4 | **/
5 |
6 |
7 | -------------------
8 | Product Table
9 | -------------------
10 | a. Product Name
11 | b. Product Description
12 | c. Product SKU
13 | d. Product Serial Number
14 | e. Product Purchase Price
15 | f. Product Selling Price
16 | g. Product Quantity
17 | h. Reordered Stock Amount
18 | i. Expiration Date
19 | j. Product Image
20 |
21 | ------------------
22 | Barcode Table
23 | ------------------
24 | a. Barcode Type
25 | b. Barcode
26 |
27 | ----------------
28 | Warehouse
29 | ----------------
30 |
31 |
32 |
33 |
34 | ----------------
35 | Category
36 | ----------------
37 |
38 |
39 |
--------------------------------------------------------------------------------
/shopping-cart/client/assets/customers.json:
--------------------------------------------------------------------------------
1 | {"customers":[{"id":"ALFKI","companyName":"Alfreds Futterkiste","contactName":"Maria Anders","contactTitle":"Sales Representative","address":"Obere Str. 57","city":"Berlin","postalCode":"12209","country":"Germany","phone":"030-0074321","fax":"030-0076545"},{"id":"ANATR","companyName":"Ana Trujillo Emparedados y helados","contactName":"Ana Trujillo","contactTitle":"Owner","address":"Avda. de la Constitución 2222","city":"México D.F.","postalCode":"05021","country":"Mexico","phone":"(5) 555-4729","fax":"(5) 555-3745"},{"id":"ANTON","companyName":"Antonio Moreno Taquería","contactName":"Antonio Moreno","contactTitle":"Owner","address":"Mataderos 2312","city":"México D.F.","postalCode":"05023","country":"Mexico","phone":"(5) 555-3932"},{"id":"AROUT","companyName":"Around the Horn","contactName":"Thomas Hardy","contactTitle":"Sales Representative","address":"120 Hanover Sq.","city":"London","postalCode":"WA1 1DP","country":"UK","phone":"(171) 555-7788","fax":"(171) 555-6750"},{"id":"BERGS","companyName":"Berglunds snabbköp","contactName":"Christina Berglund","contactTitle":"Order Administrator","address":"Berguvsvägen 8","city":"Luleå","postalCode":"S-958 22","country":"Sweden","phone":"0921-12 34 65","fax":"0921-12 34 67"},{"id":"BLAUS","companyName":"Blauer See Delikatessen","contactName":"Hanna Moos","contactTitle":"Sales Representative","address":"Forsterstr. 57","city":"Mannheim","postalCode":"68306","country":"Germany","phone":"0621-08460","fax":"0621-08924"},{"id":"BLONP","companyName":"Blondesddsl père et fils","contactName":"Frédérique Citeaux","contactTitle":"Marketing Manager","address":"24, place Kléber","city":"Strasbourg","postalCode":"67000","country":"France","phone":"88.60.15.31","fax":"88.60.15.32"},{"id":"BOLID","companyName":"Bólido Comidas preparadas","contactName":"Martín Sommer","contactTitle":"Owner","address":"C/ Araquil, 67","city":"Madrid","postalCode":"28023","country":"Spain","phone":"(91) 555 22 82","fax":"(91) 555 91 99"},{"id":"BONAP","companyName":"Bon app","contactName":"Laurence Lebihan","contactTitle":"Owner","address":"12, rue des Bouchers","city":"Marseille","postalCode":"13008","country":"France","phone":"91.24.45.40","fax":"91.24.45.41"},{"id":"BOTTM","companyName":"Bottom-Dollar Markets","contactName":"Elizabeth Lincoln","contactTitle":"Accounting Manager","address":"23 Tsawassen Blvd.","city":"Tsawassen","region":"BC","postalCode":"T2F 8M4","country":"Canada","phone":"(604) 555-4729","fax":"(604) 555-3745"},{"id":"BSBEV","companyName":"B's Beverages","contactName":"Victoria Ashworth","contactTitle":"Sales Representative","address":"Fauntleroy Circus","city":"London","postalCode":"EC2 5NT","country":"UK","phone":"(171) 555-1212"},{"id":"CACTU","companyName":"Cactus Comidas para llevar","contactName":"Patricio Simpson","contactTitle":"Sales Agent","address":"Cerrito 333","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 135-5555","fax":"(1) 135-4892"},{"id":"CENTC","companyName":"Centro comercial Moctezuma","contactName":"Francisco Chang","contactTitle":"Marketing Manager","address":"Sierras de Granada 9993","city":"México D.F.","postalCode":"05022","country":"Mexico","phone":"(5) 555-3392","fax":"(5) 555-7293"},{"id":"CHOPS","companyName":"Chop-suey Chinese","contactName":"Yang Wang","contactTitle":"Owner","address":"Hauptstr. 29","city":"Bern","postalCode":"3012","country":"Switzerland","phone":"0452-076545"},{"id":"COMMI","companyName":"Comércio Mineiro","contactName":"Pedro Afonso","contactTitle":"Sales Associate","address":"Av. dos Lusíadas, 23","city":"Sao Paulo","region":"SP","postalCode":"05432-043","country":"Brazil","phone":"(11) 555-7647"},{"id":"CONSH","companyName":"Consolidated Holdings","contactName":"Elizabeth Brown","contactTitle":"Sales Representative","address":"Berkeley Gardens 12 Brewery","city":"London","postalCode":"WX1 6LT","country":"UK","phone":"(171) 555-2282","fax":"(171) 555-9199"},{"id":"DRACD","companyName":"Drachenblut Delikatessen","contactName":"Sven Ottlieb","contactTitle":"Order Administrator","address":"Walserweg 21","city":"Aachen","postalCode":"52066","country":"Germany","phone":"0241-039123","fax":"0241-059428"},{"id":"DUMON","companyName":"Du monde entier","contactName":"Janine Labrune","contactTitle":"Owner","address":"67, rue des Cinquante Otages","city":"Nantes","postalCode":"44000","country":"France","phone":"40.67.88.88","fax":"40.67.89.89"},{"id":"EASTC","companyName":"Eastern Connection","contactName":"Ann Devon","contactTitle":"Sales Agent","address":"35 King George","city":"London","postalCode":"WX3 6FW","country":"UK","phone":"(171) 555-0297","fax":"(171) 555-3373"},{"id":"ERNSH","companyName":"Ernst Handel","contactName":"Roland Mendel","contactTitle":"Sales Manager","address":"Kirchgasse 6","city":"Graz","postalCode":"8010","country":"Austria","phone":"7675-3425","fax":"7675-3426"},{"id":"FAMIA","companyName":"Familia Arquibaldo","contactName":"Aria Cruz","contactTitle":"Marketing Assistant","address":"Rua Orós, 92","city":"Sao Paulo","region":"SP","postalCode":"05442-030","country":"Brazil","phone":"(11) 555-9857"},{"id":"FISSA","companyName":"FISSA Fabrica Inter. Salchichas S.A.","contactName":"Diego Roel","contactTitle":"Accounting Manager","address":"C/ Moralzarzal, 86","city":"Madrid","postalCode":"28034","country":"Spain","phone":"(91) 555 94 44","fax":"(91) 555 55 93"},{"id":"FOLIG","companyName":"Folies gourmandes","contactName":"Martine Rancé","contactTitle":"Assistant Sales Agent","address":"184, chaussée de Tournai","city":"Lille","postalCode":"59000","country":"France","phone":"20.16.10.16","fax":"20.16.10.17"},{"id":"FOLKO","companyName":"Folk och fä HB","contactName":"Maria Larsson","contactTitle":"Owner","address":"Åkergatan 24","city":"Bräcke","postalCode":"S-844 67","country":"Sweden","phone":"0695-34 67 21"},{"id":"FRANK","companyName":"Frankenversand","contactName":"Peter Franken","contactTitle":"Marketing Manager","address":"Berliner Platz 43","city":"München","postalCode":"80805","country":"Germany","phone":"089-0877310","fax":"089-0877451"},{"id":"FRANR","companyName":"France restauration","contactName":"Carine Schmitt","contactTitle":"Marketing Manager","address":"54, rue Royale","city":"Nantes","postalCode":"44000","country":"France","phone":"40.32.21.21","fax":"40.32.21.20"},{"id":"FRANS","companyName":"Franchi S.p.A.","contactName":"Paolo Accorti","contactTitle":"Sales Representative","address":"Via Monte Bianco 34","city":"Torino","postalCode":"10100","country":"Italy","phone":"011-4988260","fax":"011-4988261"},{"id":"FURIB","companyName":"Furia Bacalhau e Frutos do Mar","contactName":"Lino Rodriguez","contactTitle":"Sales Manager","address":"Jardim das rosas n. 32","city":"Lisboa","postalCode":"1675","country":"Portugal","phone":"(1) 354-2534","fax":"(1) 354-2535"},{"id":"GALED","companyName":"Galería del gastrónomo","contactName":"Eduardo Saavedra","contactTitle":"Marketing Manager","address":"Rambla de Cataluña, 23","city":"Barcelona","postalCode":"08022","country":"Spain","phone":"(93) 203 4560","fax":"(93) 203 4561"},{"id":"GODOS","companyName":"Godos Cocina Típica","contactName":"José Pedro Freyre","contactTitle":"Sales Manager","address":"C/ Romero, 33","city":"Sevilla","postalCode":"41101","country":"Spain","phone":"(95) 555 82 82"},{"id":"GOURL","companyName":"Gourmet Lanchonetes","contactName":"André Fonseca","contactTitle":"Sales Associate","address":"Av. Brasil, 442","city":"Campinas","region":"SP","postalCode":"04876-786","country":"Brazil","phone":"(11) 555-9482"},{"id":"GREAL","companyName":"Great Lakes Food Market","contactName":"Howard Snyder","contactTitle":"Marketing Manager","address":"2732 Baker Blvd.","city":"Eugene","region":"OR","postalCode":"97403","country":"USA","phone":"(503) 555-7555"},{"id":"GROSR","companyName":"GROSELLA-Restaurante","contactName":"Manuel Pereira","contactTitle":"Owner","address":"5ª Ave. Los Palos Grandes","city":"Caracas","region":"DF","postalCode":"1081","country":"Venezuela","phone":"(2) 283-2951","fax":"(2) 283-3397"},{"id":"HANAR","companyName":"Hanari Carnes","contactName":"Mario Pontes","contactTitle":"Accounting Manager","address":"Rua do Paço, 67","city":"Rio de Janeiro","region":"RJ","postalCode":"05454-876","country":"Brazil","phone":"(21) 555-0091","fax":"(21) 555-8765"},{"id":"HILAA","companyName":"HILARION-Abastos","contactName":"Carlos Hernández","contactTitle":"Sales Representative","address":"Carrera 22 con Ave. Carlos Soublette #8-35","city":"San Cristóbal","region":"Táchira","postalCode":"5022","country":"Venezuela","phone":"(5) 555-1340","fax":"(5) 555-1948"},{"id":"HUNGC","companyName":"Hungry Coyote Import Store","contactName":"Yoshi Latimer","contactTitle":"Sales Representative","address":"City Center Plaza 516 Main St.","city":"Elgin","region":"OR","postalCode":"97827","country":"USA","phone":"(503) 555-6874","fax":"(503) 555-2376"},{"id":"HUNGO","companyName":"Hungry Owl All-Night Grocers","contactName":"Patricia McKenna","contactTitle":"Sales Associate","address":"8 Johnstown Road","city":"Cork","region":"Co. Cork","country":"Ireland","phone":"2967 542","fax":"2967 3333"},{"id":"ISLAT","companyName":"Island Trading","contactName":"Helen Bennett","contactTitle":"Marketing Manager","address":"Garden House Crowther Way","city":"Cowes","region":"Isle of Wight","postalCode":"PO31 7PJ","country":"UK","phone":"(198) 555-8888"},{"id":"KOENE","companyName":"Königlich Essen","contactName":"Philip Cramer","contactTitle":"Sales Associate","address":"Maubelstr. 90","city":"Brandenburg","postalCode":"14776","country":"Germany","phone":"0555-09876"},{"id":"LACOR","companyName":"La corne d'abondance","contactName":"Daniel Tonini","contactTitle":"Sales Representative","address":"67, avenue de l'Europe","city":"Versailles","postalCode":"78000","country":"France","phone":"30.59.84.10","fax":"30.59.85.11"},{"id":"LAMAI","companyName":"La maison d'Asie","contactName":"Annette Roulet","contactTitle":"Sales Manager","address":"1 rue Alsace-Lorraine","city":"Toulouse","postalCode":"31000","country":"France","phone":"61.77.61.10","fax":"61.77.61.11"},{"id":"LAUGB","companyName":"Laughing Bacchus Wine Cellars","contactName":"Yoshi Tannamuri","contactTitle":"Marketing Assistant","address":"1900 Oak St.","city":"Vancouver","region":"BC","postalCode":"V3F 2K1","country":"Canada","phone":"(604) 555-3392","fax":"(604) 555-7293"},{"id":"LAZYK","companyName":"Lazy K Kountry Store","contactName":"John Steel","contactTitle":"Marketing Manager","address":"12 Orchestra Terrace","city":"Walla Walla","region":"WA","postalCode":"99362","country":"USA","phone":"(509) 555-7969","fax":"(509) 555-6221"},{"id":"LEHMS","companyName":"Lehmanns Marktstand","contactName":"Renate Messner","contactTitle":"Sales Representative","address":"Magazinweg 7","city":"Frankfurt a.M.","postalCode":"60528","country":"Germany","phone":"069-0245984","fax":"069-0245874"},{"id":"LETSS","companyName":"Let's Stop N Shop","contactName":"Jaime Yorres","contactTitle":"Owner","address":"87 Polk St. Suite 5","city":"San Francisco","region":"CA","postalCode":"94117","country":"USA","phone":"(415) 555-5938"},{"id":"LILAS","companyName":"LILA-Supermercado","contactName":"Carlos González","contactTitle":"Accounting Manager","address":"Carrera 52 con Ave. Bolívar #65-98 Llano Largo","city":"Barquisimeto","region":"Lara","postalCode":"3508","country":"Venezuela","phone":"(9) 331-6954","fax":"(9) 331-7256"},{"id":"LINOD","companyName":"LINO-Delicateses","contactName":"Felipe Izquierdo","contactTitle":"Owner","address":"Ave. 5 de Mayo Porlamar","city":"I. de Margarita","region":"Nueva Esparta","postalCode":"4980","country":"Venezuela","phone":"(8) 34-56-12","fax":"(8) 34-93-93"},{"id":"LONEP","companyName":"Lonesome Pine Restaurant","contactName":"Fran Wilson","contactTitle":"Sales Manager","address":"89 Chiaroscuro Rd.","city":"Portland","region":"OR","postalCode":"97219","country":"USA","phone":"(503) 555-9573","fax":"(503) 555-9646"},{"id":"MAGAA","companyName":"Magazzini Alimentari Riuniti","contactName":"Giovanni Rovelli","contactTitle":"Marketing Manager","address":"Via Ludovico il Moro 22","city":"Bergamo","postalCode":"24100","country":"Italy","phone":"035-640230","fax":"035-640231"},{"id":"MAISD","companyName":"Maison Dewey","contactName":"Catherine Dewey","contactTitle":"Sales Agent","address":"Rue Joseph-Bens 532","city":"Bruxelles","postalCode":"B-1180","country":"Belgium","phone":"(02) 201 24 67","fax":"(02) 201 24 68"},{"id":"MEREP","companyName":"Mère Paillarde","contactName":"Jean Fresnière","contactTitle":"Marketing Assistant","address":"43 rue St. Laurent","city":"Montréal","region":"Québec","postalCode":"H1J 1C3","country":"Canada","phone":"(514) 555-8054","fax":"(514) 555-8055"},{"id":"MORGK","companyName":"Morgenstern Gesundkost","contactName":"Alexander Feuer","contactTitle":"Marketing Assistant","address":"Heerstr. 22","city":"Leipzig","postalCode":"04179","country":"Germany","phone":"0342-023176"},{"id":"NORTS","companyName":"North/South","contactName":"Simon Crowther","contactTitle":"Sales Associate","address":"South House 300 Queensbridge","city":"London","postalCode":"SW7 1RZ","country":"UK","phone":"(171) 555-7733","fax":"(171) 555-2530"},{"id":"OCEAN","companyName":"Océano Atlántico Ltda.","contactName":"Yvonne Moncada","contactTitle":"Sales Agent","address":"Ing. Gustavo Moncada 8585 Piso 20-A","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 135-5333","fax":"(1) 135-5535"},{"id":"OLDWO","companyName":"Old World Delicatessen","contactName":"Rene Phillips","contactTitle":"Sales Representative","address":"2743 Bering St.","city":"Anchorage","region":"AK","postalCode":"99508","country":"USA","phone":"(907) 555-7584","fax":"(907) 555-2880"},{"id":"OTTIK","companyName":"Ottilies Käseladen","contactName":"Henriette Pfalzheim","contactTitle":"Owner","address":"Mehrheimerstr. 369","city":"Köln","postalCode":"50739","country":"Germany","phone":"0221-0644327","fax":"0221-0765721"},{"id":"PARIS","companyName":"Paris spécialités","contactName":"Marie Bertrand","contactTitle":"Owner","address":"265, boulevard Charonne","city":"Paris","postalCode":"75012","country":"France","phone":"(1) 42.34.22.66","fax":"(1) 42.34.22.77"},{"id":"PERIC","companyName":"Pericles Comidas clásicas","contactName":"Guillermo Fernández","contactTitle":"Sales Representative","address":"Calle Dr. Jorge Cash 321","city":"México D.F.","postalCode":"05033","country":"Mexico","phone":"(5) 552-3745","fax":"(5) 545-3745"},{"id":"PICCO","companyName":"Piccolo und mehr","contactName":"Georg Pipps","contactTitle":"Sales Manager","address":"Geislweg 14","city":"Salzburg","postalCode":"5020","country":"Austria","phone":"6562-9722","fax":"6562-9723"},{"id":"PRINI","companyName":"Princesa Isabel Vinhos","contactName":"Isabel de Castro","contactTitle":"Sales Representative","address":"Estrada da saúde n. 58","city":"Lisboa","postalCode":"1756","country":"Portugal","phone":"(1) 356-5634"},{"id":"QUEDE","companyName":"Que Delícia","contactName":"Bernardo Batista","contactTitle":"Accounting Manager","address":"Rua da Panificadora, 12","city":"Rio de Janeiro","region":"RJ","postalCode":"02389-673","country":"Brazil","phone":"(21) 555-4252","fax":"(21) 555-4545"},{"id":"QUEEN","companyName":"Queen Cozinha","contactName":"Lúcia Carvalho","contactTitle":"Marketing Assistant","address":"Alameda dos Canàrios, 891","city":"Sao Paulo","region":"SP","postalCode":"05487-020","country":"Brazil","phone":"(11) 555-1189"},{"id":"QUICK","companyName":"QUICK-Stop","contactName":"Horst Kloss","contactTitle":"Accounting Manager","address":"Taucherstraße 10","city":"Cunewalde","postalCode":"01307","country":"Germany","phone":"0372-035188"},{"id":"RANCH","companyName":"Rancho grande","contactName":"Sergio Gutiérrez","contactTitle":"Sales Representative","address":"Av. del Libertador 900","city":"Buenos Aires","postalCode":"1010","country":"Argentina","phone":"(1) 123-5555","fax":"(1) 123-5556"},{"id":"RATTC","companyName":"Rattlesnake Canyon Grocery","contactName":"Paula Wilson","contactTitle":"Assistant Sales Representative","address":"2817 Milton Dr.","city":"Albuquerque","region":"NM","postalCode":"87110","country":"USA","phone":"(505) 555-5939","fax":"(505) 555-3620"},{"id":"REGGC","companyName":"Reggiani Caseifici","contactName":"Maurizio Moroni","contactTitle":"Sales Associate","address":"Strada Provinciale 124","city":"Reggio Emilia","postalCode":"42100","country":"Italy","phone":"0522-556721","fax":"0522-556722"},{"id":"RICAR","companyName":"Ricardo Adocicados","contactName":"Janete Limeira","contactTitle":"Assistant Sales Agent","address":"Av. Copacabana, 267","city":"Rio de Janeiro","region":"RJ","postalCode":"02389-890","country":"Brazil","phone":"(21) 555-3412"},{"id":"RICSU","companyName":"Richter Supermarkt","contactName":"Michael Holz","contactTitle":"Sales Manager","address":"Grenzacherweg 237","city":"Genève","postalCode":"1203","country":"Switzerland","phone":"0897-034214"},{"id":"ROMEY","companyName":"Romero y tomillo","contactName":"Alejandra Camino","contactTitle":"Accounting Manager","address":"Gran Vía, 1","city":"Madrid","postalCode":"28001","country":"Spain","phone":"(91) 745 6200","fax":"(91) 745 6210"},{"id":"SANTG","companyName":"Santé Gourmet","contactName":"Jonas Bergulfsen","contactTitle":"Owner","address":"Erling Skakkes gate 78","city":"Stavern","postalCode":"4110","country":"Norway","phone":"07-98 92 35","fax":"07-98 92 47"},{"id":"SAVEA","companyName":"Save-a-lot Markets","contactName":"Jose Pavarotti","contactTitle":"Sales Representative","address":"187 Suffolk Ln.","city":"Boise","region":"ID","postalCode":"83720","country":"USA","phone":"(208) 555-8097"},{"id":"SEVES","companyName":"Seven Seas Imports","contactName":"Hari Kumar","contactTitle":"Sales Manager","address":"90 Wadhurst Rd.","city":"London","postalCode":"OX15 4NB","country":"UK","phone":"(171) 555-1717","fax":"(171) 555-5646"},{"id":"SIMOB","companyName":"Simons bistro","contactName":"Jytte Petersen","contactTitle":"Owner","address":"Vinbæltet 34","city":"Kobenhavn","postalCode":"1734","country":"Denmark","phone":"31 12 34 56","fax":"31 13 35 57"},{"id":"SPECD","companyName":"Spécialités du monde","contactName":"Dominique Perrier","contactTitle":"Marketing Manager","address":"25, rue Lauriston","city":"Paris","postalCode":"75016","country":"France","phone":"(1) 47.55.60.10","fax":"(1) 47.55.60.20"},{"id":"SPLIR","companyName":"Split Rail Beer & Ale","contactName":"Art Braunschweiger","contactTitle":"Sales Manager","address":"P.O. Box 555","city":"Lander","region":"WY","postalCode":"82520","country":"USA","phone":"(307) 555-4680","fax":"(307) 555-6525"},{"id":"SUPRD","companyName":"Suprêmes délices","contactName":"Pascale Cartrain","contactTitle":"Accounting Manager","address":"Boulevard Tirou, 255","city":"Charleroi","postalCode":"B-6000","country":"Belgium","phone":"(071) 23 67 22 20","fax":"(071) 23 67 22 21"},{"id":"THEBI","companyName":"The Big Cheese","contactName":"Liz Nixon","contactTitle":"Marketing Manager","address":"89 Jefferson Way Suite 2","city":"Portland","region":"OR","postalCode":"97201","country":"USA","phone":"(503) 555-3612"},{"id":"THECR","companyName":"The Cracker Box","contactName":"Liu Wong","contactTitle":"Marketing Assistant","address":"55 Grizzly Peak Rd.","city":"Butte","region":"MT","postalCode":"59801","country":"USA","phone":"(406) 555-5834","fax":"(406) 555-8083"},{"id":"TOMSP","companyName":"Toms Spezialitäten","contactName":"Karin Josephs","contactTitle":"Marketing Manager","address":"Luisenstr. 48","city":"Münster","postalCode":"44087","country":"Germany","phone":"0251-031259","fax":"0251-035695"},{"id":"TORTU","companyName":"Tortuga Restaurante","contactName":"Miguel Angel Paolino","contactTitle":"Owner","address":"Avda. Azteca 123","city":"México D.F.","postalCode":"05033","country":"Mexico","phone":"(5) 555-2933"},{"id":"TRADH","companyName":"Tradição Hipermercados","contactName":"Anabela Domingues","contactTitle":"Sales Representative","address":"Av. Inês de Castro, 414","city":"Sao Paulo","region":"SP","postalCode":"05634-030","country":"Brazil","phone":"(11) 555-2167","fax":"(11) 555-2168"},{"id":"TRAIH","companyName":"Trail's Head Gourmet Provisioners","contactName":"Helvetius Nagy","contactTitle":"Sales Associate","address":"722 DaVinci Blvd.","city":"Kirkland","region":"WA","postalCode":"98034","country":"USA","phone":"(206) 555-8257","fax":"(206) 555-2174"},{"id":"VAFFE","companyName":"Vaffeljernet","contactName":"Palle Ibsen","contactTitle":"Sales Manager","address":"Smagsloget 45","city":"Århus","postalCode":"8200","country":"Denmark","phone":"86 21 32 43","fax":"86 22 33 44"},{"id":"VICTE","companyName":"Victuailles en stock","contactName":"Mary Saveley","contactTitle":"Sales Agent","address":"2, rue du Commerce","city":"Lyon","postalCode":"69004","country":"France","phone":"78.32.54.86","fax":"78.32.54.87"},{"id":"VINET","companyName":"Vins et alcools Chevalier","contactName":"Paul Henriot","contactTitle":"Accounting Manager","address":"59 rue de l'Abbaye","city":"Reims","postalCode":"51100","country":"France","phone":"26.47.15.10","fax":"26.47.15.11"},{"id":"WANDK","companyName":"Die Wandernde Kuh","contactName":"Rita Müller","contactTitle":"Sales Representative","address":"Adenauerallee 900","city":"Stuttgart","postalCode":"70563","country":"Germany","phone":"0711-020361","fax":"0711-035428"},{"id":"WARTH","companyName":"Wartian Herkku","contactName":"Pirkko Koskitalo","contactTitle":"Accounting Manager","address":"Torikatu 38","city":"Oulu","postalCode":"90110","country":"Finland","phone":"981-443655","fax":"981-443655"},{"id":"WELLI","companyName":"Wellington Importadora","contactName":"Paula Parente","contactTitle":"Sales Manager","address":"Rua do Mercado, 12","city":"Resende","region":"SP","postalCode":"08737-363","country":"Brazil","phone":"(14) 555-8122"},{"id":"WHITC","companyName":"White Clover Markets","contactName":"Karl Jablonski","contactTitle":"Owner","address":"305 - 14th Ave. S. Suite 3B","city":"Seattle","region":"WA","postalCode":"98128","country":"USA","phone":"(206) 555-4112","fax":"(206) 555-4115"},{"id":"WILMK","companyName":"Wilman Kala","contactName":"Matti Karttunen","contactTitle":"Owner/Marketing Assistant","address":"Keskuskatu 45","city":"Helsinki","postalCode":"21240","country":"Finland","phone":"90-224 8858","fax":"90-224 8858"},{"id":"WOLZA","companyName":"Wolski Zajazd","contactName":"Zbyszek Piestrzeniewicz","contactTitle":"Owner","address":"ul. Filtrowa 68","city":"Warszawa","postalCode":"01-012","country":"Poland","phone":"(26) 642-7012","fax":"(26) 642-7012"}],"responseStatus":{}}
--------------------------------------------------------------------------------
/shopping-cart/client/assets/desserts.json:
--------------------------------------------------------------------------------
1 | {
2 | "count": 9,
3 | "data": [
4 | {
5 | "name": "Frozen yogurt",
6 | "type": "Ice cream",
7 | "calories": { "value": 159.0 },
8 | "fat": { "value": 6.0 },
9 | "carbs": { "value": 24.0 },
10 | "protein": { "value": 4.0 },
11 | "sodium": { "value": 87.0 },
12 | "calcium": { "value": 14.0 },
13 | "iron": { "value": 1.0 },
14 | "comment": "Not as good as the real thing."
15 | }, {
16 | "name": "Ice cream sandwich",
17 | "type": "Ice cream",
18 | "calories": { "value": 237.0 },
19 | "fat": { "value": 9.0 },
20 | "carbs": { "value": 37.0 },
21 | "protein": { "value": 4.3 },
22 | "sodium": { "value": 129.0 },
23 | "calcium": { "value": 8.0 },
24 | "iron": { "value": 1.0 }
25 | }, {
26 | "name": "Eclair",
27 | "type": "Pastry",
28 | "calories": { "value": 262.0 },
29 | "fat": { "value": 16.0 },
30 | "carbs": { "value": 24.0 },
31 | "protein": { "value": 6.0 },
32 | "sodium": { "value": 337.0 },
33 | "calcium": { "value": 6.0 },
34 | "iron": { "value": 7.0 }
35 | }, {
36 | "name": "Cupcake",
37 | "type": "Pastry",
38 | "calories": { "value": 305.0 },
39 | "fat": { "value": 3.7 },
40 | "carbs": { "value": 67.0 },
41 | "protein": { "value": 4.3 },
42 | "sodium": { "value": 413.0 },
43 | "calcium": { "value": 3.0 },
44 | "iron": { "value": 8.0 }
45 | }, {
46 | "name": "Jelly bean",
47 | "type": "Candy",
48 | "calories": { "value": 375.0 },
49 | "fat": { "value": 0.0 },
50 | "carbs": { "value": 94.0 },
51 | "protein": { "value": 0.0 },
52 | "sodium": { "value": 50.0 },
53 | "calcium": { "value": 0.0 },
54 | "iron": { "value": 0.0 }
55 | }, {
56 | "name": "Lollipop",
57 | "type": "Candy",
58 | "calories": { "value": 392.0 },
59 | "fat": { "value": 0.2 },
60 | "carbs": { "value": 98.0 },
61 | "protein": { "value": 0.0 },
62 | "sodium": { "value": 38.0 },
63 | "calcium": { "value": 0.0 },
64 | "iron": { "value": 2.0 }
65 | }, {
66 | "name": "Honeycomb",
67 | "type": "Other",
68 | "calories": { "value": 408.0 },
69 | "fat": { "value": 3.2 },
70 | "carbs": { "value": 87.0 },
71 | "protein": { "value": 6.5 },
72 | "sodium": { "value": 562.0 },
73 | "calcium": { "value": 0.0 },
74 | "iron": { "value": 45.0 }
75 | }, {
76 | "name": "Donut",
77 | "type": "Pastry",
78 | "calories": { "value": 452.0 },
79 | "fat": { "value": 25.0 },
80 | "carbs": { "value": 51.0 },
81 | "protein": { "value": 4.9 },
82 | "sodium": { "value": 326.0 },
83 | "calcium": { "value": 2.0 },
84 | "iron": { "value": 22.0 }
85 | }, {
86 | "name": "KitKat",
87 | "type": "Candy",
88 | "calories": { "value": 518.0 },
89 | "fat": { "value": 26.0 },
90 | "carbs": { "value": 65.0 },
91 | "protein": { "value": 7.0 },
92 | "sodium": { "value": 54.0 },
93 | "calcium": { "value": 12.0 },
94 | "iron": { "value": 6.0 }
95 | }
96 | ]
97 | }
--------------------------------------------------------------------------------
/shopping-cart/client/assets/shopping-cart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/assets/shopping-cart.png
--------------------------------------------------------------------------------
/shopping-cart/client/css/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/css/favicon.ico
--------------------------------------------------------------------------------
/shopping-cart/client/css/material-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/css/material-icons.woff2
--------------------------------------------------------------------------------
/shopping-cart/client/css/style.css:
--------------------------------------------------------------------------------
1 | [ng-cloak] {
2 | display: none !important;
3 | }
4 |
5 | @font-face {
6 | font-family: 'Material Icons';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url(./material-icons.woff2) format('woff2');
10 | }
11 |
12 | .material-icons {
13 | font-family: 'Material Icons';
14 | font-weight: normal;
15 | font-style: normal;
16 | font-size: 24px;
17 | line-height: 1;
18 | letter-spacing: normal;
19 | text-transform: none;
20 | display: inline-block;
21 | white-space: nowrap;
22 | word-wrap: normal;
23 | direction: ltr;
24 | font-feature-settings: 'liga';
25 | -webkit-font-feature-settings: 'liga';
26 | -webkit-font-smoothing: antialiased;
27 | }
28 |
29 | [ng-cloak] {
30 | display: none !important;
31 | }
32 |
33 | .splash {
34 | display: none;
35 | }
36 |
37 | [ng-cloak].splash {
38 | display: block !important;
39 | }
40 |
41 | .md-sidenav-left, md-sidenav {
42 | top: 71px;
43 | border-radius: 4px;
44 | }
45 |
46 | md-sidenav {
47 | max-width: 240px;
48 | }
49 |
50 | md-toolbar:not(.md-menu-toolbar) {
51 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12);
52 | }
53 |
54 | md-backdrop.md-opaque {
55 | opacity: 0;
56 | }
57 |
58 | md-toolbar.md-tall {
59 | height: 0px;
60 | min-height: 0px;
61 | max-height: 0px;
62 | }
63 |
64 | .pages-sidenav {
65 | height: 100%;
66 | padding-left: 16%;
67 | transition-duration: 0.6s;
68 | -webkit-transition-duration: 0.6s;
69 | }
70 |
71 | .submenus-text {
72 | padding-left: 2px;
73 | font-size: 14px;
74 | }
75 |
76 | md-list-item .md-list-item-inner {
77 | border-bottom: 0.2px solid;
78 | }
79 |
80 | #main {
81 | box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12);
82 | }
83 |
84 | .home-title {
85 | padding-left: 30px;
86 | }
87 | /**** Accordion Style ***********/
88 |
89 | .md-subheader .md-subheader-inner {
90 | padding: 10px !important;
91 | cursor: pointer;
92 | }
93 | .md-accordion {
94 | padding: 2px;
95 | }
96 | md-list-item {
97 | color: rgba(0,0,0,0.54);
98 | }
99 | .md-accordion .expandCollapse {
100 | width:30px;
101 | height:30px;
102 | position:relative;
103 | font-size:16px;
104 | font-weight:bold;
105 | cursor:pointer;
106 | color:#9999;
107 | display:block;
108 | margin-top: -2px;
109 | margin-left: -2px;
110 | overflow: hidden;
111 | float: right;
112 | }
113 | .md-accordion .expandCollapse:active {
114 | border:0px;
115 | }
116 | .md-accordion .expandCollapse:before, .md-accordion .expandCollapse:after {
117 | width:30px;
118 | height:30px;
119 | display:block;
120 | position:absolute;
121 | top:0; left:0;
122 | line-height:32px;
123 | text-align:center;
124 | -webkit-transition: .3s all ease-out;
125 | transition: .3s all ease-out;
126 | }
127 | .md-accordion .expandCollapse:before {
128 | opacity:1;
129 | -webkit-transform: rotate(0deg);
130 | transform: rotate(0deg);
131 | content: "|";
132 | margin-top:-3px;
133 | }
134 | .md-accordion .expandCollapse:after {
135 | opacity:1;
136 | -webkit-transform: rotate(-90deg);
137 | transform: rotate(-90deg);
138 | content: "|";
139 | margin-left:-3px;
140 | }
141 | .md-accordion .active:before {
142 | opacity:1;
143 | -webkit-transform: rotate(90deg);
144 | transform: rotate(90deg);
145 | margin-left:3px;
146 | margin-top:0px;
147 | }
148 |
149 | .md-accordion .dataContent {
150 | background: #F2F2F2;
151 | height: 0px;
152 | overflow: hidden;
153 | transition: .3s all ease-out;
154 | -webkit-transition: .3s all ease-out;
155 | }
156 |
157 | .md-accordion .activeContent {
158 | height: auto;
159 | padding-top: 0px;
160 | display: block;
161 | transition: .3s all ease-out;
162 | }
163 |
164 | .md-accordion md-toolbar{
165 | cursor:pointer;
166 | border-bottom: 1px solid rgb(63,107,181)
167 | }
168 | md-list-item._md-button-wrap>div.md-button:first-child {
169 | padding: 0 10px;
170 | }
171 |
172 | .product-continer {
173 | padding: 6px 2px 0 0;
174 | border-radius: 4px;
175 | margin-bottom: 100px;
176 | }
177 | .product-add {
178 | height: auto;
179 | border: 1px solid rgba(0,0,0,0.07);
180 | transition: .3s all ease-out;
181 | }
182 | .ng-hide {
183 | height: 0;
184 | }
185 | /** Add Product **/
186 | .inputdemoErrors .inputErrorsApp {
187 | min-height: 48px; }
188 |
189 | .inputdemoErrors md-input-container > p {
190 | font-size: 0.8em;
191 | text-align: left;
192 | width: 100%;
193 | }
194 | #input-file-id {
195 | opacity: 1;
196 | width: 200px;
197 | height: 200px;
198 | border: 1px solid rgba(0,0,0,.14);
199 | background-color: rgba(0,0,0,.02);
200 |
201 | }
202 |
203 | #input-file-id:before {
204 | content: '';
205 | }
206 |
207 | .custom-file-input::-webkit-file-upload-button {
208 | visibility: hidden;
209 | }
210 | .custom-file-input::before {
211 | content: 'Browse';
212 | background: linear-gradient(top, #f9f9f9, #e3e3e3);
213 | border: 1px solid #999;
214 | border-radius: 3px;
215 | padding: 8px 26px 5px 26px;
216 | outline: none;
217 | white-space: nowrap;
218 | -webkit-user-select: none;
219 | cursor: pointer;
220 | text-shadow: 1px 1px #fff;
221 | font-size: 14px;
222 | color: #999;
223 | }
224 | .custom-file-input:hover::before {
225 | border-color: #999;
226 | }
227 | .custom-file-input:active::before {
228 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9);
229 | }
230 |
231 | .md-block {
232 | margin: 12px;
233 | }
234 |
--------------------------------------------------------------------------------
/shopping-cart/client/js/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const app = angular.module('app', ['ngRoute', 'ngAnimate', 'ngAria', 'md.data.table', 'ngMaterial']);
4 |
5 | /*
6 | * Theme Settings
7 | */
8 | app.config(['$mdThemingProvider', function ($mdThemingProvider) {
9 | $mdThemingProvider.theme("blue")
10 | .primaryPalette("blue")
11 | .accentPalette("red");
12 |
13 | $mdThemingProvider.theme("green")
14 | .primaryPalette("teal")
15 | .accentPalette("red");
16 |
17 | $mdThemingProvider.theme("altTheme")
18 | .primaryPalette("purple")
19 | .accentPalette("green");
20 |
21 | $mdThemingProvider.alwaysWatchTheme(true);
22 | }]);
23 |
24 | /*
25 | * configuring our routes for the app
26 | */
27 | app.config(function ($routeProvider, $locationProvider) {
28 | $routeProvider
29 | // route for the home page
30 |
31 | .when('/home', {
32 | templateUrl: '/views/pages/home.html',
33 | controller: 'homeController'
34 | })
35 | .when('/products', {
36 | templateUrl: '/views/pages/products.html',
37 | controller: 'productsController'
38 | })
39 | .otherwise({
40 | redirectTo: '/home'
41 | });
42 |
43 | // use the HTML5 History API
44 | $locationProvider.html5Mode(true);
45 | });
46 |
47 | app.config(
48 | function($mdIconProvider, $$mdSvgRegistry) {
49 | // Add default icons from angular material
50 | $mdIconProvider
51 | .icon('md-close', $$mdSvgRegistry.mdClose)
52 | .icon('md-menu', $$mdSvgRegistry.mdMenu)
53 | .icon('md-toggle-arrow', $$mdSvgRegistry.mdToggleArrow) ;
54 | }
55 | );
56 |
57 | app.factory('appService', ($http) => {
58 | return new AppService($http)
59 | });
60 |
--------------------------------------------------------------------------------
/shopping-cart/client/js/app.service.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | class AppService{
4 | constructor($http){
5 | this.$http = $http;
6 | this.socket = null;
7 | }
8 | httpCall(httpData){
9 | if (httpData.url === undefined || httpData.url === null || httpData.url === ''){
10 | alert(`Invalid HTTP call`);
11 | }
12 | const HTTP = this.$http;
13 | const params = httpData.params;
14 | return new Promise( (resolve, reject) => {
15 | HTTP.post(httpData.url, params).then( (response) => {
16 | resolve(response.data);
17 | }).catch( (response, status, header, config) => {
18 | reject(response.data);
19 | });
20 | });
21 | }
22 | connectSocketServer(userId){
23 | const socket = io.connect( { query: `userId=${userId}` });
24 | this.socket = socket;
25 | }
26 |
27 | socketEmit(eventName, params){
28 | this.socket.emit(eventName, params);
29 | }
30 |
31 | socketOn(eventName, callback) {
32 | this.socket.on(eventName, (response) => {
33 | if (callback) {
34 | callback(response);
35 | }
36 | });
37 | }
38 |
39 | getMessages(userId, friendId) {
40 | return new Promise((resolve, reject) => {
41 | this.httpCall({
42 | url: '/getMessages',
43 | params: {
44 | 'userId': userId,
45 | 'toUserId': friendId
46 | }
47 | }).then((response) => {
48 | resolve(response);
49 | }).catch((error) => {
50 | reject(error);
51 | });
52 | });
53 | }
54 |
55 | scrollToBottom(){
56 | const messageThread = document.querySelector('.message-thread');
57 | setTimeout(() => {
58 | messageThread.scrollTop = messageThread.scrollHeight + 500;
59 | }, 10);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/shopping-cart/client/js/home.controller.js:
--------------------------------------------------------------------------------
1 | 'user strict';
2 |
3 | app.controller('homeController', function ($scope, $routeParams, $location, appService, $mdSidenav){
4 |
5 | console.log('HomeController');
6 | });
--------------------------------------------------------------------------------
/shopping-cart/client/js/menu.controller.js:
--------------------------------------------------------------------------------
1 | 'user strict';
2 |
3 | app.controller('menuController', function ($scope, $routeParams, $location, $mdSidenav){
4 |
5 | console.log('menuController');
6 | $scope.project_name = 'Shopping Cart';
7 | $scope.currentTheme = "green";
8 |
9 | $scope.$on('$viewContentLoaded', () => {
10 | document.getElementById('pages').classList.add('pages-sidenav');
11 | $scope.openNav();
12 | });
13 |
14 | /** Sidebar Menu **/
15 | $scope.menus = [
16 | {
17 | title: 'Dashboard',
18 | icon: 'dashboard',
19 | active: false,
20 | path: 'dashboard'
21 | },
22 | {
23 | title: 'Products',
24 | icon: 'pages',
25 | active: false,
26 | type: 'dropdown',
27 | submenus: [
28 | {
29 | title: 'Products',
30 | icon: 'radio_button_checked',
31 | path: 'products'
32 | },
33 | {
34 | title: 'Out Of Stock',
35 | icon: 'radio_button_checked',
36 | path: 'out-of-stock'
37 | },
38 | {
39 | title: 'Expired Products',
40 | icon: 'radio_button_checked',
41 | path: 'expired-products'
42 | },
43 | {
44 | title: 'Products Tax',
45 | icon: 'radio_button_checked',
46 | path: 'products-tax'
47 | },
48 | {
49 | title: 'Products Categories',
50 | icon: 'radio_button_checked',
51 | path: 'products-categories'
52 | }
53 | ]
54 | },
55 | {
56 | title: 'Warehouses',
57 | icon: 'store',
58 | active: false,
59 | path: 'warehouses'
60 | },
61 | {
62 | title: 'Suppliers',
63 | icon: 'people_outline',
64 | active: false,
65 | path: 'suppliers'
66 | },
67 | {
68 | title: 'Purchases',
69 | icon: 'shopping_cart',
70 | active: false,
71 | type: 'dropdown',
72 | submenus: [
73 | {
74 | title: 'New Purchases',
75 | icon: 'radio_button_checked',
76 | path: 'new-purchases'
77 | },
78 | {
79 | title: 'Purchase List',
80 | icon: 'radio_button_checked',
81 | path: 'purchase-list'
82 | }
83 | ]
84 | },
85 | {
86 | title: 'Customers',
87 | icon: 'people',
88 | active: false,
89 | path: 'customers'
90 | },
91 | {
92 | title: 'Companies',
93 | icon: 'shop',
94 | active: false,
95 | path: 'companies'
96 | },
97 | {
98 | title: 'Sales Order',
99 | icon: 'add_shopping_cart',
100 | active: false,
101 | type: 'dropdown',
102 | submenus: [
103 | {
104 | title: 'Manage Orders',
105 | icon: 'radio_button_checked',
106 | path: 'manage-orders'
107 | },
108 | {
109 | title: 'Add New Order',
110 | icon: 'radio_button_checked',
111 | path: 'add-new-order'
112 | },
113 | {
114 | title: 'Order Quotes',
115 | icon: 'radio_button_checked',
116 | path: 'order-quotes'
117 | },
118 | {
119 | title: 'Add Order Quote',
120 | icon: 'radio_button_checked',
121 | path: 'add-order-quote'
122 | }
123 | ]
124 | },
125 | {
126 | title: 'Calendar',
127 | icon: 'calendar_today',
128 | active: false,
129 | path: 'calendar'
130 | },
131 | {
132 | title: 'Expenditure',
133 | icon: 'attach_money',
134 | active: false,
135 | path: 'expenditure'
136 | },
137 | {
138 | title: 'Reports',
139 | icon: 'bar_chart',
140 | active: false,
141 | type: 'dropdown',
142 | submenus: [
143 | {
144 | title: 'Today Reports',
145 | icon: 'radio_button_checked',
146 | path: 'today-reports'
147 | },
148 | {
149 | title: 'Purchase Report',
150 | icon: 'radio_button_checked',
151 | path: 'purchase-report'
152 | },
153 | {
154 | title: 'Sales Report',
155 | icon: 'radio_button_checked',
156 | path: 'sales-report'
157 | }
158 | ]
159 | },
160 | {
161 | title: 'System',
162 | icon: 'settings',
163 | active: false,
164 | type: 'dropdown',
165 | submenus: [
166 | {
167 | title: 'Multi Language',
168 | icon: 'radio_button_checked',
169 | path: 'multi-language'
170 | },
171 | {
172 | title: 'Settings',
173 | icon: 'radio_button_checked',
174 | path: 'Settings'
175 | },
176 | {
177 | title: 'Payment Gateway',
178 | icon: 'radio_button_checked',
179 | path: 'payment-gateway'
180 | },
181 | {
182 | title: 'Theme Settings',
183 | icon: 'radio_button_checked',
184 | path: 'theme-settings'
185 | },
186 | {
187 | title: 'Constants',
188 | icon: 'radio_button_checked',
189 | path: 'constants'
190 | },
191 | {
192 | title: 'Database Backup',
193 | icon: 'radio_button_checked',
194 | path: 'database-backup'
195 | },
196 | {
197 | title: 'Email Templates',
198 | icon: 'radio_button_checked',
199 | path: 'email-templates'
200 | },
201 | {
202 | title: 'Staff',
203 | icon: 'radio_button_checked',
204 | path: 'staff'
205 | },
206 | {
207 | title: 'Staff Roles & Privileges',
208 | icon: 'radio_button_checked',
209 | path: 'staff-roles-privileges'
210 | },
211 | {
212 | title: 'Transactions Log',
213 | icon: 'radio_button_checked',
214 | path: 'transactions-log'
215 | }
216 | ]
217 | },
218 | {
219 | title: 'Logout',
220 | icon: 'power_settings_new',
221 | active: false,
222 | path: 'Logout'
223 | }
224 | ];
225 |
226 | $scope.sideNav = () => {
227 | document.getElementById('pages').classList.toggle('pages-sidenav');
228 | }
229 |
230 | $scope.toggleNav = () => {
231 | $mdSidenav("left").toggle();
232 | }
233 |
234 | $scope.openNav = () => {
235 | $mdSidenav("left").open();
236 | }
237 |
238 | $scope.closeNav = () => {
239 | $mdSidenav("left").close();
240 | }
241 |
242 | $scope.goTo = (link) => {
243 | $mdSidenav("left").open();
244 | $location.path(link);
245 | }
246 |
247 | // Menu Toggle
248 | $scope.collapseAll = function(data) {
249 | for(var i in $scope.menus) {
250 | if($scope.menus[i] != data) {
251 | $scope.menus[i].expanded = false;
252 | }
253 | }
254 | data.expanded = !data.expanded;
255 | };
256 | });
257 |
--------------------------------------------------------------------------------
/shopping-cart/client/js/products.controller.js:
--------------------------------------------------------------------------------
1 | 'user strict';
2 |
3 | // File Upload Directive
4 | app.directive('fileModel', ['$parse', function ($parse) {
5 | return {
6 | restrict: 'A',
7 | link: function(scope, element, attrs) {
8 | var model = $parse(attrs.fileModel);
9 | var modelSetter = model.assign;
10 |
11 | element.bind('change', function(){
12 | scope.$apply(function(){
13 | modelSetter(scope, element[0].files[0]);
14 | });
15 | });
16 | }
17 | };
18 | }]);
19 |
20 | // File Upload Service
21 | app.service('multipartForm', ['$http', function ($http) {
22 | this.post = function(uploadUrl, data) {
23 | var fd = new FormData();
24 | for(var key in data) {
25 | fd.append(key, data[key]);
26 | }
27 |
28 | $http.post(uploadUrl, fd, {
29 | transformRequest: angular.identity,
30 | headers: {'Content-Type': undefined}
31 | }).then(function (httpResponse) {
32 | console.log('multipartForm Response:', httpResponse);
33 | });
34 | }
35 | }]);
36 |
37 | app.controller('productsController', function ($http, $mdEditDialog, $q, $timeout, $scope, multipartForm){
38 |
39 | $scope.options = {
40 | rowSelection: true,
41 | multiSelect: true,
42 | autoSelect: true,
43 | decapitate: false,
44 | largeEditDialog: false,
45 | boundaryLinks: false,
46 | limitSelect: true,
47 | pageSelect: true
48 | };
49 |
50 | $scope.IsVisible = false;
51 | $scope.selected = [];
52 | $scope.product = {};
53 | $scope.limitOptions = [5, 10, 15, {
54 | label: 'All',
55 | value: function () {
56 | return $scope.products ? $scope.products.count : 0;
57 | }
58 | }];
59 |
60 | $scope.query = {
61 | order: 'product_name',
62 | limit: 10,
63 | page: 1
64 | };
65 |
66 | $http.post('/getProducts').then(function (products) {
67 | $scope.products = products.data;
68 | console.log($scope.products);
69 | });
70 |
71 | $scope.toggleLimitOptions = function () {
72 | $scope.limitOptions = $scope.limitOptions ? undefined : [5, 10, 15];
73 | };
74 |
75 | $scope.onPaginate = function(page, limit) {
76 | console.log('Scope Page: ' + $scope.query.page + ' Scope Limit: ' + $scope.query.limit);
77 | console.log('Page: ' + page + ' Limit: ' + limit);
78 |
79 | $scope.promise = $timeout(function () {
80 |
81 | }, 2000);
82 | };
83 |
84 | $scope.deselect = function (item) {
85 | console.log(item.name, 'was deselected');
86 | };
87 |
88 | $scope.log = function (item) {
89 | console.log(item.name, 'was selected');
90 | };
91 |
92 | $scope.loadStuff = function () {
93 | $scope.promise = $timeout(function () {
94 |
95 | }, 2000);
96 | };
97 |
98 | $scope.onReorder = function(order) {
99 |
100 | console.log('Scope Order: ' + $scope.query.order);
101 | console.log('Order: ' + order);
102 |
103 | $scope.promise = $timeout(function () {
104 |
105 | }, 2000);
106 | };
107 |
108 | $scope.addProduct = function() {
109 | $scope.IsVisible = $scope.IsVisible ? false : true;
110 | }
111 |
112 | // Image Preview
113 | $scope.SelectFile = function (e) {
114 | var reader = new FileReader();
115 | reader.onload = function (e) {
116 | $scope.PreviewImage = e.target.result;
117 | $scope.$apply();
118 | };
119 |
120 | reader.readAsDataURL(e.target.files[0]);
121 | };
122 |
123 | // Add Product
124 | $scope.submit= function(){
125 |
126 | // File Upload Service
127 | const uploadUrl = "/addProducts";
128 | multipartForm.post(uploadUrl, $scope.product);
129 | }
130 |
131 | });
--------------------------------------------------------------------------------
/shopping-cart/client/uploads/img-2852020-1590684956674.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/uploads/img-2852020-1590684956674.jpg
--------------------------------------------------------------------------------
/shopping-cart/client/uploads/iphone-11-pro-27-5-2020-1590551435418.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learning-zone/angularjs-basics/da8615b11345e50068001be41609c70433705bf6/shopping-cart/client/uploads/iphone-11-pro-27-5-2020-1590551435418.jpg
--------------------------------------------------------------------------------
/shopping-cart/client/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Shopping Cart
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | menu
58 |
59 |
{{project_name}}
60 |
61 |
62 |
63 |
64 |
65 | Loading...
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/shopping-cart/client/views/pages/home.html:
--------------------------------------------------------------------------------
1 | Home Page
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/shopping-cart/client/views/pages/products.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Product Details
6 |
7 |
8 | playlist_add
9 |
10 |
11 | refresh
12 |
13 |
14 | filter_list
15 |
16 |
17 | more_vert
18 |
19 |
20 |
21 |
22 |
23 |
120 |
121 |
122 |
123 |
124 | {{selected.length}} {{selected.length > 1 ? 'items' : 'item'}} selected
125 |
126 |
127 | delete
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | Action |
137 | Image |
138 | Name |
139 | Warehouse |
140 | Quantity |
141 | Barcode |
142 | Purchase Price |
143 | Selling Price |
144 | Category |
145 |
146 |
147 |
148 |
149 |
150 | edit |
151 | ![]() |
152 | {{product.product_name}} |
153 | {{product.wharehouse_id}} |
154 | {{product.quantity}} |
155 | {{product.barcode}} |
156 | {{product.purchase_price}} |
157 | {{product.selling_price}} |
158 | {{product.category_id}} |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/shopping-cart/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shopping-cart",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.4",
9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
10 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
11 | "requires": {
12 | "mime-types": "~2.1.16",
13 | "negotiator": "0.6.1"
14 | }
15 | },
16 | "after": {
17 | "version": "0.8.2",
18 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
19 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
20 | },
21 | "append-field": {
22 | "version": "1.0.0",
23 | "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
24 | "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY="
25 | },
26 | "array-flatten": {
27 | "version": "1.1.1",
28 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
29 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
30 | },
31 | "arraybuffer.slice": {
32 | "version": "0.0.7",
33 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
34 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
35 | },
36 | "async-limiter": {
37 | "version": "1.0.0",
38 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
39 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
40 | },
41 | "backo2": {
42 | "version": "1.0.2",
43 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
44 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
45 | },
46 | "base64-arraybuffer": {
47 | "version": "0.1.5",
48 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
49 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
50 | },
51 | "base64id": {
52 | "version": "1.0.0",
53 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
54 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
55 | },
56 | "better-assert": {
57 | "version": "1.0.2",
58 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
59 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
60 | "requires": {
61 | "callsite": "1.0.0"
62 | }
63 | },
64 | "bignumber.js": {
65 | "version": "4.0.4",
66 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz",
67 | "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg=="
68 | },
69 | "blob": {
70 | "version": "0.0.4",
71 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
72 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE="
73 | },
74 | "body-parser": {
75 | "version": "1.18.2",
76 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
77 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
78 | "requires": {
79 | "bytes": "3.0.0",
80 | "content-type": "~1.0.4",
81 | "debug": "2.6.9",
82 | "depd": "~1.1.1",
83 | "http-errors": "~1.6.2",
84 | "iconv-lite": "0.4.19",
85 | "on-finished": "~2.3.0",
86 | "qs": "6.5.1",
87 | "raw-body": "2.3.2",
88 | "type-is": "~1.6.15"
89 | }
90 | },
91 | "buffer-from": {
92 | "version": "1.1.1",
93 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
94 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
95 | },
96 | "busboy": {
97 | "version": "0.2.14",
98 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
99 | "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
100 | "requires": {
101 | "dicer": "0.2.5",
102 | "readable-stream": "1.1.x"
103 | },
104 | "dependencies": {
105 | "isarray": {
106 | "version": "0.0.1",
107 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
108 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
109 | },
110 | "readable-stream": {
111 | "version": "1.1.14",
112 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
113 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
114 | "requires": {
115 | "core-util-is": "~1.0.0",
116 | "inherits": "~2.0.1",
117 | "isarray": "0.0.1",
118 | "string_decoder": "~0.10.x"
119 | }
120 | },
121 | "string_decoder": {
122 | "version": "0.10.31",
123 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
124 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
125 | }
126 | }
127 | },
128 | "bytes": {
129 | "version": "3.0.0",
130 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
131 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
132 | },
133 | "callsite": {
134 | "version": "1.0.0",
135 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
136 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
137 | },
138 | "component-bind": {
139 | "version": "1.0.0",
140 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
141 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
142 | },
143 | "component-emitter": {
144 | "version": "1.2.1",
145 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
146 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
147 | },
148 | "component-inherit": {
149 | "version": "0.0.3",
150 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
151 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
152 | },
153 | "concat-stream": {
154 | "version": "1.6.2",
155 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
156 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
157 | "requires": {
158 | "buffer-from": "^1.0.0",
159 | "inherits": "^2.0.3",
160 | "readable-stream": "^2.2.2",
161 | "typedarray": "^0.0.6"
162 | }
163 | },
164 | "content-disposition": {
165 | "version": "0.5.2",
166 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
167 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
168 | },
169 | "content-type": {
170 | "version": "1.0.4",
171 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
172 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
173 | },
174 | "cookie": {
175 | "version": "0.3.1",
176 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
177 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
178 | },
179 | "cookie-signature": {
180 | "version": "1.0.6",
181 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
182 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
183 | },
184 | "core-util-is": {
185 | "version": "1.0.2",
186 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
187 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
188 | },
189 | "debug": {
190 | "version": "2.6.9",
191 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
192 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
193 | "requires": {
194 | "ms": "2.0.0"
195 | }
196 | },
197 | "depd": {
198 | "version": "1.1.2",
199 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
200 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
201 | },
202 | "destroy": {
203 | "version": "1.0.4",
204 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
205 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
206 | },
207 | "dicer": {
208 | "version": "0.2.5",
209 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
210 | "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
211 | "requires": {
212 | "readable-stream": "1.1.x",
213 | "streamsearch": "0.1.2"
214 | },
215 | "dependencies": {
216 | "isarray": {
217 | "version": "0.0.1",
218 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
219 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
220 | },
221 | "readable-stream": {
222 | "version": "1.1.14",
223 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
224 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
225 | "requires": {
226 | "core-util-is": "~1.0.0",
227 | "inherits": "~2.0.1",
228 | "isarray": "0.0.1",
229 | "string_decoder": "~0.10.x"
230 | }
231 | },
232 | "string_decoder": {
233 | "version": "0.10.31",
234 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
235 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
236 | }
237 | }
238 | },
239 | "ee-first": {
240 | "version": "1.1.1",
241 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
242 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
243 | },
244 | "encodeurl": {
245 | "version": "1.0.1",
246 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
247 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
248 | },
249 | "engine.io": {
250 | "version": "3.1.4",
251 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz",
252 | "integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=",
253 | "requires": {
254 | "accepts": "1.3.3",
255 | "base64id": "1.0.0",
256 | "cookie": "0.3.1",
257 | "debug": "~2.6.9",
258 | "engine.io-parser": "~2.1.0",
259 | "uws": "~0.14.4",
260 | "ws": "~3.3.1"
261 | },
262 | "dependencies": {
263 | "accepts": {
264 | "version": "1.3.3",
265 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
266 | "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
267 | "requires": {
268 | "mime-types": "~2.1.11",
269 | "negotiator": "0.6.1"
270 | }
271 | }
272 | }
273 | },
274 | "engine.io-client": {
275 | "version": "3.1.4",
276 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz",
277 | "integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=",
278 | "requires": {
279 | "component-emitter": "1.2.1",
280 | "component-inherit": "0.0.3",
281 | "debug": "~2.6.9",
282 | "engine.io-parser": "~2.1.1",
283 | "has-cors": "1.1.0",
284 | "indexof": "0.0.1",
285 | "parseqs": "0.0.5",
286 | "parseuri": "0.0.5",
287 | "ws": "~3.3.1",
288 | "xmlhttprequest-ssl": "~1.5.4",
289 | "yeast": "0.1.2"
290 | }
291 | },
292 | "engine.io-parser": {
293 | "version": "2.1.2",
294 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz",
295 | "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==",
296 | "requires": {
297 | "after": "0.8.2",
298 | "arraybuffer.slice": "~0.0.7",
299 | "base64-arraybuffer": "0.1.5",
300 | "blob": "0.0.4",
301 | "has-binary2": "~1.0.2"
302 | }
303 | },
304 | "escape-html": {
305 | "version": "1.0.3",
306 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
307 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
308 | },
309 | "etag": {
310 | "version": "1.8.1",
311 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
312 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
313 | },
314 | "express": {
315 | "version": "4.16.2",
316 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
317 | "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=",
318 | "requires": {
319 | "accepts": "~1.3.4",
320 | "array-flatten": "1.1.1",
321 | "body-parser": "1.18.2",
322 | "content-disposition": "0.5.2",
323 | "content-type": "~1.0.4",
324 | "cookie": "0.3.1",
325 | "cookie-signature": "1.0.6",
326 | "debug": "2.6.9",
327 | "depd": "~1.1.1",
328 | "encodeurl": "~1.0.1",
329 | "escape-html": "~1.0.3",
330 | "etag": "~1.8.1",
331 | "finalhandler": "1.1.0",
332 | "fresh": "0.5.2",
333 | "merge-descriptors": "1.0.1",
334 | "methods": "~1.1.2",
335 | "on-finished": "~2.3.0",
336 | "parseurl": "~1.3.2",
337 | "path-to-regexp": "0.1.7",
338 | "proxy-addr": "~2.0.2",
339 | "qs": "6.5.1",
340 | "range-parser": "~1.2.0",
341 | "safe-buffer": "5.1.1",
342 | "send": "0.16.1",
343 | "serve-static": "1.13.1",
344 | "setprototypeof": "1.1.0",
345 | "statuses": "~1.3.1",
346 | "type-is": "~1.6.15",
347 | "utils-merge": "1.0.1",
348 | "vary": "~1.1.2"
349 | },
350 | "dependencies": {
351 | "setprototypeof": {
352 | "version": "1.1.0",
353 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
354 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
355 | },
356 | "statuses": {
357 | "version": "1.3.1",
358 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
359 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
360 | }
361 | }
362 | },
363 | "finalhandler": {
364 | "version": "1.1.0",
365 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
366 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
367 | "requires": {
368 | "debug": "2.6.9",
369 | "encodeurl": "~1.0.1",
370 | "escape-html": "~1.0.3",
371 | "on-finished": "~2.3.0",
372 | "parseurl": "~1.3.2",
373 | "statuses": "~1.3.1",
374 | "unpipe": "~1.0.0"
375 | },
376 | "dependencies": {
377 | "statuses": {
378 | "version": "1.3.1",
379 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
380 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
381 | }
382 | }
383 | },
384 | "forwarded": {
385 | "version": "0.1.2",
386 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
387 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
388 | },
389 | "fresh": {
390 | "version": "0.5.2",
391 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
392 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
393 | },
394 | "fs": {
395 | "version": "0.0.1-security",
396 | "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
397 | "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
398 | },
399 | "has-binary2": {
400 | "version": "1.0.2",
401 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz",
402 | "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=",
403 | "requires": {
404 | "isarray": "2.0.1"
405 | },
406 | "dependencies": {
407 | "isarray": {
408 | "version": "2.0.1",
409 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
410 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
411 | }
412 | }
413 | },
414 | "has-cors": {
415 | "version": "1.1.0",
416 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
417 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
418 | },
419 | "http": {
420 | "version": "0.0.1-security",
421 | "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz",
422 | "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g=="
423 | },
424 | "http-errors": {
425 | "version": "1.6.2",
426 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
427 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
428 | "requires": {
429 | "depd": "1.1.1",
430 | "inherits": "2.0.3",
431 | "setprototypeof": "1.0.3",
432 | "statuses": ">= 1.3.1 < 2"
433 | },
434 | "dependencies": {
435 | "depd": {
436 | "version": "1.1.1",
437 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
438 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
439 | }
440 | }
441 | },
442 | "iconv-lite": {
443 | "version": "0.4.19",
444 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
445 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
446 | },
447 | "indexof": {
448 | "version": "0.0.1",
449 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
450 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
451 | },
452 | "inherits": {
453 | "version": "2.0.3",
454 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
455 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
456 | },
457 | "ipaddr.js": {
458 | "version": "1.5.2",
459 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
460 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
461 | },
462 | "isarray": {
463 | "version": "1.0.0",
464 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
465 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
466 | },
467 | "media-typer": {
468 | "version": "0.3.0",
469 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
470 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
471 | },
472 | "merge-descriptors": {
473 | "version": "1.0.1",
474 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
475 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
476 | },
477 | "methods": {
478 | "version": "1.1.2",
479 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
480 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
481 | },
482 | "mime": {
483 | "version": "1.4.1",
484 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
485 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
486 | },
487 | "mime-db": {
488 | "version": "1.30.0",
489 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
490 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
491 | },
492 | "mime-types": {
493 | "version": "2.1.17",
494 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
495 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
496 | "requires": {
497 | "mime-db": "~1.30.0"
498 | }
499 | },
500 | "minimist": {
501 | "version": "1.2.5",
502 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
503 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
504 | },
505 | "mkdirp": {
506 | "version": "0.5.5",
507 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
508 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
509 | "requires": {
510 | "minimist": "^1.2.5"
511 | }
512 | },
513 | "ms": {
514 | "version": "2.0.0",
515 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
516 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
517 | },
518 | "multer": {
519 | "version": "1.4.2",
520 | "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz",
521 | "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==",
522 | "requires": {
523 | "append-field": "^1.0.0",
524 | "busboy": "^0.2.11",
525 | "concat-stream": "^1.5.2",
526 | "mkdirp": "^0.5.1",
527 | "object-assign": "^4.1.1",
528 | "on-finished": "^2.3.0",
529 | "type-is": "^1.6.4",
530 | "xtend": "^4.0.0"
531 | }
532 | },
533 | "mysql": {
534 | "version": "2.15.0",
535 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz",
536 | "integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==",
537 | "requires": {
538 | "bignumber.js": "4.0.4",
539 | "readable-stream": "2.3.3",
540 | "safe-buffer": "5.1.1",
541 | "sqlstring": "2.3.0"
542 | }
543 | },
544 | "negotiator": {
545 | "version": "0.6.1",
546 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
547 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
548 | },
549 | "object-assign": {
550 | "version": "4.1.1",
551 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
552 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
553 | },
554 | "object-component": {
555 | "version": "0.0.3",
556 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
557 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
558 | },
559 | "on-finished": {
560 | "version": "2.3.0",
561 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
562 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
563 | "requires": {
564 | "ee-first": "1.1.1"
565 | }
566 | },
567 | "parseqs": {
568 | "version": "0.0.5",
569 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
570 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
571 | "requires": {
572 | "better-assert": "~1.0.0"
573 | }
574 | },
575 | "parseuri": {
576 | "version": "0.0.5",
577 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
578 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
579 | "requires": {
580 | "better-assert": "~1.0.0"
581 | }
582 | },
583 | "parseurl": {
584 | "version": "1.3.2",
585 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
586 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
587 | },
588 | "path": {
589 | "version": "0.12.7",
590 | "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
591 | "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
592 | "requires": {
593 | "process": "^0.11.1",
594 | "util": "^0.10.3"
595 | }
596 | },
597 | "path-to-regexp": {
598 | "version": "0.1.7",
599 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
600 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
601 | },
602 | "process": {
603 | "version": "0.11.10",
604 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
605 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
606 | },
607 | "process-nextick-args": {
608 | "version": "1.0.7",
609 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
610 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
611 | },
612 | "proxy-addr": {
613 | "version": "2.0.2",
614 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
615 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=",
616 | "requires": {
617 | "forwarded": "~0.1.2",
618 | "ipaddr.js": "1.5.2"
619 | }
620 | },
621 | "qs": {
622 | "version": "6.5.1",
623 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
624 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
625 | },
626 | "range-parser": {
627 | "version": "1.2.0",
628 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
629 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
630 | },
631 | "raw-body": {
632 | "version": "2.3.2",
633 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
634 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
635 | "requires": {
636 | "bytes": "3.0.0",
637 | "http-errors": "1.6.2",
638 | "iconv-lite": "0.4.19",
639 | "unpipe": "1.0.0"
640 | }
641 | },
642 | "readable-stream": {
643 | "version": "2.3.3",
644 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
645 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
646 | "requires": {
647 | "core-util-is": "~1.0.0",
648 | "inherits": "~2.0.3",
649 | "isarray": "~1.0.0",
650 | "process-nextick-args": "~1.0.6",
651 | "safe-buffer": "~5.1.1",
652 | "string_decoder": "~1.0.3",
653 | "util-deprecate": "~1.0.1"
654 | }
655 | },
656 | "safe-buffer": {
657 | "version": "5.1.1",
658 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
659 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
660 | },
661 | "send": {
662 | "version": "0.16.1",
663 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
664 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==",
665 | "requires": {
666 | "debug": "2.6.9",
667 | "depd": "~1.1.1",
668 | "destroy": "~1.0.4",
669 | "encodeurl": "~1.0.1",
670 | "escape-html": "~1.0.3",
671 | "etag": "~1.8.1",
672 | "fresh": "0.5.2",
673 | "http-errors": "~1.6.2",
674 | "mime": "1.4.1",
675 | "ms": "2.0.0",
676 | "on-finished": "~2.3.0",
677 | "range-parser": "~1.2.0",
678 | "statuses": "~1.3.1"
679 | },
680 | "dependencies": {
681 | "statuses": {
682 | "version": "1.3.1",
683 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
684 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
685 | }
686 | }
687 | },
688 | "serve-static": {
689 | "version": "1.13.1",
690 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
691 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
692 | "requires": {
693 | "encodeurl": "~1.0.1",
694 | "escape-html": "~1.0.3",
695 | "parseurl": "~1.3.2",
696 | "send": "0.16.1"
697 | }
698 | },
699 | "setprototypeof": {
700 | "version": "1.0.3",
701 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
702 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
703 | },
704 | "socket.io": {
705 | "version": "2.0.4",
706 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz",
707 | "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=",
708 | "requires": {
709 | "debug": "~2.6.6",
710 | "engine.io": "~3.1.0",
711 | "socket.io-adapter": "~1.1.0",
712 | "socket.io-client": "2.0.4",
713 | "socket.io-parser": "~3.1.1"
714 | }
715 | },
716 | "socket.io-adapter": {
717 | "version": "1.1.1",
718 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
719 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
720 | },
721 | "socket.io-client": {
722 | "version": "2.0.4",
723 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz",
724 | "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=",
725 | "requires": {
726 | "backo2": "1.0.2",
727 | "base64-arraybuffer": "0.1.5",
728 | "component-bind": "1.0.0",
729 | "component-emitter": "1.2.1",
730 | "debug": "~2.6.4",
731 | "engine.io-client": "~3.1.0",
732 | "has-cors": "1.1.0",
733 | "indexof": "0.0.1",
734 | "object-component": "0.0.3",
735 | "parseqs": "0.0.5",
736 | "parseuri": "0.0.5",
737 | "socket.io-parser": "~3.1.1",
738 | "to-array": "0.1.4"
739 | }
740 | },
741 | "socket.io-parser": {
742 | "version": "3.1.2",
743 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz",
744 | "integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=",
745 | "requires": {
746 | "component-emitter": "1.2.1",
747 | "debug": "~2.6.4",
748 | "has-binary2": "~1.0.2",
749 | "isarray": "2.0.1"
750 | },
751 | "dependencies": {
752 | "isarray": {
753 | "version": "2.0.1",
754 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
755 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
756 | }
757 | }
758 | },
759 | "sqlstring": {
760 | "version": "2.3.0",
761 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz",
762 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg="
763 | },
764 | "statuses": {
765 | "version": "1.4.0",
766 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
767 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
768 | },
769 | "streamsearch": {
770 | "version": "0.1.2",
771 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
772 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
773 | },
774 | "string_decoder": {
775 | "version": "1.0.3",
776 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
777 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
778 | "requires": {
779 | "safe-buffer": "~5.1.0"
780 | }
781 | },
782 | "to-array": {
783 | "version": "0.1.4",
784 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
785 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
786 | },
787 | "type-is": {
788 | "version": "1.6.15",
789 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
790 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
791 | "requires": {
792 | "media-typer": "0.3.0",
793 | "mime-types": "~2.1.15"
794 | }
795 | },
796 | "typedarray": {
797 | "version": "0.0.6",
798 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
799 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
800 | },
801 | "ultron": {
802 | "version": "1.1.1",
803 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
804 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
805 | },
806 | "unpipe": {
807 | "version": "1.0.0",
808 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
809 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
810 | },
811 | "util": {
812 | "version": "0.10.4",
813 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
814 | "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
815 | "requires": {
816 | "inherits": "2.0.3"
817 | }
818 | },
819 | "util-deprecate": {
820 | "version": "1.0.2",
821 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
822 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
823 | },
824 | "utils-merge": {
825 | "version": "1.0.1",
826 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
827 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
828 | },
829 | "uws": {
830 | "version": "0.14.5",
831 | "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz",
832 | "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=",
833 | "optional": true
834 | },
835 | "vary": {
836 | "version": "1.1.2",
837 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
838 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
839 | },
840 | "ws": {
841 | "version": "3.3.3",
842 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
843 | "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
844 | "requires": {
845 | "async-limiter": "~1.0.0",
846 | "safe-buffer": "~5.1.0",
847 | "ultron": "~1.1.0"
848 | }
849 | },
850 | "xmlhttprequest-ssl": {
851 | "version": "1.5.5",
852 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
853 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
854 | },
855 | "xtend": {
856 | "version": "4.0.2",
857 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
858 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
859 | },
860 | "yeast": {
861 | "version": "0.1.2",
862 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
863 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
864 | }
865 | }
866 | }
867 |
--------------------------------------------------------------------------------
/shopping-cart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shopping-cart",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "node server.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "body-parser": "^1.18.2",
14 | "express": "^4.16.2",
15 | "fs": "0.0.1-security",
16 | "http": "0.0.1-security",
17 | "multer": "^1.4.2",
18 | "mysql": "^2.15.0",
19 | "path": "^0.12.7",
20 | "socket.io": "^2.0.4"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/shopping-cart/server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const express = require("express");
4 | const http = require('http');
5 | const socketio = require('socket.io');
6 | const bodyParser = require('body-parser');
7 |
8 | const socketEvents = require('./utils/socket');
9 | const routes = require('./utils/routes');
10 | const config = require('./utils/config');
11 |
12 |
13 | class Server{
14 |
15 | constructor(){
16 | this.port = process.env.PORT || 3000;
17 | this.host = `localhost`;
18 |
19 | this.app = express();
20 | this.http = http.Server(this.app);
21 | this.socket = socketio(this.http);
22 | }
23 |
24 | appConfig(){
25 | this.app.use(
26 | bodyParser.json()
27 | );
28 | new config(this.app);
29 | }
30 |
31 | /* Including app Routes starts*/
32 | includeRoutes(){
33 | new routes(this.app).routesConfig();
34 | new socketEvents(this.socket).socketConfig();
35 | }
36 | /* Including app Routes ends*/
37 |
38 | appExecute(){
39 |
40 | this.appConfig();
41 | this.includeRoutes();
42 |
43 | this.http.listen(this.port, this.host, () => {
44 | console.log(`Listening on http://${this.host}:${this.port}`);
45 | });
46 | }
47 |
48 | }
49 |
50 | const app = new Server();
51 | app.appExecute();
--------------------------------------------------------------------------------
/shopping-cart/utils/config.js:
--------------------------------------------------------------------------------
1 | class Config{
2 |
3 | constructor(app){
4 | // Setting .html as the default template extension
5 | app.set('view engine', 'html');
6 |
7 | // Telling express where it can find the templates
8 | app.set('views', (__dirname + '/../views'));
9 |
10 | //Files
11 | app.use(require('express').static(require('path').join('client')));
12 |
13 | }
14 | }
15 | module.exports = Config;
--------------------------------------------------------------------------------
/shopping-cart/utils/db.js:
--------------------------------------------------------------------------------
1 | const mysql = require('mysql');
2 |
3 | class Db {
4 | constructor(config) {
5 | this.connection = mysql.createPool({
6 | connectionLimit: 100,
7 | host: '127.0.0.1',
8 | user: 'root',
9 | password: 'root',
10 | database: 'learning_zone',
11 | debug: false
12 | });
13 | }
14 | query(sql, args) {
15 | return new Promise((resolve, reject) => {
16 | this.connection.query(sql, args, (err, rows) => {
17 | if (err)
18 | return reject(err);
19 | resolve(rows);
20 | });
21 | });
22 | }
23 | close() {
24 | return new Promise((resolve, reject) => {
25 | this.connection.end(err => {
26 | if (err)
27 | return reject(err);
28 | resolve();
29 | });
30 | });
31 | }
32 | }
33 | module.exports = new Db();
--------------------------------------------------------------------------------
/shopping-cart/utils/helper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const DB = require('./db');
3 |
4 | class Helper{
5 |
6 | constructor(app){
7 | this.db = DB;
8 | }
9 |
10 | async userNameCheck (username){
11 | return await this.db.query(`SELECT count(username) as count FROM users WHERE LOWER(username) = ?`, `${username}`);
12 | }
13 |
14 | async registerUser(params){
15 | try {
16 | return await this.db.query("INSERT INTO users (`username`,`password`,`online`) VALUES (?,?,?)", [params['username'],params['password'],'Y']);
17 | } catch (error) {
18 | console.error(error);
19 | return null;
20 | }
21 | }
22 |
23 | async loginUser(params){
24 | try {
25 | return await this.db.query(`SELECT id FROM users WHERE LOWER(username) = ? AND password = ?`, [params.username,params.password]);
26 | } catch (error) {
27 | return null;
28 | }
29 | }
30 |
31 | async userSessionCheck(userId){
32 | try {
33 | const result = await this.db.query(`SELECT online,username FROM user WHERE id = ? AND online = ?`, [userId,'Y']);
34 | if(result !== null){
35 | return result[0]['username'];
36 | }else{
37 | return null;
38 | }
39 | } catch (error) {
40 | return null;
41 | }
42 | }
43 |
44 | async addSocketId(userId, userSocketId){
45 | try {
46 | return await this.db.query(`UPDATE users SET socketid = ?, online= ? WHERE id = ?`, [userSocketId,'Y',userId]);
47 | } catch (error) {
48 | console.log(error);
49 | return null;
50 | }
51 | }
52 |
53 | async isUserLoggedOut(userSocketId){
54 | try {
55 | return await this.db.query(`SELECT online FROM users WHERE socketid = ?`, [userSocketId]);
56 | } catch (error) {
57 | return null;
58 | }
59 | }
60 |
61 | async logoutUser(userSocketId){
62 | return await this.db.query(`UPDATE users SET socketid = ?, online= ? WHERE socketid = ?`, ['','N',userSocketId]);
63 | }
64 |
65 | getChatList(userId, userSocketId){
66 | try {
67 | return Promise.all([
68 | this.db.query(`SELECT id,username,online,socketid FROM users WHERE id = ?`, [userId]),
69 | this.db.query(`SELECT id,username,online,socketid FROM users WHERE online = ? and socketid != ?`, ['Y',userSocketId])
70 | ]).then( (response) => {
71 | return {
72 | userinfo : response[0].length > 0 ? response[0][0] : response[0],
73 | chatlist : response[1]
74 | };
75 | }).catch( (error) => {
76 | console.warn(error);
77 | return (null);
78 | });
79 | } catch (error) {
80 | console.warn(error);
81 | return null;
82 | }
83 | }
84 |
85 | async insertMessages(params){
86 | try {
87 | return await this.db.query(
88 | "INSERT INTO message (`from_user_id`,`to_user_id`,`message`) values (?,?,?)",
89 | [params.fromUserId, params.toUserId, params.message]
90 | );
91 | } catch (error) {
92 | console.warn(error);
93 | return null;
94 | }
95 | }
96 |
97 | async getMessages(userId, toUserId){
98 | try {
99 | return await this.db.query(
100 | `SELECT id,from_user_id as fromUserId,to_user_id as toUserId,message FROM message WHERE
101 | (from_user_id = ? AND to_user_id = ? )
102 | OR
103 | (from_user_id = ? AND to_user_id = ? ) ORDER BY id ASC
104 | `,
105 | [userId, toUserId, toUserId, userId]
106 | );
107 | } catch (error) {
108 | console.warn(error);
109 | return null;
110 | }
111 | }
112 | }
113 | module.exports = new Helper();
--------------------------------------------------------------------------------
/shopping-cart/utils/product.js:
--------------------------------------------------------------------------------
1 | 'user strict';
2 | const DB = require('./db');
3 |
4 | class Product{
5 |
6 | constructor(app){
7 | this.db = DB;
8 | }
9 |
10 | // Get All Products
11 | async getProducts(userId, toUserId){
12 | try {
13 | return await this.db.query(
14 | `SELECT * FROM product ORDER BY id ASC`
15 | );
16 | } catch (error) {
17 | console.warn(error);
18 | return null;
19 | }
20 | }
21 |
22 | // Add Product
23 | async addProducts(params){
24 |
25 | let insert_statement = "INSERT INTO `product` (`product_name`, `product_description`, `sku`, `serial_number`, `purchase_price`, `selling_price`, `quantity`, `barcode`, `reordered_stock_amount`, `product_image`, `category_id`, `wharehouse_id`) VALUES ( ? )";
26 | let values = [
27 | params['product_name'], params['product_description'], params['sku'], params['serial_number'], params['purchase_price'],
28 | params['selling_price'], params['quantity'], params['barcode'], params['reordered_stock_amount'], params['product_image'],
29 | params['category'], params['warehouse']
30 | ];
31 |
32 | console.log("insert_statement: "+insert_statement);
33 | console.log("values: "+values);
34 | try {
35 | return await this.db.query(insert_statement, [values]);
36 | } catch (error) {
37 | console.error(error);
38 | return null;
39 | }
40 | }
41 | }
42 | module.exports = new Product();
--------------------------------------------------------------------------------
/shopping-cart/utils/routes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const helper = require('./helper');
4 | const product = require('./product');
5 | const path = require('path');
6 | const multer = require('multer');
7 |
8 | class Routes{
9 |
10 | constructor(app){
11 |
12 | this.app = app;
13 | }
14 |
15 | appRoutes(){
16 | this.app.post('/usernameCheck',async (request,response) =>{
17 | const username = request.body.username;
18 | if (username === "" || username === undefined || username === null) {
19 | response.status(412).json({
20 | error : true,
21 | message : `username cant be empty.`
22 | });
23 | } else {
24 | const data = await helper.userNameCheck(username.toLowerCase());
25 | if (data[0]['count'] > 0) {
26 | response.status(401).json({
27 | error:true,
28 | message: 'This username is alreday taken.'
29 | });
30 | } else {
31 | response.status(200).json({
32 | error:false,
33 | message: 'This username is available.'
34 | });
35 | }
36 | }
37 | });
38 |
39 | this.app.post('/registerUser', async (request,response) => {
40 | const registrationResponse = {}
41 | const data = {
42 | username : (request.body.username).toLowerCase(),
43 | password : request.body.password
44 | };
45 | if(data.username === '') {
46 | registrationResponse.error = true;
47 | registrationResponse.message = `username cant be empty.`;
48 | response.status(412).json(registrationResponse);
49 | }else if(data.password === ''){
50 | registrationResponse.error = true;
51 | registrationResponse.message = `password cant be empty.`;
52 | response.status(412).json(registrationResponse);
53 | }else{
54 | const result = await helper.registerUser( data );
55 | if (result === null) {
56 | registrationResponse.error = true;
57 | registrationResponse.message = `User registration unsuccessful,try after some time.`;
58 | response.status(417).json(registrationResponse);
59 | } else {
60 | registrationResponse.error = false;
61 | registrationResponse.userId = result.insertId;
62 | registrationResponse.message = `User registration successful.`;
63 | response.status(200).json(registrationResponse);
64 | }
65 | }
66 | });
67 |
68 | this.app.post('/login',async (request,response) =>{
69 | const loginResponse = {}
70 | const data = {
71 | username : (request.body.username).toLowerCase(),
72 | password : request.body.password
73 | };
74 | if(data.username === '' || data.username === null) {
75 | loginResponse.error = true;
76 | loginResponse.message = `username cant be empty.`;
77 | response.status(412).json(loginResponse);
78 | }else if(data.password === '' || data.password === null){
79 | loginResponse.error = true;
80 | loginResponse.message = `password cant be empty.`;
81 | response.status(412).json(loginResponse);
82 | }else{
83 | const result = await helper.loginUser(data);
84 | if (result === null || result.length === 0) {
85 | loginResponse.error = true;
86 | loginResponse.message = `Invalid username and password combination.`;
87 | response.status(401).json(loginResponse);
88 | } else {
89 | loginResponse.error = false;
90 | loginResponse.userId = result[0].id;
91 | loginResponse.message = `User logged in.`;
92 | response.status(200).json(loginResponse);
93 | }
94 | }
95 | });
96 |
97 | this.app.post('/userSessionCheck', async (request,response) =>{
98 | const userId = request.body.userId;
99 | const sessionCheckResponse = {}
100 | if (userId == '') {
101 | sessionCheckResponse.error = true;
102 | sessionCheckResponse.message = `User Id cant be empty.`;
103 | response.status(412).json(sessionCheckResponse);
104 | }else{
105 | const username = await helper.userSessionCheck(userId);
106 | if (username === null || username === '') {
107 | sessionCheckResponse.error = true;
108 | sessionCheckResponse.message = `User is not logged in.`;
109 | response.status(401).json(sessionCheckResponse);
110 | }else{
111 | sessionCheckResponse.error = false;
112 | sessionCheckResponse.username = username;
113 | sessionCheckResponse.message = `User logged in.`;
114 | response.status(200).json(sessionCheckResponse);
115 | }
116 | }
117 | });
118 |
119 | this.app.post('/getMessages',async (request,response) => {
120 | const userId = request.body.userId;
121 | const toUserId = request.body.toUserId;
122 | const messages = {}
123 | if (userId === '') {
124 | messages.error = true;
125 | messages.message = `userId cant be empty.`;
126 | response.status(200).json(messages);
127 | }else{
128 | const result = await helper.getMessages( userId, toUserId);
129 | if (result === null) {
130 | messages.error = true;
131 | messages.message = `Internal Server error.`;
132 | response.status(500).json(messages);
133 | }else{
134 | messages.error = false;
135 | messages.messages = result;
136 | response.status(200).json(messages);
137 | }
138 | }
139 | });
140 |
141 | /** Get Product Details */
142 | this.app.post('/getProducts',async (request,response) => {
143 | const userId = request.body.userId;
144 | const toUserId = request.body.toUserId;
145 | const products = {}
146 | if (userId === '') {
147 | products.error = true;
148 | products.message = `userId cant be empty.`;
149 | response.status(200).json(products);
150 | }else{
151 | const result = await product.getProducts( userId, toUserId);
152 | if (result === null) {
153 | products.error = true;
154 | products.message = `Internal Server error.`;
155 | response.status(500).json(products);
156 | }else{
157 | products.error = false;
158 | products.products = result;
159 | response.status(200).json(products);
160 | }
161 | }
162 | });
163 |
164 | // File Upload
165 | var storage = multer.diskStorage({
166 | destination: './client/uploads/',
167 | filename: function (request, file, cb) {
168 | var d = new Date();
169 | cb(null, 'img' + '-' + d.getDate() + (d.getMonth()+1) + d.getFullYear() + '-' + Date.now() + path.extname(file.originalname))
170 | }
171 | })
172 |
173 | var upload = multer({ storage: storage });
174 |
175 | // Add Product
176 | this.app.post('/addProducts', upload.single('file'), async (request, response, next) => {
177 |
178 | const userId = request.body.userId;
179 | const toUserId = request.body.toUserId;
180 | const params = request.body;
181 | // File Location
182 | params.product_image = './uploads/' + request.file.filename;
183 |
184 | console.log("Routes request: "+JSON.stringify(params));
185 | console.log("Routes Params: "+JSON.stringify(request.file));
186 |
187 | const products = {}
188 | if (userId === '') {
189 | products.error = true;
190 | products.message = `userId cant be empty.`;
191 | response.status(200).json(products);
192 | }else{
193 | const result = await product.addProducts( params );
194 | if (result === null) {
195 | products.error = true;
196 | products.message = `Internal Server error.`;
197 | response.status(500).json(products);
198 | }else{
199 | products.error = false;
200 | products.products = result;
201 | response.status(200).json(products);
202 | }
203 | }
204 | });
205 |
206 | this.app.get('*',(request,response) =>{
207 | response.sendFile(path.join(__dirname + '../../client/views/index.html'));
208 | /*
209 | * OR one can define the template engine and use response.render();
210 | */
211 | });
212 | }
213 |
214 | routesConfig(){
215 | this.appRoutes();
216 | }
217 | }
218 | module.exports = Routes;
--------------------------------------------------------------------------------
/shopping-cart/utils/socket.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const helper = require('./helper');
5 |
6 | class Socket{
7 |
8 | constructor(socket){
9 | this.io = socket;
10 | }
11 |
12 | socketEvents(){
13 |
14 | this.io.on('connection', (socket) => {
15 |
16 | /**
17 | * get the user's Chat list
18 | */
19 | socket.on('chat-list', async (userId) => {
20 |
21 | let chatListResponse = {};
22 |
23 | if (userId === '' && (typeof userId !== 'string' || typeof userId !== 'number')) {
24 |
25 | chatListResponse.error = true;
26 | chatListResponse.message = `User does not exits.`;
27 |
28 | this.io.emit('chat-list-response',chatListResponse);
29 | }else{
30 | const result = await helper.getChatList(userId, socket.id);
31 | this.io.to(socket.id).emit('chat-list-response', {
32 | error: result !== null ? false : true,
33 | singleUser: false,
34 | chatList: result.chatlist
35 | });
36 |
37 | socket.broadcast.emit('chat-list-response', {
38 | error: result !== null ? false : true,
39 | singleUser: true,
40 | chatList: result.userinfo
41 | });
42 | }
43 | });
44 | /**
45 | * send the messages to the user
46 | */
47 | socket.on('add-message', async (data) => {
48 |
49 | if (data.message === '') {
50 |
51 | this.io.to(socket.id).emit(`add-message-response`,`Message cant be empty`);
52 |
53 | }else if(data.fromUserId === ''){
54 |
55 | this.io.to(socket.id).emit(`add-message-response`,`Unexpected error, Login again.`);
56 |
57 | }else if(data.toUserId === ''){
58 |
59 | this.io.to(socket.id).emit(`add-message-response`,`Select a user to chat.`);
60 |
61 | }else{
62 | let toSocketId = data.toSocketId;
63 | const sqlResult = await helper.insertMessages({
64 | fromUserId: data.fromUserId,
65 | toUserId: data.toUserId,
66 | message: data.message
67 | });
68 | this.io.to(toSocketId).emit(`add-message-response`, data);
69 | }
70 | });
71 |
72 |
73 | /**
74 | * Logout the user
75 | */
76 | socket.on('logout', async () => {
77 | const isLoggedOut = await helper.logoutUser(socket.id);
78 | this.io.to(socket.id).emit('logout-response',{
79 | error : false
80 | });
81 | socket.disconnect();
82 | });
83 |
84 |
85 | /**
86 | * sending the disconnected user to all socket users.
87 | */
88 | socket.on('disconnect',async ()=>{
89 | const isLoggedOut = await helper.logoutUser(socket.id);
90 | setTimeout(async ()=>{
91 | const isLoggedOut = await helper.isUserLoggedOut(socket.id);
92 | if (isLoggedOut && isLoggedOut !== null) {
93 | socket.broadcast.emit('chat-list-response', {
94 | error: false,
95 | userDisconnected: true,
96 | socketId: socket.id
97 | });
98 | }
99 | },1000);
100 | });
101 |
102 | });
103 |
104 | }
105 |
106 | socketConfig(){
107 |
108 | this.io.use( async (socket, next) => {
109 | let userId = socket.request._query['userId'];
110 | let userSocketId = socket.id;
111 | const response = await helper.addSocketId( userId, userSocketId);
112 | if(response && response !== null){
113 | next();
114 | }else{
115 | console.error(`Socket connection failed, for user Id ${userId}.`);
116 | }
117 | });
118 |
119 | this.socketEvents();
120 | }
121 | }
122 | module.exports = Socket;
--------------------------------------------------------------------------------