├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── proxy.conf.json ├── server.js ├── src ├── app │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── communication │ │ ├── emails │ │ │ ├── add-email │ │ │ │ ├── add-email.component.html │ │ │ │ ├── add-email.component.scss │ │ │ │ └── add-email.component.ts │ │ │ ├── conversation │ │ │ │ ├── conversation.component.html │ │ │ │ ├── conversation.component.scss │ │ │ │ └── conversation.component.ts │ │ │ ├── inbox │ │ │ │ ├── inbox.component.html │ │ │ │ ├── inbox.component.scss │ │ │ │ └── inbox.component.ts │ │ │ ├── outbox │ │ │ │ ├── outbox.component.html │ │ │ │ ├── outbox.component.scss │ │ │ │ └── outbox.component.ts │ │ │ └── reply-dialog │ │ │ │ ├── reply-dialog.component.html │ │ │ │ ├── reply-dialog.component.scss │ │ │ │ └── reply-dialog.component.ts │ │ ├── notifications │ │ │ ├── add-notification │ │ │ │ ├── add-notification.component.html │ │ │ │ ├── add-notification.component.scss │ │ │ │ └── add-notification.component.ts │ │ │ ├── notification │ │ │ │ ├── notification.component.html │ │ │ │ ├── notification.component.scss │ │ │ │ └── notification.component.ts │ │ │ └── notifications │ │ │ │ ├── notifications.component.html │ │ │ │ ├── notifications.component.scss │ │ │ │ └── notifications.component.ts │ │ └── suggestions │ │ │ ├── add-suggestion │ │ │ ├── add-suggestion.component.html │ │ │ ├── add-suggestion.component.scss │ │ │ └── add-suggestion.component.ts │ │ │ ├── suggestion │ │ │ ├── suggestion.component.html │ │ │ ├── suggestion.component.scss │ │ │ └── suggestion.component.ts │ │ │ └── suggestions │ │ │ ├── suggestions.component.html │ │ │ ├── suggestions.component.scss │ │ │ └── suggestions.component.ts │ ├── custom │ │ └── error-dialog │ │ │ ├── error-dialog.component.html │ │ │ ├── error-dialog.component.scss │ │ │ └── error-dialog.component.ts │ ├── globals.ts │ ├── interceptor.ts │ ├── material.ts │ ├── pipes │ │ ├── enumeration.pipe.ts │ │ ├── minute-seconds.pipe.ts │ │ ├── no-comma-number.pipe.ts │ │ ├── tasks-doing.pipe.ts │ │ ├── tasks-done.pipe.ts │ │ └── tasks-todo.pipe.ts │ ├── production │ │ ├── finance │ │ │ ├── add-expense-dialog │ │ │ │ ├── add-expense-dialog.component.html │ │ │ │ ├── add-expense-dialog.component.scss │ │ │ │ └── add-expense-dialog.component.ts │ │ │ ├── add-income-dialog │ │ │ │ ├── add-income-dialog.component.html │ │ │ │ ├── add-income-dialog.component.scss │ │ │ │ └── add-income-dialog.component.ts │ │ │ ├── current-report │ │ │ │ ├── current-report.component.html │ │ │ │ ├── current-report.component.scss │ │ │ │ └── current-report.component.ts │ │ │ ├── recalculate-dialog │ │ │ │ ├── recalculate-dialog.component.html │ │ │ │ ├── recalculate-dialog.component.scss │ │ │ │ └── recalculate-dialog.component.ts │ │ │ ├── report │ │ │ │ ├── report.component.html │ │ │ │ ├── report.component.scss │ │ │ │ └── report.component.ts │ │ │ └── reports │ │ │ │ ├── reports.component.html │ │ │ │ ├── reports.component.scss │ │ │ │ └── reports.component.ts │ │ ├── planning │ │ │ ├── planning │ │ │ │ ├── planning.component.html │ │ │ │ ├── planning.component.scss │ │ │ │ └── planning.component.ts │ │ │ ├── show-special-plan-dialog │ │ │ │ ├── show-special-plan-dialog.component.html │ │ │ │ ├── show-special-plan-dialog.component.scss │ │ │ │ └── show-special-plan-dialog.component.ts │ │ │ ├── special-plan-dialog │ │ │ │ ├── special-plan-dialog.component.html │ │ │ │ ├── special-plan-dialog.component.scss │ │ │ │ └── special-plan-dialog.component.ts │ │ │ ├── special-plan-no-date-dialog │ │ │ │ ├── special-plan-no-date-dialog.component.html │ │ │ │ ├── special-plan-no-date-dialog.component.scss │ │ │ │ └── special-plan-no-date-dialog.component.ts │ │ │ ├── special-plans │ │ │ │ ├── special-plans.component.html │ │ │ │ ├── special-plans.component.scss │ │ │ │ └── special-plans.component.ts │ │ │ └── update-daily-plan │ │ │ │ ├── update-daily-plan.component.html │ │ │ │ ├── update-daily-plan.component.scss │ │ │ │ └── update-daily-plan.component.ts │ │ └── tasks │ │ │ ├── add-task │ │ │ ├── add-task.component.html │ │ │ ├── add-task.component.scss │ │ │ └── add-task.component.ts │ │ │ ├── assignment │ │ │ ├── assignment.component.html │ │ │ ├── assignment.component.scss │ │ │ └── assignment.component.ts │ │ │ ├── indicators │ │ │ ├── indicators.component.html │ │ │ ├── indicators.component.scss │ │ │ └── indicators.component.ts │ │ │ ├── kanban │ │ │ ├── kanban.component.html │ │ │ ├── kanban.component.scss │ │ │ └── kanban.component.ts │ │ │ ├── task │ │ │ ├── task.component.html │ │ │ ├── task.component.scss │ │ │ └── task.component.ts │ │ │ └── tasks │ │ │ ├── tasks.component.html │ │ │ ├── tasks.component.scss │ │ │ └── tasks.component.ts │ ├── security │ │ ├── login │ │ │ ├── login.component.html │ │ │ ├── login.component.scss │ │ │ └── login.component.ts │ │ └── validate │ │ │ ├── validate.component.html │ │ │ ├── validate.component.scss │ │ │ └── validate.component.ts │ ├── services │ │ ├── complaint.service.ts │ │ ├── delivery.service.ts │ │ ├── email.service.ts │ │ ├── employee.service.ts │ │ ├── holiday.service.ts │ │ ├── item.service.ts │ │ ├── login.service.ts │ │ ├── notification.service.ts │ │ ├── order.service.ts │ │ ├── planning.service.ts │ │ ├── report.service.ts │ │ ├── return.service.ts │ │ ├── setup.service.ts │ │ ├── suggestion.service.ts │ │ ├── task.service.ts │ │ └── team.service.ts │ ├── setup │ │ ├── setup.component.html │ │ ├── setup.component.scss │ │ └── setup.component.ts │ ├── shop │ │ ├── complaints │ │ │ ├── complaint-resolution-dialog │ │ │ │ ├── complaint-resolution-dialog.component.html │ │ │ │ ├── complaint-resolution-dialog.component.scss │ │ │ │ └── complaint-resolution-dialog.component.ts │ │ │ ├── complaint-status-dialog │ │ │ │ ├── complaint-status-dialog.component.html │ │ │ │ ├── complaint-status-dialog.component.scss │ │ │ │ └── complaint-status-dialog.component.ts │ │ │ ├── complaint │ │ │ │ ├── complaint.component.html │ │ │ │ ├── complaint.component.scss │ │ │ │ └── complaint.component.ts │ │ │ └── complaints │ │ │ │ ├── complaints.component.html │ │ │ │ ├── complaints.component.scss │ │ │ │ └── complaints.component.ts │ │ ├── deliveries │ │ │ ├── add-delivery │ │ │ │ ├── add-delivery.component.html │ │ │ │ ├── add-delivery.component.scss │ │ │ │ └── add-delivery.component.ts │ │ │ ├── deliveries │ │ │ │ ├── deliveries.component.html │ │ │ │ ├── deliveries.component.scss │ │ │ │ └── deliveries.component.ts │ │ │ └── delivery │ │ │ │ ├── delivery.component.html │ │ │ │ ├── delivery.component.scss │ │ │ │ └── delivery.component.ts │ │ ├── items │ │ │ ├── add-item │ │ │ │ ├── add-item.component.html │ │ │ │ ├── add-item.component.scss │ │ │ │ └── add-item.component.ts │ │ │ ├── item │ │ │ │ ├── item.component.html │ │ │ │ ├── item.component.scss │ │ │ │ └── item.component.ts │ │ │ ├── items │ │ │ │ ├── items.component.html │ │ │ │ ├── items.component.scss │ │ │ │ └── items.component.ts │ │ │ ├── new-price-dialog │ │ │ │ ├── new-price-dialog.component.html │ │ │ │ ├── new-price-dialog.component.scss │ │ │ │ └── new-price-dialog.component.ts │ │ │ └── special-offer-dialog │ │ │ │ ├── special-offer-dialog.component.html │ │ │ │ ├── special-offer-dialog.component.scss │ │ │ │ └── special-offer-dialog.component.ts │ │ ├── orders │ │ │ ├── add-order │ │ │ │ ├── add-order.component.html │ │ │ │ ├── add-order.component.scss │ │ │ │ └── add-order.component.ts │ │ │ ├── order-status-dialog │ │ │ │ ├── order-status-dialog.component.html │ │ │ │ ├── order-status-dialog.component.scss │ │ │ │ └── order-status-dialog.component.ts │ │ │ ├── order │ │ │ │ ├── order.component.html │ │ │ │ ├── order.component.scss │ │ │ │ └── order.component.ts │ │ │ └── orders │ │ │ │ ├── orders.component.html │ │ │ │ ├── orders.component.scss │ │ │ │ └── orders.component.ts │ │ └── returns │ │ │ ├── return │ │ │ ├── return.component.html │ │ │ ├── return.component.scss │ │ │ └── return.component.ts │ │ │ ├── returns │ │ │ ├── returns.component.html │ │ │ ├── returns.component.scss │ │ │ └── returns.component.ts │ │ │ └── status-dialog │ │ │ ├── status-dialog.component.html │ │ │ ├── status-dialog.component.scss │ │ │ └── status-dialog.component.ts │ ├── staff │ │ ├── employees │ │ │ ├── add-employee │ │ │ │ ├── add-employee.component.html │ │ │ │ ├── add-employee.component.scss │ │ │ │ └── add-employee.component.ts │ │ │ ├── employee │ │ │ │ ├── employee.component.html │ │ │ │ ├── employee.component.scss │ │ │ │ └── employee.component.ts │ │ │ └── employees │ │ │ │ ├── employees.component.html │ │ │ │ ├── employees.component.scss │ │ │ │ └── employees.component.ts │ │ ├── holidays │ │ │ ├── add-holiday │ │ │ │ ├── add-holiday.component.html │ │ │ │ ├── add-holiday.component.scss │ │ │ │ └── add-holiday.component.ts │ │ │ └── manage-holidays-dialog │ │ │ │ ├── manage-holidays-dialog.component.html │ │ │ │ ├── manage-holidays-dialog.component.scss │ │ │ │ └── manage-holidays-dialog.component.ts │ │ └── teams │ │ │ ├── team │ │ │ ├── team.component.html │ │ │ ├── team.component.scss │ │ │ └── team.component.ts │ │ │ └── teams │ │ │ ├── teams.component.html │ │ │ ├── teams.component.scss │ │ │ └── teams.component.ts │ ├── token.ts │ └── types.ts ├── assets │ └── .gitkeep ├── browserslist ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── styles.scss ├── test.ts ├── theme.scss ├── tsconfig.app.json ├── tsconfig.spec.json ├── tslint.json └── variables.scss ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Joe Kutner 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. -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to erp-mes-frontend!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "erp-mes-frontend", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "node server.js", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "postinstall": "ng build --prod" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "^6.1.9", 16 | "@angular/cdk": "^6.4.7", 17 | "@angular/cli": "~6.0.8", 18 | "@angular/common": "^6.1.9", 19 | "@angular/compiler": "^6.1.9", 20 | "@angular/compiler-cli": "^6.1.9", 21 | "@angular/core": "^6.1.9", 22 | "@angular/flex-layout": "github:angular/flex-layout-builds", 23 | "@angular/forms": "^6.1.9", 24 | "@angular/http": "^6.1.9", 25 | "@angular/material": "^6.4.7", 26 | "@angular/platform-browser": "^6.1.9", 27 | "@angular/platform-browser-dynamic": "^6.1.9", 28 | "@angular/router": "^6.1.9", 29 | "chart.js": "^2.7.3", 30 | "core-js": "^2.5.4", 31 | "express": "^4.16.3", 32 | "hammerjs": "^2.0.8", 33 | "jquery": "^3.3.1", 34 | "net": "^1.0.2", 35 | "rxjs": "^6.3.3", 36 | "sockjs-client": "^1.3.0", 37 | "stompjs": "^2.3.3", 38 | "typescript": "~2.7.2", 39 | "zone.js": "^0.8.26" 40 | }, 41 | "devDependencies": { 42 | "@angular-devkit/build-angular": "^0.11.3", 43 | "@angular/language-service": "^6.1.9", 44 | "@types/jasmine": "^2.8.9", 45 | "@types/jasminewd2": "^2.0.5", 46 | "@types/node": "~8.9.4", 47 | "codelyzer": "~4.2.1", 48 | "jasmine-core": "~2.99.1", 49 | "jasmine-spec-reporter": "~4.2.1", 50 | "karma": "~1.7.1", 51 | "karma-chrome-launcher": "~2.2.0", 52 | "karma-coverage-istanbul-reporter": "^2.0.4", 53 | "karma-jasmine": "~1.1.1", 54 | "karma-jasmine-html-reporter": "^0.2.2", 55 | "protractor": "^5.4.1", 56 | "ts-node": "~5.0.1", 57 | "tslint": "~5.9.1" 58 | }, 59 | "engines": { 60 | "node": "8.11.3", 61 | "npm": "5.6.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/": { 3 | "target": "http://localhost:8080", 4 | "secure": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'), 2 | path = require('path'); 3 | 4 | const app = express(); 5 | 6 | app.use(express.static('./dist/erp-mes-frontend')); 7 | 8 | app.get('/*', (req, res) => { 9 | res.sendFile(path.join(__dirname, '/dist/erp-mes-frontend/index.html')); 10 | }); 11 | 12 | app.listen(process.env.PORT || 8080, () => { 13 | console.log('Server started'); 14 | }) -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @import "../variables"; 2 | 3 | mat-drawer { 4 | background-color: $light; 5 | } 6 | 7 | mat-drawer-container { 8 | height: 100%; 9 | background-color: white; 10 | } 11 | 12 | mat-expansion-panel { 13 | margin: 0; 14 | background-color: $normal; 15 | } 16 | 17 | .mat-nav-list[dense] { 18 | padding-top: 0; 19 | background-color: $light; 20 | } 21 | 22 | mat-expansion-panel-header { 23 | padding: 0 20px; 24 | } 25 | 26 | mat-icon { 27 | font-size: 22px !important; 28 | } 29 | 30 | mat-card { 31 | border-radius: 0; 32 | padding: 15px 15px 15px 20px; 33 | background-color: $dark; 34 | &:hover { 35 | cursor: pointer; 36 | } 37 | } 38 | 39 | .open-button { 40 | background-color: $dark; 41 | box-shadow: none; 42 | color: black; 43 | border: none; 44 | cursor: pointer; 45 | position: fixed; 46 | bottom: 30px; 47 | right: 30px; 48 | z-index: 30; 49 | } 50 | 51 | .send-button { 52 | background-color: $dark; 53 | box-shadow: none; 54 | color: black; 55 | border: none; 56 | cursor: pointer; 57 | position: fixed; 58 | bottom: 95px; 59 | right: 30px; 60 | } 61 | 62 | h3 { 63 | margin: 10px auto; 64 | text-align: center; 65 | } 66 | 67 | .popup { 68 | z-index: 20; 69 | display: none; 70 | position: fixed; 71 | bottom: 15px; 72 | right: 15px; 73 | background-color: $normal; 74 | min-width: 400px; 75 | min-height: 400px; 76 | max-width: 400px; 77 | } 78 | 79 | #chat { 80 | overflow: scroll; 81 | overflow-x: hidden; 82 | text-align: left; 83 | height: 40vh; 84 | width: auto; 85 | background-color: $light; 86 | margin: 10px 10px 0 10px; 87 | } 88 | 89 | .popup textarea { 90 | min-width: 300px; 91 | min-height: 120px; 92 | text-align: left; 93 | margin: 10px; 94 | border: none; 95 | resize: none; 96 | } 97 | 98 | .popup textarea:focus { 99 | background-color: $light; 100 | outline: none; 101 | } 102 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {Token} from './token'; 3 | import {Router} from '@angular/router'; 4 | import {SetupService} from './services/setup.service'; 5 | import {LoginService} from './services/login.service'; 6 | import {BACKEND_URL, FRONTEND_URL} from './globals'; 7 | import * as Stomp from 'stompjs'; 8 | import * as SockJS from 'sockjs-client'; 9 | import $ from 'jquery'; 10 | 11 | @Component({ 12 | selector: 'app-root', 13 | templateUrl: './app.component.html', 14 | styleUrls: ['./app.component.scss'] 15 | }) 16 | export class AppComponent { 17 | collapsedHeight = '48px'; 18 | expandedHeight = '48px'; 19 | serverUrl = BACKEND_URL + 'socket'; 20 | stompClient; 21 | 22 | constructor(private token: Token, private router: Router, private setupService: SetupService, 23 | private loginService: LoginService) { 24 | if (!this.isUserLoggedIn()) { 25 | this.setupService.checkSetup().subscribe(res => { 26 | if (res) { 27 | this.router.navigate(['login']); 28 | } else { 29 | this.router.navigate(['setup']); 30 | } 31 | }); 32 | } else if (window.location.href === FRONTEND_URL) { 33 | this.loginService.fetchUser().subscribe(user => { 34 | this.router.navigate(['employees', user.id]); 35 | }); 36 | } 37 | this.initializeWebSocketConnection(); 38 | } 39 | 40 | initializeWebSocketConnection() { 41 | const ws = new SockJS(this.serverUrl); 42 | this.stompClient = Stomp.over(ws); 43 | const that = this; 44 | this.stompClient.connect({}, function () { 45 | that.stompClient.debug = () => {}; 46 | that.stompClient.subscribe('/chat', (message) => { 47 | if (message.body) { 48 | $('#chat').append('
' + message.body + '
'); 49 | } 50 | }); 51 | }); 52 | } 53 | 54 | sendMessage(message) { 55 | this.loginService.fetchUser().subscribe(res => { 56 | const name = res.firstName.charAt(0) + '. ' + res.lastName; 57 | this.stompClient.send('/app/send/message', {}, name + ' | ' + message); 58 | $('#input').val(''); 59 | window.setInterval(function() { 60 | const elem = document.getElementById('chat'); 61 | elem.scrollTop = elem.scrollHeight; 62 | }, 300); 63 | }); 64 | } 65 | 66 | isUserLoggedIn(): boolean { 67 | return this.token.getToken() != null; 68 | } 69 | 70 | visitMyProfile() { 71 | this.loginService.fetchUser().subscribe(user => { 72 | this.router.navigate(['employees', user.id]); 73 | }); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/app/communication/emails/add-email/add-email.component.html: -------------------------------------------------------------------------------- 1 | Write email 2 |
3 | 4 | 5 | To 6 | 7 | 8 | 9 | 10 | Subject 11 | 12 | 13 | 14 | 15 | Content 16 | 17 | 18 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /src/app/communication/emails/add-email/add-email.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/communication/emails/conversation/conversation.component.html: -------------------------------------------------------------------------------- 1 | Email #{{selectedEmail.id}} - {{selectedEmail.email}} 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | Type: {{email.emailType}} 10 | 11 | 12 | 13 | Address: {{email.email}} 14 | 15 | 16 | 17 | Date and time: {{email.timestamp | date: 'yyyy-MM-dd, HH:mm'}} 18 | 19 | 20 | 21 | Subject: {{email.subject}} 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /src/app/communication/emails/conversation/conversation.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .content { 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | button { 9 | margin-right: 0; 10 | } 11 | 12 | .email { 13 | margin: 15px; 14 | } 15 | -------------------------------------------------------------------------------- /src/app/communication/emails/inbox/inbox.component.html: -------------------------------------------------------------------------------- 1 | Inbox 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | From: {{email.email}} 10 | 11 | 12 | 13 | Date and time: {{email.timestamp | date: 'yyyy-MM-dd, HH:mm'}} 14 | 15 | 16 | 17 | Subject: {{email.subject}} 18 | 19 | 20 | 21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /src/app/communication/emails/inbox/inbox.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .content { 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | button { 9 | margin-right: 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/communication/emails/inbox/inbox.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {EmailEntity} from '../../../types'; 3 | import {EmailService} from '../../../services/email.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {Observable} from "rxjs/index"; 7 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 8 | 9 | @Component({ 10 | selector: 'app-inbox', 11 | templateUrl: './inbox.component.html', 12 | styleUrls: ['./inbox.component.scss'] 13 | }) 14 | export class InboxComponent implements OnInit { 15 | 16 | emails: Array; 17 | areEmailsLoaded: boolean; 18 | obs: Observable; 19 | dataSource: MatTableDataSource = new MatTableDataSource([]); 20 | paginator: any; 21 | 22 | constructor(private emailService: EmailService, private router: Router, private dialog: MatDialog) { 23 | } 24 | 25 | @ViewChild(MatPaginator) 26 | set pagination(paginator: MatPaginator) { 27 | this.paginator = paginator; 28 | this.dataSource.paginator = this.paginator; 29 | } 30 | 31 | ngOnInit() { 32 | this.fetchEmails(); 33 | } 34 | 35 | fetchEmails() { 36 | this.emailService.fetchReceivedEmails().subscribe(res => this.emails = res, 37 | err => { 38 | if (err.status == 401) { 39 | this.router.navigate(['/login']); 40 | } else { 41 | this.showError(err); 42 | } 43 | }, 44 | () => { 45 | this.areEmailsLoaded = true; 46 | this.dataSource = new MatTableDataSource(this.emails); 47 | this.obs = this.dataSource.connect(); 48 | }); 49 | } 50 | 51 | sendEmail() { 52 | this.router.navigate(['/emails/add']); 53 | } 54 | 55 | showError(err) { 56 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 57 | width: '700px', 58 | data: { 59 | error: err.error, 60 | status: err.status 61 | } 62 | }); 63 | 64 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/communication/emails/outbox/outbox.component.html: -------------------------------------------------------------------------------- 1 | Outbox 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | To: {{email.email}} 10 | 11 | 12 | 13 | Date and time: {{email.timestamp | date: 'yyyy-MM-dd, HH:mm'}} 14 | 15 | 16 | 17 | Subject: {{email.subject}} 18 | 19 | 20 | 21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /src/app/communication/emails/outbox/outbox.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .content { 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | button { 9 | margin-right: 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/communication/emails/outbox/outbox.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {EmailEntity} from '../../../types'; 3 | import {EmailService} from '../../../services/email.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {Observable} from "rxjs/index"; 7 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 8 | 9 | @Component({ 10 | selector: 'app-outbox', 11 | templateUrl: './outbox.component.html', 12 | styleUrls: ['./outbox.component.scss'] 13 | }) 14 | export class OutboxComponent implements OnInit { 15 | 16 | emails: Array; 17 | areEmailsLoaded: boolean; 18 | obs: Observable; 19 | dataSource: MatTableDataSource = new MatTableDataSource([]); 20 | paginator: any; 21 | 22 | constructor(private emailService: EmailService, private router: Router, private dialog: MatDialog) { 23 | } 24 | 25 | @ViewChild(MatPaginator) 26 | set pagination(paginator: MatPaginator) { 27 | this.paginator = paginator; 28 | this.dataSource.paginator = this.paginator; 29 | } 30 | 31 | ngOnInit() { 32 | this.fetchEmails(); 33 | } 34 | 35 | fetchEmails() { 36 | this.emailService.fetchSentEmails().subscribe(res => this.emails = res, 37 | err => { 38 | if (err.status == 401) { 39 | this.router.navigate(['/login']); 40 | } else { 41 | this.showError(err); 42 | } 43 | }, 44 | () => { 45 | this.areEmailsLoaded = true; 46 | this.dataSource = new MatTableDataSource(this.emails); 47 | this.obs = this.dataSource.connect(); 48 | }); 49 | } 50 | 51 | sendEmail() { 52 | this.router.navigate(['/emails/add']); 53 | } 54 | 55 | showError(err) { 56 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 57 | width: '700px', 58 | data: { 59 | error: err.error, 60 | status: err.status 61 | } 62 | }); 63 | 64 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/communication/emails/reply-dialog/reply-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Type your email:

2 |

{{error}}

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/communication/emails/reply-dialog/reply-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/communication/emails/reply-dialog/reply-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 3 | import {EmailEntityRequest} from "../../../types"; 4 | import {EmailService} from "../../../services/email.service"; 5 | import {FormControl, FormGroup, Validators} from "@angular/forms"; 6 | 7 | export interface DialogData { 8 | email: string; 9 | } 10 | 11 | @Component({ 12 | selector: 'app-reply-dialog', 13 | templateUrl: './reply-dialog.component.html', 14 | styleUrls: ['./reply-dialog.component.scss'] 15 | }) 16 | export class ReplyDialogComponent { 17 | 18 | form: FormGroup; 19 | subject: FormControl; 20 | fullContent: FormControl; 21 | content = []; 22 | emailEntityRequest: EmailEntityRequest; 23 | error: string; 24 | shouldShowError: boolean; 25 | 26 | constructor(public dialogRef: MatDialogRef, 27 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 28 | private emailService: EmailService) { 29 | this.setupFormControls(); 30 | this.form = new FormGroup({ 31 | "subject": this.subject, 32 | "content": this.fullContent, 33 | }); 34 | } 35 | 36 | setupFormControls() { 37 | this.subject = new FormControl('', [ 38 | Validators.required 39 | ]); 40 | this.fullContent = new FormControl('', [ 41 | Validators.required 42 | ]); 43 | } 44 | 45 | cancel() { 46 | this.dialogRef.close(null); 47 | } 48 | 49 | submit() { 50 | this.divideContent(); 51 | this.emailEntityRequest = { 52 | email: this.data.email, 53 | subject: this.subject.value, 54 | content: this.content 55 | }; 56 | this.emailService.sendEmail(this.emailEntityRequest) 57 | .subscribe(res => { 58 | }, 59 | err => { 60 | this.shouldShowError = true; 61 | this.error = err.error; 62 | }, 63 | () => { 64 | this.dialogRef.close(null); 65 | }); 66 | } 67 | 68 | divideContent() { 69 | let i: number; 70 | let lastInd = 0; 71 | const threshold = 250; 72 | for (i = 0; i < Math.floor(this.fullContent.value.length / threshold); i++) { 73 | const firstInd = lastInd; 74 | const tempString = this.fullContent.value.substring(0, (i + 1) * threshold); 75 | lastInd = tempString.lastIndexOf(' ') + 1; 76 | this.content[i] = this.fullContent.value.substring(firstInd, lastInd); 77 | } 78 | this.content[i] = this.fullContent.value.substring(lastInd); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/app/communication/notifications/add-notification/add-notification.component.html: -------------------------------------------------------------------------------- 1 | Add notification 2 |
3 | 4 |
5 | 6 | Instruction 7 | 8 | {{getErrorInstruction()}} 9 | 10 | 11 | 12 | Description 13 | 14 | {{getErrorDescription()}} 15 | 16 | 17 | 18 | Consignees 19 | 20 | 21 | {{c.firstName}} {{c.lastName}} ({{c.role | enumeration}}) 22 | 23 | 24 | 25 | 26 | 27 | Type 28 | 29 | 30 | {{t | titlecase}} 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /src/app/communication/notifications/add-notification/add-notification.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/communication/notifications/notification/notification.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .mat-divider { 4 | margin: 10px 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/communication/notifications/notification/notification.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Notification} from '../../../types'; 3 | import {NotificationService} from '../../../services/notification.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 6 | import {MatDialog} from '@angular/material'; 7 | import {State} from '../../../globals'; 8 | 9 | @Component({ 10 | selector: 'app-notification', 11 | templateUrl: './notification.component.html', 12 | styleUrls: ['./notification.component.scss'] 13 | }) 14 | export class NotificationComponent implements OnInit { 15 | 16 | notification: Notification; 17 | isNotificationLoaded = false; 18 | isResolved = State.RESOLVED; 19 | 20 | constructor(private notificationService: NotificationService, private route: ActivatedRoute, 21 | private router: Router, private dialog: MatDialog) { 22 | } 23 | 24 | ngOnInit() { 25 | this.route.params.subscribe( 26 | params => { 27 | this.fetchNotification(); 28 | } 29 | ); 30 | } 31 | 32 | fetchNotification() { 33 | this.notificationService.fetchOneNotification(this.route.snapshot.params[('id')]) 34 | .subscribe(res => { 35 | this.notification = res; 36 | }, err => { 37 | if (err.status === 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err, true); 41 | } 42 | }, () => { 43 | this.isNotificationLoaded = true; 44 | }); 45 | } 46 | 47 | submitForm() { 48 | this.notificationService.setNextState(this.route.snapshot.params[('id')]) 49 | .subscribe(res => { 50 | this.notification = res; 51 | }, err => { 52 | if (err.status === 401) { 53 | this.router.navigate(['/login']); 54 | } else { 55 | this.showError(err, false); 56 | } 57 | }, () => { 58 | this.router.navigate(['/notifications', this.route.snapshot.params[('id')]]); 59 | }); 60 | } 61 | 62 | seeEmployee(id: number) { 63 | this.router.navigate(['/employees', id]); 64 | } 65 | 66 | showError(err, redirect: boolean) { 67 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 68 | width: '700px', 69 | data: { 70 | error: err.error, 71 | status: err.status 72 | } 73 | }); 74 | 75 | if (redirect) { 76 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/notifications'])); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/app/communication/notifications/notifications/notifications.component.html: -------------------------------------------------------------------------------- 1 | Notifications 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 |
Creation time{{row.creationTime | date:'short'}}State{{row.state | enumeration}}Type{{row.type | enumeration}}ID{{row.id}}Instruction{{row.instruction}}Notifier{{row.notifier.firstName}} {{row.notifier.lastName}}Transferee 45 | {{row.transferee ? row.transferee.firstName : null}} 46 | {{row.transferee ? row.transferee.lastName : null}} 47 |
53 | 54 | 55 | 56 |
57 | 58 |
59 | 60 |
61 |
62 | -------------------------------------------------------------------------------- /src/app/communication/notifications/notifications/notifications.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/communication/notifications/notifications/notifications.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {NotificationService} from '../../../services/notification.service'; 3 | import {Router} from '@angular/router'; 4 | import {Notification} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatSort, MatTableDataSource} from '@angular/material'; 6 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 7 | 8 | @Component({ 9 | selector: 'app-notifications', 10 | templateUrl: './notifications.component.html', 11 | styleUrls: ['./notifications.component.scss'] 12 | }) 13 | export class NotificationsComponent implements OnInit { 14 | 15 | notifications: Array; 16 | areNotificationsLoaded = false; 17 | displayedColumns: string[] = ['creationTime', 'state', 'type', 'id', 'instruction', 'notifier', 'transferee']; 18 | dataSource: MatTableDataSource = new MatTableDataSource(); 19 | paginator: any; 20 | sort: any; 21 | 22 | @ViewChild(MatPaginator) 23 | set pagination(paginator: MatPaginator) { 24 | this.paginator = paginator; 25 | this.dataSource.paginator = this.paginator; 26 | } 27 | 28 | @ViewChild(MatSort) 29 | set sorting(sort: MatSort) { 30 | this.sort = sort; 31 | this.dataSource.sort = this.sort; 32 | } 33 | 34 | constructor(private notificationService: NotificationService, private router: Router, private dialog: MatDialog) { } 35 | 36 | ngOnInit() { 37 | this.notificationService.fetchAllNotifications().subscribe(res => { 38 | this.notifications = res; 39 | }, err => { 40 | if (err.status === 401) { 41 | this.router.navigate(['/login']); 42 | } else { 43 | this.showError(err); 44 | } 45 | }, () => { 46 | this.areNotificationsLoaded = true; 47 | this.dataSource = new MatTableDataSource(this.notifications); 48 | }); 49 | } 50 | 51 | seeNotification(id: number) { 52 | this.router.navigate(['/notifications', id]); 53 | } 54 | 55 | addNotification() { 56 | this.router.navigate(['/notifications/add']); 57 | } 58 | 59 | applyFilter(filterValue: string) { 60 | this.dataSource.filter = filterValue.trim().toLowerCase(); 61 | } 62 | 63 | showError(err) { 64 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 65 | width: '700px', 66 | data: { 67 | error: err.error, 68 | status: err.status 69 | } 70 | }); 71 | 72 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/add-suggestion/add-suggestion.component.html: -------------------------------------------------------------------------------- 1 | Add new suggestion 2 |
3 | 4 |
5 | 6 | 7 | Name 8 | 9 | {{getErrorName()}} 10 | 11 | 12 | 13 | Description 14 | 15 | {{getErrorDescription()}} 16 | 17 | 18 | 19 | Recipients 20 | 21 | 22 | {{r.firstName}} {{r.lastName}} ({{r.role | enumeration}}) 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/add-suggestion/add-suggestion.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestion/suggestion.component.html: -------------------------------------------------------------------------------- 1 | Suggestion 2 |
3 | 4 |
5 |

{{suggestion.name}}

6 | 7 |

{{suggestion.description}}

8 | 9 |
10 |
11 |

ID: {{suggestion.id}}

12 | 13 |

Phase: {{suggestion.phase | enumeration}}

14 | 15 | 18 |
19 |
20 |

Reported at: 21 | 22 | {{suggestion.creationTime | date: 'short'}} 23 | 24 |

25 |

Reported by: 26 | 27 | {{suggestion.author.firstName}} {{suggestion.author.lastName}} 28 | 29 |

30 | 31 |

Launch at: 32 | 33 | {{suggestion.startTime ? (suggestion.startTime | date: 'short') : 'N/A'}} 34 | 35 |

36 |

Launch by: 37 | 38 | {{suggestion.startEmployee ? (suggestion.startEmployee.firstName + ' ' + suggestion.startEmployee.lastName) : 'N/A'}} 39 | 40 |

41 | 42 |

Ended at: 43 | 44 | {{suggestion.endTime ? (suggestion.endTime | date: 'short') : 'N/A'}} 45 | 46 |

47 |

Ended by: 48 | 49 | {{suggestion.endEmployee ? (suggestion.endEmployee.firstName + ' ' + suggestion.endEmployee.lastName) : 'N/A'}} 50 | 51 |

52 | 53 |
54 |
55 |

Recipients:

56 |
57 | 60 |
61 | 62 |
63 |
64 |
65 |
66 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestion/suggestion.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .mat-divider { 4 | margin: 10px 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestion/suggestion.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Suggestion} from '../../../types'; 3 | import {SuggestionService} from '../../../services/suggestion.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 6 | import {MatDialog} from '@angular/material'; 7 | import {Phase} from '../../../globals'; 8 | 9 | @Component({ 10 | selector: 'app-suggestion', 11 | templateUrl: './suggestion.component.html', 12 | styleUrls: ['./suggestion.component.scss'] 13 | }) 14 | export class SuggestionComponent implements OnInit { 15 | 16 | suggestion: Suggestion; 17 | isSuggestionLoaded = false; 18 | isImplemented = Phase.IMPLEMENTED; 19 | 20 | constructor(private suggestionService: SuggestionService, private route: ActivatedRoute, 21 | private router: Router, private dialog: MatDialog) { } 22 | 23 | ngOnInit() { 24 | this.route.params.subscribe( 25 | params => { 26 | this.fetchSuggestion(); 27 | } 28 | ); 29 | } 30 | 31 | fetchSuggestion() { 32 | this.suggestionService.fetchOneSuggestion(this.route.snapshot.params[('id')]) 33 | .subscribe(res => { 34 | this.suggestion = res; 35 | }, err => { 36 | if (err.status === 401) { 37 | this.router.navigate(['/login']); 38 | } else { 39 | this.showError(err, true); 40 | } 41 | }, () => { 42 | this.isSuggestionLoaded = true; 43 | }); 44 | } 45 | 46 | submitForm() { 47 | this.suggestionService.setNextPhase(this.route.snapshot.params[('id')]) 48 | .subscribe(res => { 49 | this.suggestion = res; 50 | }, err => { 51 | if (err.status === 401) { 52 | this.router.navigate(['/login']); 53 | } else { 54 | this.showError(err, false); 55 | } 56 | }, () => { 57 | this.router.navigate(['/suggestions', this.route.snapshot.params[('id')]]); 58 | }); 59 | } 60 | 61 | seeEmployee(id: number) { 62 | this.router.navigate(['/employees', id]); 63 | } 64 | 65 | showError(err, redirect: boolean) { 66 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 67 | width: '700px', 68 | data: { 69 | error: err.error, 70 | status: err.status 71 | } 72 | }); 73 | 74 | if (redirect) { 75 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/suggestions'])); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestions/suggestions.component.html: -------------------------------------------------------------------------------- 1 | Suggestions 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | 41 | 42 |
Creation time{{row.creationTime | date:'short'}}Phase{{row.phase | enumeration}}ID{{row.id}}Name{{row.name}}Author 35 | {{row.author.firstName}} 36 | {{row.author.lastName}} 37 |
43 | 44 | 45 | 46 |
47 | 48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestions/suggestions.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/communication/suggestions/suggestions/suggestions.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {Suggestion} from '../../../types'; 3 | import {SuggestionService} from '../../../services/suggestion.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatSort, MatTableDataSource} from '@angular/material'; 6 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 7 | 8 | @Component({ 9 | selector: 'app-suggestions', 10 | templateUrl: './suggestions.component.html', 11 | styleUrls: ['./suggestions.component.scss'] 12 | }) 13 | export class SuggestionsComponent implements OnInit { 14 | 15 | suggestions: Array; 16 | areSuggestionsLoaded = false; 17 | displayedColumns: string[] = ['creationTime', 'phase', 'id', 'name', 'author']; 18 | dataSource: MatTableDataSource = new MatTableDataSource(); 19 | paginator: any; 20 | sort: any; 21 | 22 | @ViewChild(MatPaginator) 23 | set pagination(paginator: MatPaginator) { 24 | this.paginator = paginator; 25 | this.dataSource.paginator = this.paginator; 26 | } 27 | 28 | @ViewChild(MatSort) 29 | set sorting(sort: MatSort) { 30 | this.sort = sort; 31 | this.dataSource.sort = this.sort; 32 | } 33 | 34 | constructor(private suggestionService: SuggestionService, private router: Router, private dialog: MatDialog) { } 35 | 36 | ngOnInit() { 37 | this.suggestionService.fetchAllSuggestions().subscribe(res => { 38 | this.suggestions = res; 39 | }, err => { 40 | if (err.status === 401) { 41 | this.router.navigate(['/login']); 42 | } else { 43 | this.showError(err); 44 | } 45 | }, () => { 46 | this.areSuggestionsLoaded = true; 47 | this.dataSource = new MatTableDataSource(this.suggestions); 48 | }); 49 | } 50 | 51 | seeSuggestion(id: number) { 52 | this.router.navigate(['/suggestions', id]); 53 | } 54 | 55 | addSuggestion() { 56 | this.router.navigate(['/suggestions/add']); 57 | } 58 | 59 | applyFilter(filterValue: string) { 60 | this.dataSource.filter = filterValue.trim().toLowerCase(); 61 | } 62 | 63 | showError(err) { 64 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 65 | width: '700px', 66 | data: { 67 | error: err.error, 68 | status: err.status 69 | } 70 | }); 71 | 72 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/custom/error-dialog/error-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/custom/error-dialog/error-dialog.component.scss: -------------------------------------------------------------------------------- 1 | button { 2 | font-style: italic; 3 | } 4 | 5 | .decline { 6 | color: darkred; 7 | } 8 | 9 | mat-icon { 10 | margin-right: 5px; 11 | margin-left: 15px; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/custom/error-dialog/error-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 3 | 4 | export interface DialogData { 5 | error: string; 6 | status?: number 7 | } 8 | 9 | @Component({ 10 | selector: 'app-error-dialog', 11 | templateUrl: './error-dialog.component.html', 12 | styleUrls: ['./error-dialog.component.scss'] 13 | }) 14 | export class ErrorDialogComponent { 15 | 16 | constructor(public dialogRef: MatDialogRef, 17 | @Inject(MAT_DIALOG_DATA) public data: DialogData) { 18 | } 19 | 20 | cancel() { 21 | this.dialogRef.close(null); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/globals.ts: -------------------------------------------------------------------------------- 1 | // export const FRONTEND_URL = 'http://localhost:4200/'; 2 | export const FRONTEND_URL = 'https://erp-mes-frontend.herokuapp.com/'; 3 | // export const BACKEND_URL = 'http://localhost:8080/'; 4 | export const BACKEND_URL = 'https://erp-mes-backend.herokuapp.com/'; 5 | 6 | export enum Role { 7 | ADMIN = 'ADMIN', 8 | ACCOUNTANT = 'ACCOUNTANT', 9 | ADMIN_ACCOUNTANT = 'ADMIN_ACCOUNTANT', 10 | ANALYST = 'ANALYST', 11 | ADMIN_ANALYST = 'ADMIN_ANALYST', 12 | WAREHOUSE = 'WAREHOUSE', 13 | ADMIN_WAREHOUSE = 'ADMIN_WAREHOUSE' 14 | } 15 | 16 | export enum HolidayType { 17 | VACATION = 'VACATION', 18 | SICK_LEAVE = 'SICK_LEAVE', 19 | PARENTAL_LEAVE = 'PARENTAL_LEAVE', 20 | BEREAVEMENT = 'BEREAVEMENT', 21 | EMERGENCY_CHILD_CARE = 'EMERGENCY_CHILD_CARE' 22 | } 23 | 24 | export enum ApprovalState { 25 | APPROVED = 'APPROVED', 26 | DECLINED = 'DECLINED', 27 | PENDING = 'PENDING' 28 | } 29 | 30 | export enum Category { 31 | TO_DO = 'TO_DO', 32 | DOING = 'DOING', 33 | DONE = 'DONE' 34 | } 35 | 36 | export enum ExpenseType { 37 | SHIPPING = 'SHIPPING', 38 | BILLS = 'BILLS', 39 | RENT = 'RENT', 40 | SALARIES = 'SALARIES', 41 | STOCK = 'STOCK', 42 | SOCIAL_FUND = 'SOCIAL_FUND', 43 | UNEXPECTED = 'UNEXPECTED', 44 | TAXES = 'TAXES' 45 | } 46 | 47 | export enum Status { 48 | WAITING_FOR_PAYMENT = 'WAITING_FOR_PAYMENT', 49 | IN_PROGRESS = 'IN_PROGRESS', 50 | SENT = 'SENT', 51 | DECLINED = 'DECLINED' 52 | } 53 | 54 | export enum State { 55 | REPORTED = 'REPORTED', 56 | IN_PROGRESS = 'IN_PROGRESS', 57 | RESOLVED = 'RESOLVED' 58 | } 59 | 60 | export enum Phase { 61 | REPORTED = 'REPORTED', 62 | IN_IMPLEMENTATION = 'IN_IMPLEMENTATION', 63 | IMPLEMENTED = 'IMPLEMENTED', 64 | } 65 | 66 | export enum Type { 67 | DELIVERY = 'DELIVERY', 68 | ORDER = 'ORDER', 69 | COMPLAINT = 'COMPLAINT', 70 | RETURN = 'RETURN', 71 | OTHER = 'OTHER' 72 | } 73 | 74 | export enum ReturnStatus { 75 | IN_PROGRESS = 'IN_PROGRESS', 76 | ACCEPTED = 'ACCEPTED', 77 | DECLINED = 'DECLINED', 78 | MONEY_RETURNED = 'MONEY_RETURNED' 79 | } 80 | 81 | export enum ComplaintStatus { 82 | IN_PROGRESS = 'IN_PROGRESS', 83 | ACCEPTED = 'ACCEPTED', 84 | DECLINED = 'DECLINED', 85 | MONEY_RETURNED = 'MONEY_RETURNED', 86 | NEW_ITEM_SENT = 'NEW_ITEM_SENT', 87 | REPAIRING_ITEM = 'REPAIRING_ITEM', 88 | REPAIRED_ITEM_SENT = 'REPAIRED_ITEM_SENT', 89 | DECLINED_ITEM_SENT = 'DECLINED_ITEM_SENT' 90 | } 91 | 92 | export enum Resolution { 93 | UNRESOLVED = 'UNRESOLVED', 94 | MONEY_RETURN = 'MONEY_RETURN', 95 | REPAIR = 'REPAIR', 96 | EXCHANGE_FOR_NEW = 'EXCHANGE_FOR_NEW' 97 | } 98 | 99 | export enum EmailType { 100 | SENT = 'SENT', 101 | RECEIVED = 'RECEIVED' 102 | } 103 | -------------------------------------------------------------------------------- /src/app/interceptor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpErrorResponse, 3 | HttpHandler, 4 | HttpHeaderResponse, 5 | HttpInterceptor, 6 | HttpProgressEvent, 7 | HttpRequest, 8 | HttpResponse, 9 | HttpSentEvent, 10 | HttpUserEvent 11 | } from '@angular/common/http'; 12 | import {Injectable} from '@angular/core'; 13 | import {Token} from './token'; 14 | import {Router} from '@angular/router'; 15 | import {Observable} from 'rxjs'; 16 | import {tap} from 'rxjs/internal/operators'; 17 | 18 | @Injectable() 19 | export class Interceptor implements HttpInterceptor { 20 | 21 | constructor(private token: Token, private router: Router) { 22 | } 23 | 24 | intercept(req: HttpRequest, next: HttpHandler): Observable | HttpUserEvent> { 25 | let authReq = req; 26 | if (this.token.getToken() != null) { 27 | authReq = req.clone({headers: req.headers.set('Authorization', 'Bearer ' + this.token.getToken())}); 28 | } 29 | return next.handle(authReq).pipe( 30 | tap((err: any) => { 31 | if (err instanceof HttpErrorResponse) { 32 | if (err.status === 401) { 33 | this.router.navigate(['employees']); 34 | } 35 | } 36 | } 37 | )); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/app/material.ts: -------------------------------------------------------------------------------- 1 | import { 2 | MatButtonModule, MatCardModule, 3 | MatCheckboxModule, MatDatepickerModule, MatDialogModule, 4 | MatExpansionModule, MatFormFieldModule, 5 | MatDividerModule, MatGridListModule, 6 | MatIconModule, MatInputModule, 7 | MatListModule, MatNativeDateModule, MatSelectModule, 8 | MatSidenavModule, MatTableModule, 9 | MatPaginatorModule, MatProgressSpinnerModule, MatTabsModule 10 | } from '@angular/material'; 11 | import {NgModule} from '@angular/core'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | MatButtonModule, 16 | MatCheckboxModule, 17 | MatIconModule, 18 | MatSidenavModule, 19 | MatExpansionModule, 20 | MatListModule, 21 | MatCardModule, 22 | MatProgressSpinnerModule, 23 | MatTableModule, 24 | MatPaginatorModule, 25 | MatFormFieldModule, 26 | MatInputModule, 27 | MatSelectModule, 28 | MatDatepickerModule, 29 | MatNativeDateModule, 30 | MatListModule, 31 | MatSelectModule, 32 | MatTabsModule, 33 | MatDividerModule, 34 | MatGridListModule, 35 | MatDialogModule, 36 | MatExpansionModule 37 | ], 38 | exports: [ 39 | MatButtonModule, 40 | MatCheckboxModule, 41 | MatIconModule, 42 | MatSidenavModule, 43 | MatExpansionModule, 44 | MatListModule, 45 | MatCardModule, 46 | MatProgressSpinnerModule, 47 | MatTableModule, 48 | MatPaginatorModule, 49 | MatFormFieldModule, 50 | MatInputModule, 51 | MatSelectModule, 52 | MatDatepickerModule, 53 | MatNativeDateModule, 54 | MatListModule, 55 | MatDialogModule, 56 | MatSelectModule, 57 | MatTabsModule, 58 | MatDividerModule, 59 | MatGridListModule, 60 | MatExpansionModule 61 | ], 62 | }) 63 | export class MaterialModule { } 64 | -------------------------------------------------------------------------------- /src/app/pipes/enumeration.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'enumeration' 5 | }) 6 | export class EnumerationPipe implements PipeTransform { 7 | 8 | transform(word: string): string { 9 | if (word !== undefined && word !== null) { 10 | word = word[0].toUpperCase() + word.substr(1).toLowerCase(); 11 | return word.toString().replace('_', ' '); 12 | } 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pipes/minute-seconds.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'minuteSeconds' 5 | }) 6 | export class MinuteSecondsPipe implements PipeTransform { 7 | 8 | transform(value: number): string { 9 | const minutes: number = Math.floor(value / 60); 10 | return minutes + 'm ' + (value - minutes * 60) + 's'; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pipes/no-comma-number.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'noCommaNumber' 5 | }) 6 | export class NoCommaNumberPipe implements PipeTransform { 7 | 8 | transform(value: number): string { 9 | if (value !== undefined && value !== null) { 10 | return value.toString().replace(",", " "); 11 | } else { 12 | return ""; 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/pipes/tasks-doing.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | import {Task} from '../types'; 3 | import {Category} from '../globals'; 4 | 5 | @Pipe({ 6 | name: 'tasksDoing' 7 | }) 8 | export class TasksDoingPipe implements PipeTransform { 9 | 10 | transform(myTasks: Task[]) { 11 | if (!myTasks) { 12 | return myTasks; 13 | } 14 | return myTasks.filter(task => task.category === Category.DOING); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pipes/tasks-done.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | import {Task} from '../types'; 3 | import {Category} from '../globals'; 4 | 5 | @Pipe({ 6 | name: 'tasksDone' 7 | }) 8 | export class TasksDonePipe implements PipeTransform { 9 | 10 | transform(myTasks: Task[]) { 11 | if (!myTasks) { 12 | return myTasks; 13 | } 14 | return myTasks.filter(task => task.category === Category.DONE); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pipes/tasks-todo.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | import {Task} from '../types'; 3 | import {Category} from '../globals'; 4 | 5 | @Pipe({ 6 | name: 'tasksTodo' 7 | }) 8 | export class TasksTodoPipe implements PipeTransform { 9 | 10 | transform(myTasks: Task[]) { 11 | if (!myTasks) { 12 | return myTasks; 13 | } 14 | return myTasks.filter(task => task.category === Category.TO_DO); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/production/finance/add-expense-dialog/add-expense-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Enter expense details:

2 |

{{error}}

3 | 4 | 5 | 6 | 7 | {{t}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/app/production/finance/add-expense-dialog/add-expense-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/production/finance/add-expense-dialog/add-expense-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {ExpenseRequest} from "../../../types"; 3 | import {MatDialogRef} from "@angular/material"; 4 | import {ReportService} from "../../../services/report.service"; 5 | import {ExpenseType} from "../../../globals"; 6 | 7 | @Component({ 8 | selector: 'app-add-expense-dialog', 9 | templateUrl: './add-expense-dialog.component.html', 10 | styleUrls: ['./add-expense-dialog.component.scss'] 11 | }) 12 | export class AddExpenseDialogComponent { 13 | 14 | expenseType: ExpenseType; 15 | types; 16 | amount: number; 17 | error: string; 18 | shouldShowError: boolean; 19 | 20 | constructor(public dialogRef: MatDialogRef, 21 | private reportService: ReportService) { 22 | this.types = Object.keys(ExpenseType); 23 | } 24 | 25 | isFormValid() { 26 | const regexp = new RegExp('\\d{2}'); 27 | return this.amount != null && regexp.test(this.amount.toString()) && this.expenseType != null; 28 | } 29 | 30 | cancel() { 31 | this.dialogRef.close(null); 32 | } 33 | 34 | submit() { 35 | const expenseRequest: ExpenseRequest = { 36 | expenseType: this.expenseType, 37 | amount: this.amount 38 | }; 39 | 40 | this.reportService.addExpense(expenseRequest).subscribe(res => { 41 | }, err => { 42 | this.shouldShowError = true; 43 | this.error = err.error; 44 | }, () => { 45 | this.cancel(); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app/production/finance/add-income-dialog/add-income-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Enter income value:

2 |

{{error}}

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/app/production/finance/add-income-dialog/add-income-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/production/finance/add-income-dialog/add-income-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {MatDialogRef} from "@angular/material"; 3 | import {ReportService} from "../../../services/report.service"; 4 | 5 | @Component({ 6 | selector: 'app-add-income-dialog', 7 | templateUrl: './add-income-dialog.component.html', 8 | styleUrls: ['./add-income-dialog.component.scss'] 9 | }) 10 | export class AddIncomeDialogComponent { 11 | 12 | income = 0; 13 | error: string; 14 | shouldShowError: boolean; 15 | 16 | constructor(public dialogRef: MatDialogRef, 17 | private reportService: ReportService) {} 18 | 19 | isFormValid() { 20 | const regexp = new RegExp('\\d{2}'); 21 | return this.income != null && regexp.test(this.income.toString()); 22 | } 23 | 24 | cancel() { 25 | this.dialogRef.close(null); 26 | } 27 | 28 | submit() { 29 | this.reportService.addIncome(this.income).subscribe(res => { 30 | }, err => { 31 | this.shouldShowError = true; 32 | this.error = err.error; 33 | }, () => { 34 | this.cancel(); 35 | }); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/app/production/finance/current-report/current-report.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 10px; 5 | margin-right: 5px; 6 | } 7 | 8 | .date-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | 18 | button { 19 | margin-left: 10px; 20 | } 21 | -------------------------------------------------------------------------------- /src/app/production/finance/recalculate-dialog/recalculate-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Enter recalculated estimates:

2 |

{{error}}

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/app/production/finance/recalculate-dialog/recalculate-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/production/finance/recalculate-dialog/recalculate-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {ReportService} from "../../../services/report.service"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | 5 | export interface DialogData { 6 | estimatedIncome: number; 7 | estimatedShipping: number; 8 | estimatedBills: number; 9 | rent: number; 10 | salaries: number; 11 | stockCosts: number; 12 | socialFund: number; 13 | unexpected: number; 14 | } 15 | 16 | @Component({ 17 | selector: 'app-recalculate-dialog', 18 | templateUrl: './recalculate-dialog.component.html', 19 | styleUrls: ['./recalculate-dialog.component.scss'] 20 | }) 21 | export class RecalculateDialogComponent { 22 | 23 | error: string; 24 | shouldShowError: boolean; 25 | 26 | constructor(public dialogRef: MatDialogRef, 27 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 28 | private reportService: ReportService) { 29 | } 30 | 31 | isFormValid() { 32 | const regexp = new RegExp('\\d{2}'); 33 | return regexp.test(this.data.estimatedIncome.toString()) && regexp.test(this.data.estimatedShipping.toString()) 34 | && regexp.test(this.data.estimatedBills.toString()) && regexp.test(this.data.rent.toString()) 35 | && regexp.test(this.data.salaries.toString()) && regexp.test(this.data.stockCosts.toString()) 36 | && regexp.test(this.data.socialFund.toString()) && regexp.test(this.data.unexpected.toString()); 37 | } 38 | 39 | cancel() { 40 | this.dialogRef.close(null); 41 | } 42 | 43 | submit() { 44 | const estimatedCostsRequest = { 45 | estimatedIncome: this.data.estimatedIncome, 46 | estimatedShippingCosts: this.data.estimatedShipping, 47 | estimatedBills: this.data.estimatedBills, 48 | rent: this.data.rent, 49 | salaries: this.data.salaries, 50 | stockCosts: this.data.stockCosts, 51 | socialFund: this.data.socialFund, 52 | unexpected: this.data.unexpected 53 | }; 54 | this.reportService.recalculateCosts(estimatedCostsRequest).subscribe(res => { 55 | }, err => { 56 | this.shouldShowError = true; 57 | this.error = err.error; 58 | }, () => { 59 | this.cancel(); 60 | }); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/app/production/finance/report/report.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 10px; 5 | margin-right: 5px; 6 | } 7 | 8 | .date-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/production/finance/report/report.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ReportService} from '../../../services/report.service'; 3 | import {ActivatedRoute, Router} from '@angular/router'; 4 | import {MonthlyReport} from '../../../types'; 5 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 6 | import {MatDialog} from "@angular/material"; 7 | 8 | @Component({ 9 | selector: 'app-report', 10 | templateUrl: './report.component.html', 11 | styleUrls: ['./report.component.scss'] 12 | }) 13 | export class ReportComponent implements OnInit { 14 | 15 | report: MonthlyReport; 16 | isReportLoaded = false; 17 | 18 | constructor(private reportService: ReportService, 19 | private route: ActivatedRoute, 20 | private router: Router, 21 | private dialog: MatDialog) { } 22 | 23 | ngOnInit() { 24 | this.fetchReport(this.route.snapshot.params['id']); 25 | } 26 | 27 | fetchReport(id: number) { 28 | this.reportService.fetchOneReport(id).subscribe(res => { 29 | this.report = res; 30 | }, err => { 31 | if (err.status == 401) { 32 | this.router.navigate(['/login']); 33 | } else { 34 | this.showError(err); 35 | } 36 | }, () => { 37 | this.isReportLoaded = true; 38 | }); 39 | } 40 | 41 | showError(err) { 42 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 43 | width: '700px', 44 | data: { 45 | error: err.error, 46 | status: err.status 47 | } 48 | }); 49 | 50 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/reports'])); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/production/finance/reports/reports.component.html: -------------------------------------------------------------------------------- 1 | Monthly reports 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
Index {{row.id}} Start date {{row.startDate}} Expenses {{row.overallExpenses}} Income {{row.overallIncome}} Balance {{row.balance}}
35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /src/app/production/finance/reports/reports.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/production/finance/reports/reports.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {ReportService} from '../../../services/report.service'; 3 | import {Router} from '@angular/router'; 4 | import {MonthlyReport} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-reports', 10 | templateUrl: './reports.component.html', 11 | styleUrls: ['./reports.component.scss'] 12 | }) 13 | export class ReportsComponent implements OnInit { 14 | 15 | reports: Array; 16 | areReportsLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private reportService: ReportService, 27 | private router: Router, private dialog: MatDialog) { } 28 | 29 | ngOnInit() { 30 | this.fetchReports(); 31 | } 32 | 33 | fetchReports() { 34 | this.reportService.fetchAllReports().subscribe(res => { 35 | this.reports = res; 36 | }, err => { 37 | if (err.status == 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err); 41 | } 42 | }, () => { 43 | this.areReportsLoaded = true; 44 | this.dataSource = new MatTableDataSource(this.reports); 45 | }); 46 | } 47 | 48 | seeReport(id: number) { 49 | this.router.navigate(['/reports', id]); 50 | } 51 | 52 | showError(err) { 53 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 54 | width: '700px', 55 | data: { 56 | error: err.error, 57 | status: err.status 58 | } 59 | }); 60 | 61 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/app/production/planning/planning/planning.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 10px; 5 | margin-right: 5px; 6 | } 7 | 8 | .daily-plan-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | } 12 | 13 | .info { 14 | margin-top: 20px; 15 | } 16 | 17 | .alert { 18 | display: inline-flex; 19 | vertical-align: middle; 20 | color: crimson; 21 | font-style: italic; 22 | } 23 | 24 | .special { 25 | display: inline-flex; 26 | vertical-align: middle; 27 | color: deeppink; 28 | font-style: italic; 29 | } 30 | 31 | .alert-label { 32 | padding-top: 22px; 33 | padding-left: 25px; 34 | } 35 | 36 | .title { 37 | padding-bottom: 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/app/production/planning/show-special-plan-dialog/show-special-plan-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{data.specialPlan.description}} 4 |
5 | 6 | 7 | Date: {{data.specialPlan.day}} 8 | 9 | 10 | 11 | Employees per day: {{data.specialPlan.employeesPerDay}} 12 | 13 | 14 | 15 | Orders per day: {{data.specialPlan.ordersPerDay}} 16 | 17 | 18 | 19 | Returns per day: {{data.specialPlan.returnsPerDay}} 20 | 21 | 22 | 23 | Complaints resolved per day: {{data.specialPlan.complaintsResolvedPerDay}} 24 | 25 |
26 | -------------------------------------------------------------------------------- /src/app/production/planning/show-special-plan-dialog/show-special-plan-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .description { 2 | margin: 15px; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/production/planning/show-special-plan-dialog/show-special-plan-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from '@angular/core'; 2 | import {SpecialPlan} from "../../../types"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | 5 | export interface DialogData { 6 | specialPlan: SpecialPlan; 7 | } 8 | 9 | @Component({ 10 | selector: 'app-show-special-plan-dialog', 11 | templateUrl: './show-special-plan-dialog.component.html', 12 | styleUrls: ['./show-special-plan-dialog.component.scss'] 13 | }) 14 | export class ShowSpecialPlanDialogComponent { 15 | 16 | constructor(public dialogRef: MatDialogRef, 17 | @Inject(MAT_DIALOG_DATA) public data: DialogData) {} 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plan-dialog/special-plan-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Insert special plan details

2 |

{{error}}

3 | 4 |
5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | Description 15 | 16 | 17 | 18 | 19 | Employees per day 20 | 21 | 22 | 23 | 24 | Orders per day 25 | 26 | 27 | 28 | 29 | Returns per day 30 | 31 | 32 | 33 | 34 | Complaints resolved per day 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plan-dialog/special-plan-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plan-no-date-dialog/special-plan-no-date-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Special plan for: {{data.date}}

2 |

{{error}}

3 | 4 |
5 | 6 | 7 | Description 8 | 9 | 10 | 11 | 12 | Employees per day 13 | 14 | 15 | 16 | 17 | Orders per day 18 | 19 | 20 | 21 | 22 | Returns per day 23 | 24 | 25 | 26 | 27 | Complaints resolved per day 28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 |
36 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plan-no-date-dialog/special-plan-no-date-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plans/special-plans.component.html: -------------------------------------------------------------------------------- 1 | Special plans 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 46 |
Index {{row.id}} Description {{row.description}} Day {{row.day}} Number of employees {{row.employeesPerDay}} Orders {{row.ordersPerDay}} Returns {{row.returnsPerDay}} Complaints {{row.complaintsResolvedPerDay}}
47 | 48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plans/special-plans.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | tr { 4 | &:hover { 5 | cursor: default; 6 | background-color: $light; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/app/production/planning/special-plans/special-plans.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {PlanningService} from '../../../services/planning.service'; 3 | import {SpecialPlan} from '../../../types'; 4 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 5 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 6 | import {Router} from "@angular/router"; 7 | 8 | @Component({ 9 | selector: 'app-special-plans', 10 | templateUrl: './special-plans.component.html', 11 | styleUrls: ['./special-plans.component.scss'] 12 | }) 13 | export class SpecialPlansComponent implements OnInit { 14 | 15 | specialPlans: Array; 16 | arePlansLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private planningService: PlanningService, private router: Router, private dialog: MatDialog) {} 27 | 28 | ngOnInit() { 29 | this.planningService.fetchSpecialPlans().subscribe(res => { 30 | this.specialPlans = res; 31 | }, err => { 32 | if (err.status == 401) { 33 | this.router.navigate(['/login']); 34 | } else { 35 | this.showError(err); 36 | } 37 | }, () => { 38 | this.arePlansLoaded = true; 39 | this.dataSource = new MatTableDataSource(this.specialPlans); 40 | }); 41 | } 42 | 43 | showError(err) { 44 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 45 | width: '700px', 46 | data: { 47 | error: err.error, 48 | status: err.status 49 | } 50 | }); 51 | 52 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/production/planning/update-daily-plan/update-daily-plan.component.html: -------------------------------------------------------------------------------- 1 | Update Daily Plan 2 |
3 | 4 | 5 | Employees per day 6 | 7 | 8 | 9 | 10 | Orders per day 11 | 12 | 13 | 14 | 15 | Returns per day 16 | 17 | 18 | 19 | 20 | Complaints resolved per day 21 | 22 | 23 | 24 | 25 |
26 | -------------------------------------------------------------------------------- /src/app/production/planning/update-daily-plan/update-daily-plan.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/production/tasks/add-task/add-task.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/production/tasks/assignment/assignment.component.html: -------------------------------------------------------------------------------- 1 | Assignment tasks 2 |
3 | 4 |
5 | 6 | 7 | Tasks 8 | 9 | 10 | {{p.id}} {{p.name}} ({{p.category | enumeration}}) 11 | 12 | 13 | 14 | 15 | 16 | Assignees 17 | 18 | 19 | {{a.firstName}} {{a.lastName}} ({{a.role | enumeration}}) 20 | 21 | 22 | 23 | 24 | 25 | Start time 26 | 27 | 28 | 29 | 30 | End time 31 | 32 | 33 | 34 | 35 |
36 |
37 | -------------------------------------------------------------------------------- /src/app/production/tasks/assignment/assignment.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/production/tasks/indicators/indicators.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .row { 4 | margin: 2vh 0; 5 | } 6 | 7 | .grid { 8 | margin: 0; 9 | min-width: 0; 10 | } 11 | 12 | p { 13 | margin-top: 0.8vw; 14 | margin-left: 9vh; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/production/tasks/kanban/kanban.component.html: -------------------------------------------------------------------------------- 1 | Kanban board 2 | 3 | 4 |
5 | 6 | 7 | 8 | {{e.firstName}} {{e.lastName}} ({{e.role | enumeration}}) 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

ID: {{myTask.id}} Type: {{myTask.type ? myTask.type : 'N/A'}}

17 | 18 |

{{myTask.name}}

19 | 20 |

Created: {{myTask.creationTime | date:'short'}}

21 | 22 |

Deadline: {{myTask.deadline | date:'short'}}

23 | 24 |
25 |
26 | 27 | 28 |
29 |

ID: {{myTask.id}} Type: {{myTask.type ? myTask.type : 'N/A'}}

30 | 31 |

{{myTask.name}}

32 | 33 |

Started: {{myTask.startTime | date:'short'}}

34 | 35 |

Deadline: {{myTask.deadline | date:'short'}}

36 | 37 |
38 |
39 | 40 | 41 |
42 |

ID: {{myTask.id}} Type: {{myTask.type ? myTask.type : 'N/A'}}

43 | 44 |

{{myTask.name}}

45 | 46 |

Ended: {{myTask.endTime | date:'short'}}

47 | 48 |

Deadline: {{myTask.deadline | date:'short'}}

49 | 50 |
51 |
52 | 53 |
54 | 55 |
56 | -------------------------------------------------------------------------------- /src/app/production/tasks/kanban/kanban.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-select { 4 | margin-bottom: 3vh; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/production/tasks/kanban/kanban.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Employee, Task} from '../../../types'; 3 | import {TaskService} from '../../../services/task.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 6 | import {MatDialog} from '@angular/material'; 7 | import {EmployeeService} from '../../../services/employee.service'; 8 | 9 | @Component({ 10 | selector: 'app-kanban', 11 | templateUrl: './kanban.component.html', 12 | styleUrls: ['./kanban.component.scss'] 13 | }) 14 | export class KanbanComponent implements OnInit { 15 | 16 | employees: Array; 17 | tasks: Array; 18 | areEmployeesLoaded = false; 19 | areTasksLoaded = false; 20 | currentId: number; 21 | 22 | constructor(private taskService: TaskService, private router: Router, private route: ActivatedRoute, 23 | private dialog: MatDialog, private employeeService: EmployeeService) { 24 | } 25 | 26 | ngOnInit() { 27 | this.route.params.subscribe( 28 | params => { 29 | this.fetchKanban(); 30 | } 31 | ); 32 | } 33 | 34 | fetchKanban() { 35 | this.currentId = +this.route.snapshot.params['id']; 36 | this.employeeService.fetchAllEmployees() 37 | .subscribe(res => { 38 | this.employees = res; 39 | }, err => { 40 | if (err.status == 401) { 41 | this.router.navigate(['/login']); 42 | } else { 43 | this.showError(err); 44 | } 45 | }, () => { 46 | this.areEmployeesLoaded = true; 47 | }); 48 | this.taskService.fetchTasksByAssignee(this.route.snapshot.params[('id')]) 49 | .subscribe(res => { 50 | this.tasks = res; 51 | }, err => { 52 | if (err.status == 401) { 53 | this.router.navigate(['/login']); 54 | } else { 55 | this.showError(err); 56 | } 57 | }, () => { 58 | this.areTasksLoaded = true; 59 | }); 60 | } 61 | 62 | seeTask(id: number) { 63 | this.router.navigate(['/tasks', id]); 64 | } 65 | 66 | seeKanban(id: number) { 67 | this.router.navigate(['/kanban', id]); 68 | } 69 | 70 | showError(err) { 71 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 72 | width: '700px', 73 | data: { 74 | error: err.error, 75 | status: err.status 76 | } 77 | }); 78 | 79 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/app/production/tasks/task/task.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | .mat-divider { 4 | margin: 10px 0; 5 | } 6 | 7 | mat-expansion-panel { 8 | margin: 0; 9 | background-color: $normal; 10 | } 11 | 12 | mat-expansion-panel-header { 13 | padding: 0 20px; 14 | } 15 | 16 | .expansion-panel-paragraph { 17 | padding: 5px 20px; 18 | } 19 | -------------------------------------------------------------------------------- /src/app/production/tasks/task/task.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {TaskService} from '../../../services/task.service'; 3 | import {ActivatedRoute, Router} from '@angular/router'; 4 | import {Task} from '../../../types'; 5 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 6 | import {MatDialog} from '@angular/material'; 7 | import {Category} from '../../../globals'; 8 | 9 | @Component({ 10 | selector: 'app-task', 11 | templateUrl: './task.component.html', 12 | styleUrls: ['./task.component.scss'] 13 | }) 14 | export class TaskComponent implements OnInit { 15 | 16 | task: Task; 17 | isTaskLoaded = false; 18 | isDone = Category.DONE; 19 | 20 | constructor(private taskService: TaskService, private route: ActivatedRoute, 21 | private router: Router, private dialog: MatDialog) { } 22 | 23 | ngOnInit() { 24 | this.route.params.subscribe( 25 | params => { 26 | this.fetchTask(); 27 | } 28 | ); 29 | } 30 | 31 | fetchTask() { 32 | this.taskService.fetchOneTask(this.route.snapshot.params[('id')]) 33 | .subscribe(res => { 34 | this.task = res; 35 | }, err => { 36 | if (err.status === 401) { 37 | this.router.navigate(['/login']); 38 | } else { 39 | this.showError(err, true); 40 | } 41 | }, () => { 42 | this.isTaskLoaded = true; 43 | }); 44 | } 45 | 46 | setNextCategory() { 47 | this.taskService.setNextCategory(this.route.snapshot.params[('id')]) 48 | .subscribe(res => { 49 | this.task = res; 50 | }, err => { 51 | if (err.status === 401) { 52 | this.router.navigate(['/login']); 53 | } else { 54 | this.showError(err, false); 55 | } 56 | }, () => { 57 | this.router.navigate(['/tasks']); 58 | }); 59 | } 60 | 61 | assignToMe() { 62 | this.taskService.assignToMe(this.route.snapshot.params[('id')]) 63 | .subscribe(res => { 64 | this.task = res; 65 | }, err => { 66 | if (err.status === 401) { 67 | this.router.navigate(['/login']); 68 | } else { 69 | this.showError(err, false); 70 | } 71 | }, () => { 72 | this.router.navigate(['/tasks']); 73 | }); 74 | } 75 | 76 | seeTask(id: number) { 77 | this.router.navigate(['/tasks', id]); 78 | } 79 | 80 | showError(err, redirect: boolean) { 81 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 82 | width: '700px', 83 | data: { 84 | error: err.error, 85 | status: err.status 86 | } 87 | }); 88 | 89 | if (redirect) { 90 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/tasks'])); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/app/production/tasks/tasks/tasks.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/production/tasks/tasks/tasks.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {TaskService} from '../../../services/task.service'; 3 | import {Router} from '@angular/router'; 4 | import {Task} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatSort, MatTableDataSource} from '@angular/material'; 6 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 7 | 8 | @Component({ 9 | selector: 'app-tasks', 10 | templateUrl: './tasks.component.html', 11 | styleUrls: ['./tasks.component.scss'] 12 | }) 13 | export class TasksComponent implements OnInit { 14 | 15 | tasks: Array; 16 | tasksAssigneeIsNull: Array; 17 | areTasksLoaded = false; 18 | displayedColumns: string[] = ['creationTime', 'deadline', 'category', 'name', 'type', 'assignee', 'id']; 19 | dataSource: MatTableDataSource = new MatTableDataSource(); 20 | paginator: any; 21 | sort: any; 22 | 23 | constructor(private taskService: TaskService, private router: Router, private dialog: MatDialog) { 24 | } 25 | 26 | @ViewChild(MatPaginator) 27 | set pagination(paginator: MatPaginator) { 28 | this.paginator = paginator; 29 | this.dataSource.paginator = this.paginator; 30 | } 31 | 32 | @ViewChild(MatSort) 33 | set sorting(sort: MatSort) { 34 | this.sort = sort; 35 | this.dataSource.sort = this.sort; 36 | } 37 | 38 | ngOnInit() { 39 | this.taskService.fetchAllTasks().subscribe(res => { 40 | this.tasks = res; 41 | }, err => { 42 | if (err.status === 401) { 43 | this.router.navigate(['/login']); 44 | } else { 45 | this.showError(err); 46 | } 47 | }, () => { 48 | this.areTasksLoaded = true; 49 | this.dataSource = new MatTableDataSource(this.tasks); 50 | this.tasksAssigneeIsNull = this.tasks.filter((task: Task) => task.assignee == null); 51 | }); 52 | } 53 | 54 | seeTask(id: number) { 55 | this.router.navigate(['/tasks', id]); 56 | } 57 | 58 | addTask() { 59 | this.router.navigate(['/tasks/add']); 60 | } 61 | 62 | goToAssignment() { 63 | this.router.navigate(['/assignment']); 64 | } 65 | 66 | applyFilter(filterValue: string) { 67 | this.dataSource.filter = filterValue.trim().toLowerCase(); 68 | } 69 | 70 | showError(err) { 71 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 72 | width: '700px', 73 | data: { 74 | error: err.error, 75 | status: err.status 76 | } 77 | }); 78 | 79 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/app/security/login/login.component.html: -------------------------------------------------------------------------------- 1 | Sign in 2 |
3 | 4 | 5 | Email 6 | 7 | 8 | 9 | 10 | Password 11 | 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /src/app/security/login/login.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/security/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import {LoginService} from '../../services/login.service'; 4 | import {Token} from '../../token'; 5 | import {FormControl, FormGroup, Validators} from "@angular/forms"; 6 | import {ErrorDialogComponent} from "../../custom/error-dialog/error-dialog.component"; 7 | import {MatDialog} from "@angular/material"; 8 | 9 | @Component({ 10 | selector: 'app-login', 11 | templateUrl: './login.component.html', 12 | styleUrls: ['./login.component.scss'] 13 | }) 14 | export class LoginComponent { 15 | 16 | form: FormGroup; 17 | email: FormControl; 18 | password: FormControl; 19 | 20 | constructor(private router: Router, 21 | private loginService: LoginService, 22 | private token: Token, 23 | private dialog: MatDialog) { 24 | this.setupFormControls(); 25 | this.form = new FormGroup({ 26 | "email": this.email, 27 | "password": this.password 28 | }); 29 | } 30 | setupFormControls() { 31 | this.email = new FormControl('', [ 32 | Validators.required, 33 | Validators.email 34 | ]); 35 | this.password = new FormControl('', [ 36 | Validators.required 37 | ]); 38 | } 39 | 40 | 41 | login() { 42 | this.loginService.login(this.form.get('email').value, this.form.get('password').value).subscribe(res => { 43 | this.token.saveToken(res.token); 44 | }, err => { 45 | if (err.status == 401) { 46 | this.router.navigate(['/login']); 47 | } else { 48 | this.showError(err); 49 | } 50 | }, () => { 51 | this.loginService.fetchUser().subscribe(res => { 52 | if (!res.passwordValid) { 53 | this.router.navigate(['employees', res.id, 'validate']); 54 | } else { 55 | this.router.navigate(['employees']); 56 | } 57 | }, err => { 58 | this.showError(err); 59 | }); 60 | }); 61 | } 62 | 63 | showError(err) { 64 | this.dialog.open(ErrorDialogComponent, { 65 | width: '700px', 66 | data: { 67 | error: err.error, 68 | status: err.status 69 | } 70 | }); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/app/security/validate/validate.component.html: -------------------------------------------------------------------------------- 1 | Validate password 2 |
3 | 4 | Password 5 | 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /src/app/security/validate/validate.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/security/validate/validate.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {LoginService} from '../../services/login.service'; 3 | import {ActivatedRoute} from '@angular/router'; 4 | import {FormControl, FormGroup, Validators} from "@angular/forms"; 5 | 6 | @Component({ 7 | selector: 'app-validate', 8 | templateUrl: './validate.component.html', 9 | styleUrls: ['./validate.component.scss'] 10 | }) 11 | export class ValidateComponent { 12 | 13 | form: FormGroup; 14 | password: FormControl; 15 | 16 | constructor(private loginService: LoginService, 17 | private route: ActivatedRoute) { 18 | this.password = new FormControl('', [ 19 | Validators.required 20 | ]); 21 | this.form = new FormGroup({ 22 | "password": this.password 23 | }); 24 | } 25 | 26 | submit() { 27 | this.loginService.validateUser(this.route.snapshot.params['id'], this.form.get('password').value); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/app/services/complaint.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Complaint, ShopServiceRequest} from '../types'; 3 | import {Observable} from 'rxjs'; 4 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class ComplaintService { 11 | 12 | private readonly httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 17 | } 18 | 19 | fetchAllComplaints(): Observable> { 20 | return this.http.get>(BACKEND_URL + 'complaints', {headers: this.httpHeaders}); 21 | } 22 | 23 | fetchOneComplaint(id: number): Observable { 24 | return this.http.get(BACKEND_URL + 'complaints/' + id, {headers: this.httpHeaders}); 25 | } 26 | 27 | addOneComplaint(request: ShopServiceRequest): Observable { 28 | return this.http.post(BACKEND_URL + 'complaints', request, {headers: this.httpHeaders}); 29 | } 30 | 31 | updateComplaintStatus(status: string, id: number): Observable { 32 | return this.http.put(BACKEND_URL + 'complaints/' + id, status, {headers: this.httpHeaders}); 33 | } 34 | 35 | updateComplaintResolution(resolution: string, id: number): Observable { 36 | return this.http.put(BACKEND_URL + 'complaints/' + id + '/resolution', resolution, 37 | {headers: this.httpHeaders}); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/app/services/delivery.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {Delivery, DeliveryItemRequest, DeliveryRequest} from '../types'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class DeliveryService { 11 | 12 | private httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 17 | } 18 | 19 | fetchAllDeliveries(): Observable> { 20 | return this.http.get>(BACKEND_URL + 'deliveries', {headers: this.httpHeaders}); 21 | } 22 | 23 | fetchOneDelivery(id: number): Observable { 24 | return this.http.get(BACKEND_URL + 'deliveries/' + id, {headers: this.httpHeaders}); 25 | } 26 | 27 | addNewDelivery(request: DeliveryRequest): Observable { 28 | return this.http.post(BACKEND_URL + 'deliveries', request, {headers: this.httpHeaders}); 29 | } 30 | 31 | confirmDelivery(id: number): Observable { 32 | return this.http.post(BACKEND_URL + 'deliveries/' + id, null, {headers: this.httpHeaders}); 33 | } 34 | 35 | getRecommendations(): Observable> { 36 | return this.http.get>(BACKEND_URL + 'deliveries/recommended-delivery', 37 | {headers: this.httpHeaders}); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/app/services/email.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Router} from '@angular/router'; 4 | import {Observable} from 'rxjs'; 5 | import {EmailEntity, EmailEntityRequest} from '../types'; 6 | import {ErrorDialogComponent} from "../custom/error-dialog/error-dialog.component"; 7 | import {MatDialog} from "@angular/material"; 8 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 9 | 10 | @Injectable({ 11 | providedIn: 'root' 12 | }) 13 | export class EmailService { 14 | 15 | private httpHeaders: HttpHeaders; 16 | 17 | constructor(private http: HttpClient, private router: Router, private dialog: MatDialog) { 18 | this.httpHeaders = new HttpHeaders() 19 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 20 | } 21 | 22 | fetchReceivedEmails(): Observable> { 23 | return this.http.get>(BACKEND_URL + 'emails/inbox', 24 | {headers: this.httpHeaders}); 25 | } 26 | 27 | fetchSentEmails(): Observable> { 28 | return this.http.get>(BACKEND_URL + 'emails/outbox', 29 | {headers: this.httpHeaders}); 30 | } 31 | 32 | sendEmail(request: EmailEntityRequest): Observable { 33 | return this.http.post(BACKEND_URL + 'emails', request, 34 | {headers: this.httpHeaders}); 35 | } 36 | 37 | reply(request: EmailEntityRequest, id: number): Observable { 38 | return this.http.post(BACKEND_URL + 'emails/' + id, request, 39 | {headers: this.httpHeaders}); 40 | } 41 | 42 | fetchConversation(id: number): Observable> { 43 | return this.http.get>(BACKEND_URL + 'emails/' + id, 44 | {headers: this.httpHeaders}); 45 | } 46 | 47 | removeMessage(id: number) { 48 | this.http.delete(BACKEND_URL + 'emails/' + id, {headers: this.httpHeaders}) 49 | .subscribe(() => { 50 | }, 51 | err => { 52 | if (err.status == 401) { 53 | this.router.navigate(['/login']); 54 | } else { 55 | this.showError(err); 56 | } 57 | }, 58 | () => { 59 | this.router.navigate(['/emails/inbox']); 60 | }); 61 | } 62 | 63 | showError(err) { 64 | this.dialog.open(ErrorDialogComponent, { 65 | width: '700px', 66 | data: { 67 | error: err.error, 68 | status: err.status 69 | } 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/app/services/holiday.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 4 | import {Holiday, HolidayRequest} from '../types'; 5 | import {Observable} from 'rxjs'; 6 | import {ErrorDialogComponent} from "../custom/error-dialog/error-dialog.component"; 7 | import {MatDialog} from "@angular/material"; 8 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 9 | 10 | @Injectable({ 11 | providedIn: 'root' 12 | }) 13 | export class HolidayService { 14 | 15 | private httpHeaders: HttpHeaders; 16 | 17 | constructor(private http: HttpClient, private router: Router, private dialog: MatDialog) { 18 | this.httpHeaders = new HttpHeaders() 19 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 20 | } 21 | 22 | fetchHolidays(employeeId: number): Observable> { 23 | return this.http.get>(BACKEND_URL + 'employees/' + employeeId + '/holidays', 24 | {headers: this.httpHeaders}); 25 | } 26 | 27 | addHoliday(request: HolidayRequest, employeeId: number) { 28 | this.http.post(BACKEND_URL + 'employees/' + employeeId + '/holidays', 29 | request, {headers: this.httpHeaders}) 30 | .subscribe(() => { 31 | }, 32 | err => { 33 | if (err.status == 401) { 34 | this.router.navigate(['/login']); 35 | } else { 36 | this.showError(err); 37 | } 38 | }, 39 | () => { 40 | this.router.navigate(['/employees', employeeId]); 41 | }); 42 | } 43 | 44 | fetchHolidaysToApprove(managerId: number): Observable> { 45 | return this.http.get>(BACKEND_URL + 'employees/' + managerId + 46 | '/subordinates/holiday-requests', {headers: this.httpHeaders}); 47 | } 48 | 49 | manageHolidays(managerId: number, employeeId: number, holidayId: number, approve: string): Observable { 50 | return this.http.post(BACKEND_URL + 'employees/' + managerId + '/subordinates/' 51 | + employeeId + '/holidays', holidayId, { 52 | headers: this.httpHeaders, 53 | params: { 54 | approve: approve 55 | } 56 | }); 57 | } 58 | 59 | showError(err) { 60 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 61 | width: '700px', 62 | data: { 63 | error: err.error, 64 | status: err.status 65 | } 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/app/services/item.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {Item, ItemRequest} from '../types'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class ItemService { 11 | 12 | private httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL) 17 | .set('Content-Type', 'application/json'); 18 | } 19 | 20 | fetchAllItems(): Observable> { 21 | return this.http.get>(BACKEND_URL + 'items', {headers: this.httpHeaders}); 22 | } 23 | 24 | fetchOneItem(id: number): Observable { 25 | return this.http.get(BACKEND_URL + 'items/' + id, {headers: this.httpHeaders}); 26 | } 27 | 28 | addNewItem(request: ItemRequest): Observable { 29 | return this.http.post(BACKEND_URL + 'items', request, {headers: this.httpHeaders}); 30 | } 31 | 32 | setNewPrice(id: number, price: number): Observable { 33 | return this.http.post(BACKEND_URL + 'items/' + id, price, {headers: this.httpHeaders}); 34 | } 35 | 36 | supplyItem(id: number, quantity: number): Observable { 37 | return this.http.post(BACKEND_URL + 'items/' + id + '/supply', 38 | quantity, {headers: this.httpHeaders}); 39 | } 40 | 41 | buyItem(id: number, quantity: number): Observable { 42 | return this.http.post(BACKEND_URL + 'items/' + id + '/buy', 43 | quantity, {headers: this.httpHeaders}); 44 | } 45 | 46 | setSpecialOffer(percentOff: string, query: string): Observable> { 47 | return this.http.post>(BACKEND_URL + 'set-special-offer', '', { 48 | headers: this.httpHeaders, 49 | params: { 50 | percentOff: percentOff, 51 | query: query 52 | } 53 | }); 54 | } 55 | 56 | cancelSpecialOffer(): Observable> { 57 | return this.http.post>(BACKEND_URL + 'cancel-special-offer', '', 58 | {headers: this.httpHeaders}); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/app/services/login.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {Employee} from '../types'; 5 | import {Router} from '@angular/router'; 6 | import {ErrorDialogComponent} from "../custom/error-dialog/error-dialog.component"; 7 | import {MatDialog} from "@angular/material"; 8 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 9 | 10 | @Injectable({ 11 | providedIn: 'root' 12 | }) 13 | export class LoginService { 14 | 15 | private httpHeaders: HttpHeaders; 16 | 17 | constructor(private http: HttpClient, private router: Router, private dialog: MatDialog) { 18 | this.httpHeaders = new HttpHeaders() 19 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 20 | } 21 | 22 | login(email: string, password: string): Observable { 23 | const credentials = {email: email, password: password}; 24 | return this.http.post(BACKEND_URL + 'generate-token', credentials, 25 | {headers: this.httpHeaders}); 26 | } 27 | 28 | fetchUser(): Observable { 29 | return this.http.get(BACKEND_URL + 'logged-in-user', 30 | {headers: this.httpHeaders}); 31 | } 32 | 33 | validateUser(id: string, password: string) { 34 | this.http.post(BACKEND_URL + 'employees/' + id + '/validate-password', password, 35 | {headers: this.httpHeaders}).subscribe(res => {}, 36 | err => { 37 | if (err.status == 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err); 41 | } 42 | }, () => { 43 | this.router.navigate(['employees', id]); 44 | }); 45 | } 46 | 47 | showError(err) { 48 | this.dialog.open(ErrorDialogComponent, { 49 | width: '700px', 50 | data: { 51 | error: err.error, 52 | status: err.status 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/app/services/notification.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Notification, NotificationRequest} from '../types'; 4 | import {Observable} from 'rxjs'; 5 | import {BACKEND_URL, FRONTEND_URL} from '../globals'; 6 | 7 | @Injectable() 8 | export class NotificationService { 9 | 10 | private httpHeaders: HttpHeaders; 11 | 12 | constructor(private http: HttpClient) { 13 | this.httpHeaders = new HttpHeaders() 14 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 15 | } 16 | 17 | fetchAllNotifications(): Observable> { 18 | return this.http.get>(BACKEND_URL + 'notifications', {headers: this.httpHeaders}); 19 | } 20 | 21 | fetchOneNotification(id: number): Observable { 22 | return this.http.get(BACKEND_URL + 'notifications/' + id, {headers: this.httpHeaders}); 23 | } 24 | 25 | fetchNotificationsByRecipient(id: number): Observable> { 26 | return this.http.get>(BACKEND_URL + 'employees/' + id + '/notifications', {headers: this.httpHeaders}); 27 | } 28 | 29 | addNotification(notificationRequest: NotificationRequest): Observable { 30 | return this.http.post(BACKEND_URL + 'notifications', notificationRequest, {headers: this.httpHeaders}); 31 | } 32 | 33 | setNextState(id: number): Observable { 34 | return this.http.put(BACKEND_URL + 'notifications/' + id, {headers: this.httpHeaders}); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/services/order.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {Order, ShopServiceRequest} from '../types'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class OrderService { 11 | 12 | private readonly httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 17 | } 18 | 19 | fetchAllOrders(): Observable> { 20 | return this.http.get>(BACKEND_URL + 'orders', {headers: this.httpHeaders}); 21 | } 22 | 23 | fetchOneOrder(id: number): Observable { 24 | return this.http.get(BACKEND_URL + 'orders/' + id, {headers: this.httpHeaders}); 25 | } 26 | 27 | addOneOrder(orderRequest: ShopServiceRequest): Observable { 28 | return this.http.post(BACKEND_URL + 'orders', orderRequest, {headers: this.httpHeaders}); 29 | } 30 | 31 | updateOrderStatus(status: string, id: number): Observable { 32 | return this.http.put(BACKEND_URL + 'orders/' + id, status, {headers: this.httpHeaders}); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/app/services/planning.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs/index'; 4 | import {DailyPlan, DailyPlanRequest, SpecialPlan, SpecialPlanRequest} from '../types'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class PlanningService { 11 | 12 | private httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 17 | } 18 | 19 | fetchDailyPlan(): Observable { 20 | return this.http.get(BACKEND_URL + 'daily-plan', {headers: this.httpHeaders}); 21 | } 22 | 23 | updateDailyPlan(request: DailyPlanRequest): Observable { 24 | return this.http.put(BACKEND_URL + 'daily-plan', request, 25 | {headers: this.httpHeaders}); 26 | } 27 | 28 | fetchSpecialPlans(): Observable> { 29 | return this.http.get>(BACKEND_URL + 'special-plans', 30 | {headers: this.httpHeaders}); 31 | } 32 | 33 | fetchSpecialPlan(day: string): Observable { 34 | return this.http.get(BACKEND_URL + 'special-plan', { 35 | headers: this.httpHeaders, 36 | params: { 37 | day: day 38 | } 39 | }); 40 | } 41 | 42 | addSpecialPlan(request: SpecialPlanRequest): Observable { 43 | return this.http.post(BACKEND_URL + 'special-plan', request, 44 | {headers: this.httpHeaders}); 45 | } 46 | 47 | countScheduledOrders(when: string): Observable { 48 | return this.http.get(BACKEND_URL + 'scheduled-orders', { 49 | headers: this.httpHeaders, 50 | params: { 51 | when: when 52 | } 53 | }); 54 | } 55 | 56 | countScheduledReturns(when: string): Observable { 57 | return this.http.get(BACKEND_URL + 'scheduled-returns', { 58 | headers: this.httpHeaders, 59 | params: { 60 | when: when 61 | } 62 | }); 63 | } 64 | 65 | countScheduledComplaints(when: string): Observable { 66 | return this.http.get(BACKEND_URL + 'scheduled-complaints', { 67 | headers: this.httpHeaders, 68 | params: { 69 | when: when 70 | } 71 | }); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/app/services/report.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {CurrentReport, EstimatedCostsRequest, ExpenseRequest, MonthlyReport} from '../types'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class ReportService { 11 | 12 | private httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL) 17 | .set('Content-Type', 'application/json'); 18 | } 19 | 20 | fetchAllReports(): Observable> { 21 | return this.http.get>(BACKEND_URL + 'reports', 22 | {headers: this.httpHeaders}); 23 | } 24 | 25 | fetchOneReport(id: number): Observable { 26 | return this.http.get(BACKEND_URL + 'reports/' + id, 27 | {headers: this.httpHeaders}); 28 | } 29 | 30 | fetchCurrentReport(): Observable { 31 | return this.http.get(BACKEND_URL + 'current-report', 32 | {headers: this.httpHeaders}); 33 | } 34 | 35 | recalculateCosts(request: EstimatedCostsRequest): Observable { 36 | return this.http.put(BACKEND_URL + 'current-report', request, 37 | {headers: this.httpHeaders}); 38 | } 39 | 40 | addIncome(amount: number): Observable { 41 | return this.http.post(BACKEND_URL + 'current-report/income', amount, 42 | {headers: this.httpHeaders}); 43 | } 44 | 45 | addExpense(request: ExpenseRequest): Observable { 46 | return this.http.post(BACKEND_URL + 'current-report/expense', request, 47 | {headers: this.httpHeaders}); 48 | } 49 | 50 | fetchRecommendations(): Observable { 51 | return this.http.get(BACKEND_URL + 'current-report/recommended-recalculations', 52 | {headers: this.httpHeaders}); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/services/return.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Return, ShopServiceRequest} from '../types'; 3 | import {Observable} from 'rxjs'; 4 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 5 | import {BACKEND_URL, FRONTEND_URL, ReturnStatus} from "../globals"; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class ReturnService { 11 | 12 | private readonly httpHeaders: HttpHeaders; 13 | 14 | constructor(private http: HttpClient) { 15 | this.httpHeaders = new HttpHeaders() 16 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 17 | } 18 | 19 | fetchAllReturns(): Observable> { 20 | return this.http.get>(BACKEND_URL + 'returns', {headers: this.httpHeaders}); 21 | } 22 | 23 | fetchOneReturn(id: number): Observable { 24 | return this.http.get(BACKEND_URL + 'returns/' + id, {headers: this.httpHeaders}); 25 | } 26 | 27 | addOneReturn(request: ShopServiceRequest): Observable { 28 | return this.http.post(BACKEND_URL + 'returns', request, {headers: this.httpHeaders}); 29 | } 30 | 31 | updateReturnStatus(status: string, id: number): Observable { 32 | return this.http.put(BACKEND_URL + 'returns/' + id, status, {headers: this.httpHeaders}); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/app/services/setup.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {AdminRequest, Employee} from "../types"; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable() 8 | export class SetupService { 9 | 10 | private httpHeaders: HttpHeaders; 11 | 12 | constructor(private http: HttpClient) { 13 | this.httpHeaders = new HttpHeaders() 14 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 15 | } 16 | 17 | checkSetup(): Observable { 18 | return this.http.get(BACKEND_URL + 'check-setup', {headers: this.httpHeaders}); 19 | } 20 | 21 | setupAdmin(request: AdminRequest): Observable { 22 | return this.http.post(BACKEND_URL + 'setup-admin', request, {headers: this.httpHeaders}); 23 | } 24 | 25 | setupTeams(): Observable { 26 | return this.http.post(BACKEND_URL + 'setup-teams', {headers: this.httpHeaders}); 27 | } 28 | 29 | setupDailyPlan(): Observable { 30 | return this.http.post(BACKEND_URL + 'setup-daily-plan', {headers: this.httpHeaders}); 31 | } 32 | 33 | setupReports(): Observable { 34 | return this.http.post(BACKEND_URL + 'setup-reports', {headers: this.httpHeaders}); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/app/services/suggestion.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Suggestion, SuggestionRequest} from '../types'; 4 | import {Observable} from 'rxjs'; 5 | import {BACKEND_URL, FRONTEND_URL} from '../globals'; 6 | 7 | @Injectable() 8 | export class SuggestionService { 9 | 10 | private readonly httpHeaders: HttpHeaders; 11 | 12 | constructor(private http: HttpClient) { 13 | this.httpHeaders = new HttpHeaders() 14 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 15 | } 16 | 17 | fetchAllSuggestions(): Observable> { 18 | return this.http.get>(BACKEND_URL + 'suggestions', {headers: this.httpHeaders}); 19 | } 20 | 21 | fetchOneSuggestion(id: number): Observable { 22 | return this.http.get(BACKEND_URL + 'suggestions/' + id, {headers: this.httpHeaders}); 23 | } 24 | 25 | addSuggestion(suggestionRequest: SuggestionRequest): Observable { 26 | return this.http.post(BACKEND_URL + 'suggestions', suggestionRequest, {headers: this.httpHeaders}); 27 | } 28 | 29 | setNextPhase(id: number): Observable { 30 | return this.http.put(BACKEND_URL + 'suggestions/' + id, {headers: this.httpHeaders}); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/app/services/task.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {AssignmentRequest, Indicators, Task, TaskRequest} from '../types'; 4 | import {Observable} from 'rxjs'; 5 | import {BACKEND_URL, FRONTEND_URL} from '../globals'; 6 | 7 | @Injectable() 8 | export class TaskService { 9 | 10 | private readonly httpHeaders: HttpHeaders; 11 | 12 | constructor(private http: HttpClient) { 13 | this.httpHeaders = new HttpHeaders() 14 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 15 | } 16 | 17 | fetchAllTasks(): Observable> { 18 | return this.http.get>(BACKEND_URL + 'tasks', {headers: this.httpHeaders}); 19 | } 20 | 21 | fetchOneTask(id: number): Observable { 22 | return this.http.get(BACKEND_URL + 'tasks/' + id, {headers: this.httpHeaders}); 23 | } 24 | 25 | fetchTasksByAssignee(id: number): Observable> { 26 | return this.http.get>(BACKEND_URL + 'kanban/' + id, {headers: this.httpHeaders}); 27 | } 28 | 29 | fetchTasksByAssigneeIsNull(): Observable> { 30 | return this.http.get>(BACKEND_URL + 'assignment', {headers: this.httpHeaders}); 31 | } 32 | 33 | addTask(taskRequest: TaskRequest): Observable { 34 | return this.http.post(BACKEND_URL + 'tasks', taskRequest, {headers: this.httpHeaders}); 35 | } 36 | 37 | assignToEmployees(assignmentRequest: AssignmentRequest): Observable> { 38 | return this.http.put>(BACKEND_URL + 'assignment', assignmentRequest, {headers: this.httpHeaders}); 39 | } 40 | 41 | setNextCategory(id: number): Observable { 42 | return this.http.put(BACKEND_URL + 'tasks/' + id, {headers: this.httpHeaders}); 43 | } 44 | 45 | assignToMe(id: number): Observable { 46 | return this.http.put(BACKEND_URL + 'tasks/' + id + '/assign', {headers: this.httpHeaders}); 47 | } 48 | 49 | fetchIndicators(id: number): Observable { 50 | return this.http.get(BACKEND_URL + 'indicators/' + id, {headers: this.httpHeaders}); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/services/team.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Team} from '../types'; 4 | import {Observable} from 'rxjs'; 5 | import {BACKEND_URL, FRONTEND_URL} from "../globals"; 6 | 7 | @Injectable() 8 | export class TeamService { 9 | 10 | private httpHeaders: HttpHeaders; 11 | 12 | constructor(private http: HttpClient) { 13 | this.httpHeaders = new HttpHeaders() 14 | .set('Access-Control-Allow-Origin', FRONTEND_URL); 15 | } 16 | 17 | fetchAllTeams(): Observable> { 18 | return this.http.get>(BACKEND_URL + 'teams', {headers: this.httpHeaders}); 19 | } 20 | 21 | fetchOneTeam(id: number): Observable { 22 | return this.http.get(BACKEND_URL + 'teams/' + id, {headers: this.httpHeaders}); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/setup/setup.component.html: -------------------------------------------------------------------------------- 1 | Fill system admin details 2 |
3 | 4 | 5 | First name 6 | 7 | 8 | 9 | 10 | Last name 11 | 12 | 13 | 14 | 15 | Email 16 | 17 | {{getErrorMessage()}} 18 | 19 | 20 | 21 | Password 22 | 23 | 24 | 25 | 26 | Account number 27 | 29 | 26 digits 30 | 31 | 32 | 33 | Salary 34 | 35 | 36 | 37 | 38 |
39 | -------------------------------------------------------------------------------- /src/app/setup/setup.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-resolution-dialog/complaint-resolution-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 |
4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-resolution-dialog/complaint-resolution-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | display: inline-flex; 3 | } 4 | 5 | button { 6 | margin-left: 10px; 7 | margin-top: 10px; 8 | align-items: center; 9 | } 10 | 11 | mat-progress-spinner { 12 | margin: auto; 13 | } 14 | 15 | .error { 16 | font-style: italic; 17 | color: darkred; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-resolution-dialog/complaint-resolution-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {Complaint} from "../../../types"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | import {ComplaintService} from "../../../services/complaint.service"; 5 | 6 | export interface DialogData { 7 | status: string[]; 8 | complaint: Complaint; 9 | } 10 | 11 | @Component({ 12 | selector: 'app-complaint-resolution-dialog', 13 | templateUrl: './complaint-resolution-dialog.component.html', 14 | styleUrls: ['./complaint-resolution-dialog.component.scss'] 15 | }) 16 | export class ComplaintResolutionDialogComponent { 17 | 18 | showSpinner: boolean; 19 | error: string; 20 | shouldShowError: boolean; 21 | 22 | constructor(public dialogRef: MatDialogRef, 23 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 24 | private complaintService: ComplaintService) { 25 | } 26 | 27 | cancel() { 28 | this.dialogRef.close(null); 29 | } 30 | 31 | submit(s: string) { 32 | this.showSpinner = true; 33 | this.complaintService.updateComplaintResolution(s, this.data.complaint.id).subscribe(res => { 34 | }, err => { 35 | this.shouldShowError = true; 36 | this.error = err.error; 37 | this.showSpinner = false; 38 | }, () => { 39 | this.cancel(); 40 | }); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-status-dialog/complaint-status-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 |
4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-status-dialog/complaint-status-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | display: inline-flex; 3 | } 4 | 5 | button { 6 | margin-left: 10px; 7 | margin-top: 10px; 8 | align-items: center; 9 | } 10 | 11 | mat-progress-spinner { 12 | margin: auto; 13 | } 14 | 15 | .error { 16 | font-style: italic; 17 | color: darkred; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint-status-dialog/complaint-status-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {Complaint, ExpenseRequest} from "../../../types"; 3 | import {ComplaintService} from "../../../services/complaint.service"; 4 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 5 | import {ReportService} from "../../../services/report.service"; 6 | import {ItemService} from "../../../services/item.service"; 7 | import {ComplaintStatus, ExpenseType} from "../../../globals"; 8 | 9 | export interface DialogData { 10 | status: string[]; 11 | complaint: Complaint; 12 | } 13 | 14 | @Component({ 15 | selector: 'app-complaint-status-dialog', 16 | templateUrl: './complaint-status-dialog.component.html', 17 | styleUrls: ['./complaint-status-dialog.component.scss'] 18 | }) 19 | export class ComplaintStatusDialogComponent { 20 | 21 | showSpinner: boolean; 22 | error: string; 23 | shouldShowError: boolean; 24 | 25 | constructor(public dialogRef: MatDialogRef, 26 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 27 | private complaintService: ComplaintService, 28 | private itemService: ItemService, 29 | private reportService: ReportService) { 30 | } 31 | 32 | cancel() { 33 | this.dialogRef.close(null); 34 | } 35 | 36 | submit(s: string) { 37 | this.showSpinner = true; 38 | this.complaintService.updateComplaintStatus(s, this.data.complaint.id) 39 | .subscribe(res => { 40 | this.data.complaint = res; 41 | if (this.data.complaint.status === ComplaintStatus.MONEY_RETURNED) { 42 | const expenseRequest: ExpenseRequest = { 43 | expenseType: ExpenseType.UNEXPECTED, 44 | amount: this.data.complaint.value 45 | }; 46 | this.reportService.addExpense(expenseRequest).subscribe(res => { 47 | }); 48 | } else if (this.data.complaint.status === ComplaintStatus.NEW_ITEM_SENT) { 49 | this.data.complaint.deliveryItems.forEach(deliveryItem => { 50 | this.itemService.buyItem(deliveryItem.item.id, deliveryItem.quantity).subscribe(res => { 51 | }); 52 | }); 53 | } 54 | }, err => { 55 | this.shouldShowError = true; 56 | this.error = err.error; 57 | this.showSpinner = false; 58 | }, () => { 59 | this.cancel(); 60 | }); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaint/complaint.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | margin-right: 5px; 6 | } 7 | 8 | .customer-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaints/complaints.component.html: -------------------------------------------------------------------------------- 1 | Complaints 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 |
Index {{row.id}} Customer name {{row.firstName}} {{row.lastName}} Current status {{row.status}} Requested resolution {{row.requestedResolution}} Resolution {{row.resolution}} Deadline {{row.scheduledFor}}
43 | 44 | 45 |
46 |
47 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaints/complaints.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/complaints/complaints/complaints.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {Complaint} from '../../../types'; 3 | import {ComplaintService} from '../../../services/complaint.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-complaints', 10 | templateUrl: './complaints.component.html', 11 | styleUrls: ['./complaints.component.scss'] 12 | }) 13 | export class ComplaintsComponent implements OnInit { 14 | 15 | complaints: Array; 16 | areComplaintsLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private complaintService: ComplaintService, private router: Router, private dialog: MatDialog) { 27 | } 28 | 29 | ngOnInit() { 30 | this.fetchComplaints(); 31 | } 32 | 33 | fetchComplaints() { 34 | this.complaintService.fetchAllComplaints().subscribe(res => { 35 | this.complaints = res; 36 | }, err => { 37 | if (err.status == 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err); 41 | } 42 | }, () => { 43 | this.areComplaintsLoaded = true; 44 | this.dataSource = new MatTableDataSource(this.complaints); 45 | }); 46 | } 47 | 48 | seeComplaint(id: number) { 49 | this.router.navigate(['/complaints', id]); 50 | } 51 | 52 | addComplaint() { 53 | this.router.navigate(['shop-service/add'], { 54 | queryParams: { 55 | service: 'complaint' 56 | } 57 | }); 58 | } 59 | 60 | showError(err) { 61 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 62 | width: '700px', 63 | data: { 64 | error: err.error, 65 | status: err.status 66 | } 67 | }); 68 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/add-delivery/add-delivery.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/deliveries/deliveries.component.html: -------------------------------------------------------------------------------- 1 | Deliveries 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 27 |
Index {{row.id}} Scheduled for {{row.scheduledFor}} Value {{row.value}}
28 | 29 | 30 |
31 |
32 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/deliveries/deliveries.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/deliveries/deliveries.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {DeliveryService} from '../../../services/delivery.service'; 3 | import {Router} from '@angular/router'; 4 | import {Delivery} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from '@angular/material'; 6 | import {ErrorDialogComponent} from '../../../custom/error-dialog/error-dialog.component'; 7 | 8 | @Component({ 9 | selector: 'app-deliveries', 10 | templateUrl: './deliveries.component.html', 11 | styleUrls: ['./deliveries.component.scss'] 12 | }) 13 | export class DeliveriesComponent implements OnInit { 14 | 15 | areDeliveriesLoaded = false; 16 | deliveries: Array; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | constructor(private deliveryService: DeliveryService, 21 | private router: Router, 22 | private dialog: MatDialog) { 23 | } 24 | 25 | @ViewChild(MatPaginator) 26 | set pagination(paginator: MatPaginator) { 27 | this.paginator = paginator; 28 | this.dataSource.paginator = this.paginator; 29 | } 30 | 31 | ngOnInit() { 32 | this.fetchDeliveries(); 33 | } 34 | 35 | fetchDeliveries() { 36 | this.deliveryService.fetchAllDeliveries().subscribe(res => { 37 | this.deliveries = res; 38 | }, err => { 39 | if (err.status == 401) { 40 | this.router.navigate(['/login']); 41 | } else { 42 | this.showError(err); 43 | } 44 | }, () => { 45 | this.areDeliveriesLoaded = true; 46 | this.dataSource = new MatTableDataSource(this.deliveries); 47 | }); 48 | } 49 | 50 | seeDelivery(id: number) { 51 | this.router.navigate(['/deliveries', id]); 52 | } 53 | 54 | addDelivery() { 55 | this.router.navigate(['deliveries/add']); 56 | } 57 | 58 | showError(err) { 59 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 60 | width: '700px', 61 | data: { 62 | error: err.error, 63 | status: err.status 64 | } 65 | }); 66 | 67 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/delivery/delivery.component.html: -------------------------------------------------------------------------------- 1 | Delivery #{{delivery.id}} 2 | 3 |
4 | 5 | 7 | Items 8 | 9 | 10 | 11 | {{deliveryItem.item.name}}, quantity: {{deliveryItem.quantity}} 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | calendar_today 20 | {{delivery.scheduledFor}} 21 | attach_money 22 | {{delivery.value}} 23 |
24 |
25 | 26 | 27 |
Delivery successfully went through.
28 |
29 | 30 |
31 | -------------------------------------------------------------------------------- /src/app/shop/deliveries/delivery/delivery.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | margin-right: 5px; 6 | } 7 | 8 | .delivery-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | 18 | .confirmed { 19 | color: limegreen; 20 | font-style: italic; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/shop/items/add-item/add-item.component.html: -------------------------------------------------------------------------------- 1 | Add item 2 |
3 | 4 | 5 | Name 6 | 7 | 8 | 9 | 10 | Stock price 11 | 12 | {{getStockErrorMessage()}} 13 | 14 | 15 | 16 | Price 17 | 18 | {{getPriceErrorMessage()}} 19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /src/app/shop/items/add-item/add-item.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/items/add-item/add-item.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {ItemService} from '../../../services/item.service'; 3 | import {Router} from '@angular/router'; 4 | import {Item, ItemRequest} from '../../../types'; 5 | import {FormControl, FormGroup, Validators} from "@angular/forms"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | import {MatDialog} from "@angular/material"; 8 | 9 | @Component({ 10 | selector: 'app-add-item', 11 | templateUrl: './add-item.component.html', 12 | styleUrls: ['./add-item.component.scss'] 13 | }) 14 | export class AddItemComponent { 15 | 16 | form: FormGroup; 17 | name: FormControl; 18 | stockPrice: FormControl; 19 | price: FormControl; 20 | itemRequest: ItemRequest; 21 | 22 | constructor(private itemService: ItemService, 23 | private router: Router, 24 | private dialog: MatDialog) { 25 | this.setupFormControls(); 26 | this.form = new FormGroup({ 27 | "name": this.name, 28 | "stockPrice": this.stockPrice, 29 | "price": this.price 30 | }); 31 | } 32 | 33 | setupFormControls() { 34 | this.name = new FormControl('', [ 35 | Validators.required 36 | ]); 37 | this.stockPrice = new FormControl('', [ 38 | Validators.required, 39 | Validators.pattern("^[0-9]*$"), 40 | ]); 41 | this.price = new FormControl('', [ 42 | Validators.required, 43 | Validators.pattern("^[0-9]*$"), 44 | ]); 45 | } 46 | 47 | submitForm() { 48 | this.itemRequest = { 49 | name: this.form.get('name').value, 50 | stockPrice: this.form.get('stockPrice').value, 51 | price: this.form.get('price').value 52 | }; 53 | let item: Item; 54 | this.itemService.addNewItem(this.itemRequest).subscribe(res => { 55 | item = res; 56 | }, err => { 57 | if (err.status == 401) { 58 | this.router.navigate(['/login']); 59 | } else { 60 | this.showError(err); 61 | } 62 | }, () => { 63 | this.router.navigate(['/items', item.id]); 64 | }); 65 | } 66 | 67 | getStockErrorMessage() { 68 | return this.stockPrice.hasError('pattern') ? 'Enter a number' : ''; 69 | } 70 | 71 | getPriceErrorMessage() { 72 | return this.price.hasError('pattern') ? 'Enter a number' : ''; 73 | } 74 | 75 | showError(err) { 76 | this.dialog.open(ErrorDialogComponent, { 77 | width: '700px', 78 | data: { 79 | error: err.error, 80 | status: err.status 81 | } 82 | }); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/app/shop/items/item/item.component.html: -------------------------------------------------------------------------------- 1 | {{item.name}} 2 | 3 |
4 | Quantity: {{item.quantity}} 5 | 6 | 7 | 8 | Current price: {{item.currentPrice}} PLN 9 | 10 | 11 | 12 | 13 | Base price: {{item.originalPrice}} PLN 14 | 15 | 16 | 17 | Stock price: {{item.stockPrice}} PLN 18 | 19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /src/app/shop/items/item/item.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/items/item/item.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Item} from '../../../types'; 3 | import {ItemService} from '../../../services/item.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {NewPriceDialogComponent} from "../new-price-dialog/new-price-dialog.component"; 6 | import {MatDialog} from "@angular/material"; 7 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 8 | 9 | @Component({ 10 | selector: 'app-item', 11 | templateUrl: './item.component.html', 12 | styleUrls: ['./item.component.scss'] 13 | }) 14 | export class ItemComponent implements OnInit { 15 | 16 | isItemLoaded = false; 17 | item: Item; 18 | 19 | constructor(private itemService: ItemService, 20 | private route: ActivatedRoute, 21 | private dialog: MatDialog, 22 | private router: Router) { 23 | } 24 | 25 | ngOnInit() { 26 | this.fetchItem(); 27 | } 28 | 29 | fetchItem() { 30 | this.itemService.fetchOneItem(this.route.snapshot.params['id']).subscribe(res => { 31 | this.item = res; 32 | }, err => { 33 | if (err.status == 401) { 34 | this.router.navigate(['/login']); 35 | } else { 36 | this.showError(err); 37 | } 38 | }, () => { 39 | this.isItemLoaded = true; 40 | }); 41 | } 42 | 43 | changePrice() { 44 | const dialogRef = this.dialog.open(NewPriceDialogComponent, { 45 | width: '350px', 46 | data: {id: this.item.id} 47 | }); 48 | 49 | dialogRef.afterClosed().subscribe(result => { 50 | this.isItemLoaded = false; 51 | this.fetchItem(); 52 | }); 53 | } 54 | 55 | showError(err) { 56 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 57 | width: '700px', 58 | data: { 59 | error: err.error, 60 | status: err.status 61 | } 62 | }); 63 | 64 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/items'])); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/shop/items/items/items.component.html: -------------------------------------------------------------------------------- 1 | Items 2 |
3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 44 |
Index {{row.id}} Name {{row.name}} Quantity {{row.quantity}} Stock price {{row.stockPrice}} Original price {{row.originalPrice}} Current price {{row.currentPrice}}
45 | 46 | 47 |
48 |
49 | -------------------------------------------------------------------------------- /src/app/shop/items/items/items.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | button { 4 | margin-left: 10px; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/shop/items/new-price-dialog/new-price-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/app/shop/items/new-price-dialog/new-price-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .error { 2 | font-style: italic; 3 | color: darkred; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/shop/items/new-price-dialog/new-price-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {ItemService} from "../../../services/item.service"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | 5 | export interface DialogData { 6 | id: number; 7 | } 8 | 9 | @Component({ 10 | selector: 'app-new-price-dialog', 11 | templateUrl: './new-price-dialog.component.html', 12 | styleUrls: ['./new-price-dialog.component.scss'] 13 | }) 14 | export class NewPriceDialogComponent { 15 | 16 | price = null; 17 | error: string; 18 | shouldShowError: boolean; 19 | 20 | constructor(public dialogRef: MatDialogRef, 21 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 22 | private itemService: ItemService) { 23 | } 24 | 25 | cancel() { 26 | this.dialogRef.close(null); 27 | } 28 | 29 | submit() { 30 | this.itemService.setNewPrice(this.data.id, this.price) 31 | .subscribe(() => { 32 | }, 33 | err => { 34 | this.shouldShowError = true; 35 | this.error = err.error; 36 | }, 37 | () => this.cancel() 38 | ); 39 | } 40 | 41 | isPriceValid() { 42 | const regexp = new RegExp('^\\d+\\.\\d{2}$'); 43 | return this.price != null && regexp.test(this.price.toString()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/shop/items/special-offer-dialog/special-offer-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Enter special offer details:

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/shop/items/special-offer-dialog/special-offer-dialog.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plkpiotr/erp-mes-frontend/70b2e4c0afa39ccaddbe098b573eaa9c57adf5b6/src/app/shop/items/special-offer-dialog/special-offer-dialog.component.scss -------------------------------------------------------------------------------- /src/app/shop/items/special-offer-dialog/special-offer-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from '@angular/core'; 2 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 3 | 4 | export interface DialogData { 5 | percentOff: string; 6 | query: string; 7 | } 8 | 9 | @Component({ 10 | selector: 'app-special-offer-dialog', 11 | templateUrl: './special-offer-dialog.component.html', 12 | styleUrls: ['./special-offer-dialog.component.scss'] 13 | }) 14 | export class SpecialOfferDialogComponent { 15 | 16 | constructor( 17 | public dialogRef: MatDialogRef, 18 | @Inject(MAT_DIALOG_DATA) public data: DialogData) { 19 | } 20 | 21 | isFormValid() { 22 | const regexp = new RegExp('\\d{2}'); 23 | return regexp.test(this.data.percentOff); 24 | } 25 | 26 | cancel() { 27 | this.dialogRef.close(null); 28 | } 29 | 30 | submit() { 31 | this.dialogRef.close(this.data); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/shop/orders/add-order/add-order.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/orders/order-status-dialog/order-status-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 |
4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /src/app/shop/orders/order-status-dialog/order-status-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | display: inline-flex; 3 | } 4 | 5 | button { 6 | margin-left: 10px; 7 | align-items: center; 8 | } 9 | 10 | mat-progress-spinner { 11 | margin: auto; 12 | } 13 | 14 | .error { 15 | font-style: italic; 16 | color: darkred; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/shop/orders/order-status-dialog/order-status-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | import {OrderService} from "../../../services/order.service"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | import {ItemService} from "../../../services/item.service"; 5 | import {ReportService} from "../../../services/report.service"; 6 | import {Order} from "../../../types"; 7 | 8 | export interface DialogData { 9 | status: string[]; 10 | order: Order; 11 | } 12 | 13 | @Component({ 14 | selector: 'app-order-status-dialog', 15 | templateUrl: './order-status-dialog.component.html', 16 | styleUrls: ['./order-status-dialog.component.scss'] 17 | }) 18 | export class OrderStatusDialogComponent { 19 | 20 | showSpinner: boolean; 21 | error: string; 22 | shouldShowError: boolean; 23 | 24 | constructor(public dialogRef: MatDialogRef, 25 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 26 | private orderService: OrderService, 27 | private itemService: ItemService, 28 | private reportService: ReportService) { 29 | } 30 | 31 | cancel() { 32 | this.dialogRef.close(null); 33 | } 34 | 35 | submit(s: string) { 36 | this.showSpinner = true; 37 | this.orderService.updateOrderStatus(s, this.data.order.id) 38 | .subscribe(res => { 39 | if (s === 'SENT') { 40 | const expenseRequest = { 41 | amount: this.data.order.value 42 | }; 43 | this.reportService.addIncome(expenseRequest.amount).subscribe(res => {}); 44 | } 45 | }, err => { 46 | this.shouldShowError = true; 47 | this.error = err.error; 48 | this.showSpinner = false; 49 | }, () => { 50 | this.cancel(); 51 | }); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/app/shop/orders/order/order.component.html: -------------------------------------------------------------------------------- 1 | Order #{{order.id}} 2 | 3 |
4 | 5 | 6 | 7 | Status: {{order.status}} 8 | 10 | 11 | 12 | 13 | Deadline: {{order.scheduledFor}} 14 | 15 | 16 | 17 | Value: {{order.value}} PLN 18 | 19 | 20 | 21 | 22 | 23 | 25 | Customer information 26 | 27 |
28 | face 29 | {{order.firstName}} {{order.lastName}} 30 | email 31 | {{order.email}} 32 | call 33 | {{order.phoneNumber}} 34 |
35 | location_city 36 | {{order.street}} {{order.houseNumber}}, {{order.postalCode}} {{order.city}} 37 |
38 |
39 | 40 | 41 | 43 | Items 44 | 45 | 46 | 47 | {{deliveryItem.item.name}}, price: {{deliveryItem.item.currentPrice}} PLN, quantity: {{deliveryItem.quantity}} 48 | 49 | 50 | 51 | 52 |
53 | -------------------------------------------------------------------------------- /src/app/shop/orders/order/order.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | margin-right: 5px; 6 | } 7 | 8 | .customer-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/shop/orders/order/order.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Order} from '../../../types'; 3 | import {OrderService} from '../../../services/order.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {OrderStatusDialogComponent} from "../order-status-dialog/order-status-dialog.component"; 6 | import {MatDialog} from "@angular/material"; 7 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 8 | import {Status} from "../../../globals"; 9 | 10 | @Component({ 11 | selector: 'app-order', 12 | templateUrl: './order.component.html', 13 | styleUrls: ['./order.component.scss'] 14 | }) 15 | export class OrderComponent implements OnInit { 16 | 17 | isOrderLoaded = false; 18 | order: Order; 19 | 20 | constructor(private orderService: OrderService, 21 | private route: ActivatedRoute, 22 | private dialog: MatDialog, 23 | private router: Router) { 24 | } 25 | 26 | ngOnInit() { 27 | this.fetchOrder(); 28 | } 29 | 30 | fetchOrder() { 31 | this.orderService.fetchOneOrder(this.route.snapshot.params['id']).subscribe(res => { 32 | this.order = res; 33 | }, err => { 34 | if (err.status == 401) { 35 | this.router.navigate(['/login']); 36 | } else { 37 | this.showError(err); 38 | } 39 | }, () => { 40 | this.isOrderLoaded = true; 41 | }); 42 | } 43 | 44 | updateOrderStatus() { 45 | let status = []; 46 | if (this.order.status === Status.WAITING_FOR_PAYMENT) { 47 | status = ['IN_PROGRESS', 'DECLINED']; 48 | } else if (this.order.status === Status.IN_PROGRESS) { 49 | status = ['SENT', 'DECLINED']; 50 | } 51 | const dialogRef = this.dialog.open(OrderStatusDialogComponent, { 52 | width: '350px', 53 | data: { 54 | status: status, 55 | order: this.order 56 | } 57 | }); 58 | 59 | dialogRef.afterClosed().subscribe(result => { 60 | this.isOrderLoaded = false; 61 | this.fetchOrder(); 62 | }); 63 | } 64 | 65 | showError(err) { 66 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 67 | width: '700px', 68 | data: { 69 | error: err.error, 70 | status: err.status 71 | } 72 | }); 73 | 74 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/orders'])); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/app/shop/orders/orders/orders.component.html: -------------------------------------------------------------------------------- 1 | Orders 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 37 |
Index {{row.id}} Customer name {{row.firstName}} {{row.lastName}} Status {{row.status}} Value {{row.value}} Deadline {{row.scheduledFor}}
38 | 39 | 40 |
41 |
42 | -------------------------------------------------------------------------------- /src/app/shop/orders/orders/orders.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/orders/orders/orders.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {Order} from '../../../types'; 3 | import {OrderService} from '../../../services/order.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-orders', 10 | templateUrl: './orders.component.html', 11 | styleUrls: ['./orders.component.scss'] 12 | }) 13 | export class OrdersComponent implements OnInit { 14 | 15 | orders: Array; 16 | areOrdersLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private orderService: OrderService, private router: Router, private dialog: MatDialog) { 27 | } 28 | 29 | ngOnInit() { 30 | this.fetchOrders(); 31 | } 32 | 33 | fetchOrders() { 34 | this.orderService.fetchAllOrders().subscribe(res => { 35 | this.orders = res; 36 | }, err => { 37 | if (err.status == 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err); 41 | } 42 | }, () => { 43 | this.areOrdersLoaded = true; 44 | this.dataSource = new MatTableDataSource(this.orders); 45 | }); 46 | } 47 | 48 | seeOrder(id: number) { 49 | this.router.navigate(['/orders', id]); 50 | } 51 | 52 | addOrder() { 53 | this.router.navigate(['shop-service/add'], { 54 | queryParams: { 55 | service: 'order' 56 | } 57 | }); 58 | } 59 | 60 | showError(err) { 61 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 62 | width: '700px', 63 | data: { 64 | error: err.error, 65 | status: err.status 66 | } 67 | }); 68 | 69 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/app/shop/returns/return/return.component.html: -------------------------------------------------------------------------------- 1 | Return #{{return.id}} 2 | 3 |
4 | 5 | 6 | 7 | Status: {{return.status}} 8 | 10 | 11 | 12 | 13 | Deadline: {{return.scheduledFor}} 14 | 15 | 16 | 17 | Value: {{return.value}} PLN 18 | 19 | 20 | 21 | 22 | 23 | 25 | Customer information 26 | 27 |
28 | face 29 | {{return.firstName}} {{return.lastName}} 30 | email 31 | {{return.email}} 32 | call 33 | {{return.phoneNumber}} 34 |
35 | location_city 36 | {{return.street}} {{return.houseNumber}}, {{return.postalCode}} {{return.city}} 37 |
38 |
39 | 40 | 41 | 43 | Items 44 | 45 | 46 | 47 | {{deliveryItem.item.name}}, price: {{deliveryItem.item.currentPrice}} PLN, quantity: {{deliveryItem.quantity}} 48 | 49 | 50 | 51 | 52 |
53 | -------------------------------------------------------------------------------- /src/app/shop/returns/return/return.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | margin-right: 5px; 6 | } 7 | 8 | .customer-info { 9 | display: inline-flex; 10 | vertical-align: middle; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .info { 15 | margin-top: 5px; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/shop/returns/return/return.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Return} from '../../../types'; 3 | import {ReturnService} from '../../../services/return.service'; 4 | import {ActivatedRoute, Router} from '@angular/router'; 5 | import {MatDialog} from "@angular/material"; 6 | import {StatusDialogComponent} from "../status-dialog/status-dialog.component"; 7 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 8 | import {ReturnStatus} from "../../../globals"; 9 | 10 | @Component({ 11 | selector: 'app-return', 12 | templateUrl: './return.component.html', 13 | styleUrls: ['./return.component.scss'] 14 | }) 15 | export class ReturnComponent implements OnInit { 16 | 17 | isReturnLoaded = false; 18 | return: Return; 19 | status: ReturnStatus; 20 | 21 | constructor(private returnService: ReturnService, private route: ActivatedRoute, 22 | private dialog: MatDialog, private router: Router) { 23 | } 24 | 25 | ngOnInit() { 26 | this.fetchReturn(); 27 | } 28 | 29 | fetchReturn() { 30 | this.returnService.fetchOneReturn(this.route.snapshot.params['id']).subscribe(res => { 31 | this.return = res; 32 | }, err => { 33 | if (err.status == 401) { 34 | this.router.navigate(['/login']); 35 | } else { 36 | this.showError(err); 37 | } 38 | }, () => { 39 | this.isReturnLoaded = true; 40 | this.status = this.return.status; 41 | }); 42 | } 43 | 44 | updateReturnStatus() { 45 | let status = []; 46 | if (this.return.status === ReturnStatus.IN_PROGRESS) { 47 | status = ['ACCEPTED', 'DECLINED']; 48 | } else if (this.return.status === ReturnStatus.ACCEPTED) { 49 | status = ['MONEY_RETURNED']; 50 | } 51 | const dialogRef = this.dialog.open(StatusDialogComponent, { 52 | width: '350px', 53 | data: { 54 | status: status, 55 | r: this.return 56 | } 57 | }); 58 | 59 | dialogRef.afterClosed().subscribe(result => { 60 | this.isReturnLoaded = false; 61 | this.fetchReturn(); 62 | }); 63 | } 64 | 65 | showError(err) { 66 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 67 | width: '700px', 68 | data: { 69 | error: err.error, 70 | status: err.status 71 | } 72 | }); 73 | 74 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/returns'])); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/app/shop/returns/returns/returns.component.html: -------------------------------------------------------------------------------- 1 | Returns 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 37 |
Index {{row.id}} Customer name {{row.firstName}} {{row.lastName}} Status {{row.status}} Value {{row.value}} Deadline {{row.scheduledFor}}
38 | 39 | 40 |
41 |
42 | -------------------------------------------------------------------------------- /src/app/shop/returns/returns/returns.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/shop/returns/returns/returns.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {Return} from '../../../types'; 3 | import {ReturnService} from '../../../services/return.service'; 4 | import {Router} from '@angular/router'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-returns', 10 | templateUrl: './returns.component.html', 11 | styleUrls: ['./returns.component.scss'] 12 | }) 13 | export class ReturnsComponent implements OnInit { 14 | 15 | returns: Array; 16 | areReturnsLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private returnService: ReturnService, private router: Router, private dialog: MatDialog) { 27 | } 28 | 29 | ngOnInit() { 30 | this.fetchReturns(); 31 | } 32 | 33 | fetchReturns() { 34 | this.returnService.fetchAllReturns().subscribe(res => { 35 | this.returns = res; 36 | }, err => { 37 | if (err.status == 401) { 38 | this.router.navigate(['/login']); 39 | } else { 40 | this.showError(err); 41 | } 42 | }, () => { 43 | this.areReturnsLoaded = true; 44 | this.dataSource = new MatTableDataSource(this.returns); 45 | }); 46 | } 47 | 48 | seeReturn(id: number) { 49 | this.router.navigate(['/returns', id]); 50 | } 51 | 52 | addReturn() { 53 | this.router.navigate(['shop-service/add'], { 54 | queryParams: { 55 | service: 'return' 56 | } 57 | }); 58 | } 59 | 60 | showError(err) { 61 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 62 | width: '700px', 63 | data: { 64 | error: err.error, 65 | status: err.status 66 | } 67 | }); 68 | 69 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/app/shop/returns/status-dialog/status-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 |
4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /src/app/shop/returns/status-dialog/status-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | display: inline-flex; 3 | } 4 | 5 | button { 6 | margin-left: 10px; 7 | align-items: center; 8 | } 9 | 10 | mat-progress-spinner { 11 | margin: auto; 12 | } 13 | 14 | .error { 15 | font-style: italic; 16 | color: darkred; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/app/shop/returns/status-dialog/status-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from '@angular/core'; 2 | import {ReturnService} from "../../../services/return.service"; 3 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 4 | import {ExpenseRequest, Return} from "../../../types"; 5 | import {ItemService} from "../../../services/item.service"; 6 | import {ReportService} from "../../../services/report.service"; 7 | import {ExpenseType} from "../../../globals"; 8 | 9 | export interface DialogData { 10 | status: string[]; 11 | r: Return; 12 | } 13 | 14 | @Component({ 15 | selector: 'app-status-dialog', 16 | templateUrl: './status-dialog.component.html', 17 | styleUrls: ['./status-dialog.component.scss'] 18 | }) 19 | export class StatusDialogComponent { 20 | 21 | showSpinner: boolean; 22 | error: string; 23 | shouldShowError: boolean; 24 | 25 | constructor(public dialogRef: MatDialogRef, 26 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 27 | private returnService: ReturnService, 28 | private itemService: ItemService, 29 | private reportService: ReportService) { 30 | } 31 | 32 | cancel() { 33 | this.dialogRef.close(null); 34 | } 35 | 36 | submit(s: string) { 37 | this.showSpinner = true; 38 | this.returnService.updateReturnStatus(s, this.data.r.id) 39 | .subscribe(res => { 40 | if (s === 'MONEY_RETURNED') { 41 | this.data.r.deliveryItems.forEach(deliveryItem => { 42 | this.itemService.supplyItem(deliveryItem.item.id, 43 | deliveryItem.quantity).subscribe(() => { 44 | }); 45 | }); 46 | const expenseRequest: ExpenseRequest = { 47 | expenseType: ExpenseType.UNEXPECTED, 48 | amount: this.data.r.value 49 | }; 50 | this.reportService.addExpense(expenseRequest).subscribe(() => {}); 51 | } 52 | }, err => { 53 | this.shouldShowError = true; 54 | this.error = err.error; 55 | this.showSpinner = false; 56 | }, () => { 57 | this.cancel(); 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/app/staff/employees/add-employee/add-employee.component.html: -------------------------------------------------------------------------------- 1 | Add employee 2 |
3 | 4 | 5 | First name 6 | 7 | 8 | 9 | 10 | Last name 11 | 12 | 13 | 14 | 15 | Email 16 | 17 | {{getErrorMessage()}} 18 | 19 | 20 | 21 | Role 22 | 23 | 24 | {{r}} 25 | 26 | 27 | 28 | 29 | 30 | Account number 31 | 33 | 26 digits 34 | 35 | 36 | 37 | Days off per year 38 | 40 | 0 - 26 41 | 42 | 43 | 44 | Salary 45 | 46 | 47 | 48 | 49 |
50 | -------------------------------------------------------------------------------- /src/app/staff/employees/add-employee/add-employee.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/staff/employees/employee/employee.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | } 6 | .out-of-office { 7 | color: limegreen; 8 | font-style: italic; 9 | } 10 | 11 | .pending-vacation { 12 | color: darkorange; 13 | font-style: italic; 14 | } 15 | 16 | .contract { 17 | display: inline-flex; 18 | vertical-align: middle; 19 | padding-bottom: 10px; 20 | } 21 | 22 | button:hover { 23 | background-color: transparent; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/staff/employees/employees/employees.component.html: -------------------------------------------------------------------------------- 1 | Employees 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
Index {{row.id}} Name {{row.firstName}} {{row.lastName}} Role {{row.role}}
25 | 26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /src/app/staff/employees/employees/employees.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/staff/employees/employees/employees.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {EmployeeService} from '../../../services/employee.service'; 3 | import {Router} from '@angular/router'; 4 | import {Employee} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-employees', 10 | templateUrl: './employees.component.html', 11 | styleUrls: ['./employees.component.scss'] 12 | }) 13 | export class EmployeesComponent implements OnInit { 14 | 15 | employees: Array; 16 | areLoaded: boolean; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private employeeService: EmployeeService, private router: Router, private dialog: MatDialog) { 27 | } 28 | 29 | ngOnInit() { 30 | this.fetchEmployees(); 31 | } 32 | 33 | fetchEmployees() { 34 | this.employeeService.fetchAllEmployees().subscribe(res => this.employees = res, 35 | err => { 36 | if (err.status == 401) { 37 | this.router.navigate(['/login']); 38 | } else { 39 | this.showError(err); 40 | } 41 | }, 42 | () => { 43 | this.areLoaded = true; 44 | this.dataSource = new MatTableDataSource(this.employees); 45 | } 46 | ); 47 | } 48 | 49 | fetchEmployee(id: number) { 50 | this.router.navigate(['/employees', id]); 51 | } 52 | 53 | addEmployee() { 54 | this.router.navigate(['/employees/add']); 55 | } 56 | 57 | showError(err) { 58 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 59 | width: '700px', 60 | data: { 61 | error: err.error, 62 | status: err.status 63 | } 64 | }); 65 | 66 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/teams'])); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/app/staff/holidays/add-holiday/add-holiday.component.html: -------------------------------------------------------------------------------- 1 | Add holiday 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Duration 12 | 13 | {{getErrorMessage()}} 14 | 15 | 16 | 17 | Holiday type 18 | 19 | 20 | {{t}} 21 | 22 | 23 | 24 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /src/app/staff/holidays/add-holiday/add-holiday.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/staff/holidays/add-holiday/add-holiday.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {HolidayService} from '../../../services/holiday.service'; 3 | import {ActivatedRoute} from '@angular/router'; 4 | import {HolidayType} from '../../../globals'; 5 | import {FormControl, FormGroup, Validators} from "@angular/forms"; 6 | 7 | @Component({ 8 | selector: 'app-add-holiday', 9 | templateUrl: './add-holiday.component.html', 10 | styleUrls: ['./add-holiday.component.scss'] 11 | }) 12 | export class AddHolidayComponent implements OnInit { 13 | 14 | employeeId: number; 15 | holidayRequest; 16 | form: FormGroup; 17 | startDate: FormControl; 18 | duration: FormControl; 19 | holidayType: FormControl; 20 | types; 21 | 22 | constructor(private holidayService: HolidayService, 23 | private route: ActivatedRoute) { 24 | } 25 | 26 | ngOnInit() { 27 | this.route.queryParams.subscribe(params => this.employeeId = params['employeeId']); 28 | this.types = Object.keys(HolidayType); 29 | this.setupFormControls(); 30 | this.form = new FormGroup({ 31 | "startDate": this.startDate, 32 | "duration": this.duration, 33 | "holidayType": this.holidayType 34 | }); 35 | } 36 | 37 | setupFormControls() { 38 | this.startDate = new FormControl('', [ 39 | Validators.required 40 | ]); 41 | this.duration = new FormControl('', [ 42 | Validators.required, 43 | Validators.pattern("^[0-9]*$"), 44 | ]); 45 | this.holidayType = new FormControl('', [ 46 | Validators.required 47 | ]); 48 | } 49 | 50 | submitForm() { 51 | this.holidayRequest = { 52 | startDate: this.form.get('startDate').value, 53 | duration: this.form.get('duration').value, 54 | holidayType: this.form.get('holidayType').value 55 | }; 56 | this.holidayService.addHoliday(this.holidayRequest, this.employeeId); 57 | } 58 | 59 | getErrorMessage() { 60 | return this.duration.hasError('pattern') ? 'Enter a number' : ''; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/staff/holidays/manage-holidays-dialog/manage-holidays-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{error}}

3 |
4 |
5 | 8 | 9 | 10 | account_circle {{req.employee.firstName}} {{req.employee.lastName}} 11 | business_center {{req.holidayType}} 12 | calendar_today {{req.startDate}} 13 | timeline {{req.duration}} day(s) 14 | hourglass_empty {{req.approvalState}} 15 | 18 | 21 | 22 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /src/app/staff/holidays/manage-holidays-dialog/manage-holidays-dialog.component.scss: -------------------------------------------------------------------------------- 1 | mat-progress-spinner { 2 | margin: auto; 3 | } 4 | 5 | button { 6 | font-style: italic; 7 | } 8 | 9 | .accept { 10 | color: limegreen; 11 | } 12 | 13 | .decline { 14 | color: darkred; 15 | } 16 | 17 | mat-icon { 18 | margin-right: 5px; 19 | margin-left: 15px; 20 | } 21 | 22 | .error { 23 | font-style: italic; 24 | color: darkred; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/app/staff/holidays/manage-holidays-dialog/manage-holidays-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from '@angular/core'; 2 | import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material"; 3 | import {HolidayService} from "../../../services/holiday.service"; 4 | import {Holiday} from "../../../types"; 5 | 6 | export interface DialogData { 7 | id: number; 8 | } 9 | 10 | @Component({ 11 | selector: 'app-manage-holidays-dialog', 12 | templateUrl: './manage-holidays-dialog.component.html', 13 | styleUrls: ['./manage-holidays-dialog.component.scss'] 14 | }) 15 | export class ManageHolidaysDialogComponent { 16 | 17 | holidayRequests: Holiday[]; 18 | areRequestsLoaded: boolean; 19 | error: string; 20 | shouldShowError: boolean; 21 | 22 | constructor( 23 | public dialogRef: MatDialogRef, 24 | @Inject(MAT_DIALOG_DATA) public data: DialogData, 25 | private holidayService: HolidayService) { 26 | this.fetchRequests(); 27 | } 28 | 29 | fetchRequests() { 30 | this.holidayService.fetchHolidaysToApprove(this.data.id).subscribe( 31 | res => { 32 | this.holidayRequests = res; 33 | }, err => { 34 | this.shouldShowError = true; 35 | this.error = err.error; 36 | }, () => { 37 | this.areRequestsLoaded = true; 38 | } 39 | ); 40 | } 41 | 42 | cancel() { 43 | this.dialogRef.close(null); 44 | } 45 | 46 | approve(holidayId: number, employeeId: number) { 47 | this.holidayService.manageHolidays(this.data.id, employeeId, holidayId, 'true') 48 | .subscribe( 49 | () => {}, 50 | err => { 51 | this.shouldShowError = true; 52 | this.error = err.error; 53 | }, () => { 54 | this.areRequestsLoaded = false; 55 | this.fetchRequests(); 56 | } 57 | ); 58 | } 59 | 60 | decline(holidayId: number, employeeId: number) { 61 | this.holidayService.manageHolidays(this.data.id, employeeId, holidayId, 'false') 62 | .subscribe( 63 | () => {}, 64 | err => { 65 | this.shouldShowError = true; 66 | this.error = err.error; 67 | }, () => { 68 | this.areRequestsLoaded = false; 69 | this.fetchRequests(); 70 | } 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/app/staff/teams/team/team.component.html: -------------------------------------------------------------------------------- 1 | Team {{team.role}} 2 |
3 | 4 | 5 |
6 |
7 | 8 | The manager of this team is
9 | 10 | 11 | {{team.manager.firstName}} {{team.manager.lastName}}
13 | email 14 | {{team.manager.email}} 15 |
16 |
17 |
18 |
19 |
20 | 21 | And the employees are: 22 | 23 | 24 | {{employee.firstName}} {{employee.lastName}} 26 | email 27 | {{employee.email}} 28 | 29 | 30 | 31 | 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /src/app/staff/teams/team/team.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | 3 | mat-icon { 4 | margin-left: 25px; 5 | } 6 | 7 | mat-list-item { 8 | margin-right: 25px; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/staff/teams/team/team.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {TeamService} from '../../../services/team.service'; 3 | import {ActivatedRoute, Router} from '@angular/router'; 4 | import {Team} from '../../../types'; 5 | import {MatDialog} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-team', 10 | templateUrl: './team.component.html', 11 | styleUrls: ['./team.component.scss'] 12 | }) 13 | export class TeamComponent implements OnInit { 14 | 15 | team: Team; 16 | isLoaded = false; 17 | 18 | constructor(private teamService: TeamService, 19 | private route: ActivatedRoute, 20 | private dialog: MatDialog, 21 | private router: Router) { 22 | } 23 | 24 | ngOnInit() { 25 | this.teamService.fetchOneTeam(this.route.snapshot.params[('id')]) 26 | .subscribe(res => { 27 | this.team = res; 28 | }, 29 | err => { 30 | if (err.status == 401) { 31 | this.router.navigate(['/login']); 32 | } else { 33 | this.showError(err); 34 | } 35 | }, 36 | () => { 37 | this.isLoaded = true; 38 | }); 39 | } 40 | 41 | showError(err) { 42 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 43 | width: '700px', 44 | data: { 45 | error: err.error, 46 | status: err.status 47 | } 48 | }); 49 | 50 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/teams'])); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/staff/teams/teams/teams.component.html: -------------------------------------------------------------------------------- 1 | Teams 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Index {{row.id}} Role {{row.role}}
20 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/app/staff/teams/teams/teams.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../theme"; 2 | -------------------------------------------------------------------------------- /src/app/staff/teams/teams/teams.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewChild} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import {TeamService} from '../../../services/team.service'; 4 | import {Team} from '../../../types'; 5 | import {MatDialog, MatPaginator, MatTableDataSource} from "@angular/material"; 6 | import {ErrorDialogComponent} from "../../../custom/error-dialog/error-dialog.component"; 7 | 8 | @Component({ 9 | selector: 'app-teams', 10 | templateUrl: './teams.component.html', 11 | styleUrls: ['./teams.component.scss'] 12 | }) 13 | export class TeamsComponent implements OnInit { 14 | 15 | teams: Array; 16 | isLoaded = false; 17 | dataSource: MatTableDataSource = new MatTableDataSource([]); 18 | paginator: any; 19 | 20 | @ViewChild(MatPaginator) 21 | set pagination(paginator: MatPaginator) { 22 | this.paginator = paginator; 23 | this.dataSource.paginator = this.paginator; 24 | } 25 | 26 | constructor(private router: Router, 27 | private teamService: TeamService, 28 | private dialog: MatDialog) { 29 | } 30 | 31 | ngOnInit() { 32 | this.teamService.fetchAllTeams().subscribe(res => { 33 | this.teams = res; 34 | }, err => { 35 | if (err.status == 401) { 36 | this.router.navigate(['/login']); 37 | } else { 38 | this.showError(err); 39 | } 40 | }, () => { 41 | this.isLoaded = true; 42 | this.dataSource = new MatTableDataSource(this.teams); 43 | }); 44 | } 45 | 46 | seeTeam(id: number) { 47 | this.router.navigate(['/teams', id]); 48 | } 49 | 50 | showError(err) { 51 | const dialogRef = this.dialog.open(ErrorDialogComponent, { 52 | width: '700px', 53 | data: { 54 | error: err.error, 55 | status: err.status 56 | } 57 | }); 58 | 59 | dialogRef.afterClosed().subscribe(() => this.router.navigate(['/employees'])); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/token.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class Token { 5 | 6 | constructor() { } 7 | 8 | public saveToken(token: string) { 9 | window.sessionStorage.removeItem('AuthToken'); 10 | window.sessionStorage.setItem('AuthToken', token); 11 | } 12 | 13 | public getToken(): string { 14 | return sessionStorage.getItem('AuthToken'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plkpiotr/erp-mes-frontend/70b2e4c0afa39ccaddbe098b573eaa9c57adf5b6/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plkpiotr/erp-mes-frontend/70b2e4c0afa39ccaddbe098b573eaa9c57adf5b6/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | ERP-MES Inc. 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {enableProdMode} from '@angular/core'; 2 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 3 | 4 | import {AppModule} from './app/app.module'; 5 | import {environment} from './environments/environment'; 6 | import 'hammerjs'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.log(err)); 14 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/prebuilt-themes/indigo-pink.css'; 2 | @import '~@angular/material/theming'; 3 | @include mat-core(); 4 | 5 | $primary: mat-palette($mat-blue, 400); 6 | $accent: mat-palette($mat-pink, 400); 7 | $warn: mat-palette($mat-pink, 400); 8 | 9 | $theme: mat-light-theme($primary, $accent, $warn); 10 | 11 | @include angular-material-theme($theme); 12 | 13 | html, body { 14 | height: 100%; 15 | } 16 | 17 | body { 18 | margin: 0; 19 | font-family: 'Roboto', sans-serif; 20 | } 21 | 22 | .mat-expansion-panel-content > .mat-expansion-panel-body { 23 | padding: 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./test', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "types": [] 7 | }, 8 | "exclude": [ 9 | "src/test.ts", 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/variables.scss: -------------------------------------------------------------------------------- 1 | $link: #439AE2; 2 | $dark: #90CAF9; 3 | $normal: #BBDEFB; 4 | $light: #E3F2FD; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2017", 17 | "dom" 18 | ] 19 | } 20 | } 21 | --------------------------------------------------------------------------------