| /* |
| ****************************************************************************** |
| * Copyright © 2018 PTA GmbH. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| ****************************************************************************** |
| */ |
| import { |
| Component, OnInit, Input, ElementRef, ViewChild, AfterContentChecked, |
| SimpleChanges, OnChanges, Output, AfterViewChecked |
| } from '@angular/core'; |
| import { FormGroup } from '@angular/forms'; |
| import { SessionContext } from '../../common/session-context'; |
| import { GridMeasure } from '../../model/grid-measure'; |
| import { Globals } from '../../common/globals'; |
| import { ErrorType } from '../../common/enums'; |
| import { DocumentService } from '../../services/document.service'; |
| import { Document } from './../../model/document'; |
| import { saveAs } from 'file-saver/FileSaver'; |
| import { RoleAccessHelperService } from '../../services/jobs/role-access-helper.service'; |
| import { EventEmitter, AfterViewInit } from '@angular/core'; |
| import { Util } from '../../common/util'; |
| import { GridMeasureService } from '../../services/grid-measure.service'; |
| import { ToasterMessageService } from '../../services/toaster-message.service'; |
| |
| @Component({ |
| selector: 'app-grid-measure-detail-tab', |
| templateUrl: './grid-measure-detail-tab.component.html', |
| styleUrls: ['./grid-measure-detail-tab.component.css', '../grid-measure-detail/grid-measure-detail.component.css'] |
| }) |
| export class GridMeasureDetailTabComponent implements OnInit, OnChanges, AfterViewChecked, AfterViewInit { |
| |
| @Input() showSpinnerGrid: boolean; |
| @Input() id: any; |
| @Input() gridMeasureDetail: GridMeasure = new GridMeasure(); |
| @Input() readOnlyForm: boolean; |
| @Output() isValidForSave: EventEmitter<boolean> = new EventEmitter<boolean>(); |
| |
| Globals = Globals; |
| fileToUpload: File = null; |
| fileName: string; |
| fileSelected: boolean; |
| documentToUpload: Document = null; |
| listOfDocuments: Document[] = null; |
| listOfDocumentsNames: string[] = []; |
| dataURI: string; |
| showSpinnerFileUpload = false; |
| dragEntered = false; |
| isAppointmentNumberOfValid: boolean; |
| switchingObjectList: string[]; |
| appointmentRepetitionList: string[]; |
| showSpinnerGridFileUpload: boolean; |
| dateFormatLocale = 'dd.MM.yyyy HH:mm'; |
| affectedResourcesList: Array<string> = []; |
| inactiveFields: Array<string> = []; |
| departmentList: any; |
| |
| datePattern = '^(([0-2]?[0-9]|3[0-1])\.([0]?[1-9]|1[0-2])\.[1-2][0-9]{3})$'; |
| dateTimePattern = '^(([0-2]?[0-9]|3[0-1])\.([0]?[1-9]|1[0-2])\.[1-2][0-9]{3}) (20|21|22|23|[0-1]?[0-9]{1}):([0-5]?[0-9]{1})$'; |
| calcDatepickerDropOrientation = Util.calcDatepickerDropOrientation; |
| |
| @ViewChild('gridMeasureDetailForm') gridMeasureDetailForm: FormGroup; |
| @ViewChild('gridMeasureDetailTabContainer') gridMeasureDetailTabContainer: ElementRef; |
| |
| |
| constructor(public sessionContext: SessionContext, |
| private documentService: DocumentService, |
| public roleAccessHelper: RoleAccessHelperService, |
| protected gridMeasureService: GridMeasureService, |
| private toasterMessageService: ToasterMessageService, |
| private gridMeasuresService: GridMeasureService) { } |
| |
| ngOnInit() { |
| |
| this.inactiveFields = this.sessionContext.getInactiveFields(); |
| this.isAppointmentNumberOfValid = true; |
| |
| this.getAffectedResourcesDistinct(); |
| |
| // TODO auslagern in Globals bzw. je nach Prozess automatisch laden (separate User Story) |
| this.switchingObjectList = ['UW A', 'UW B', 'test1', 'test2']; |
| this.appointmentRepetitionList = this.sessionContext.getBackendsettings().appointmentRepetition.map(ap => ap.name); |
| this.gridMeasuresService.getUserDepartments() |
| .subscribe(departments => this.departmentList = departments, |
| error => { |
| console.log(error); |
| }); |
| } |
| |
| ngAfterViewInit() { |
| this.initInactiveFields(); |
| } |
| |
| ngAfterViewChecked() { |
| if (this.gridMeasureDetailForm) { |
| this.gridMeasureDetail._isValide = this.gridMeasureDetailForm.valid; |
| } |
| } |
| |
| ngOnChanges(changes: SimpleChanges) { |
| if (changes['id'] && changes['id'].currentValue) { |
| this.getDocumentsForId(); |
| } |
| if (changes['readOnlyForm']) { |
| this.initInactiveFields(); |
| } |
| if (changes['gridMeasureDetail'] && changes['gridMeasureDetail'].currentValue) { |
| this.gridMeasureDetail.appointmentNumberOf = this.gridMeasureDetail.appointmentNumberOf || 0; |
| this.appointmentRepetitionList = this.sessionContext.getBackendsettings().appointmentRepetition.map(ap => ap.name); |
| if (!this.gridMeasureDetail.appointmentRepetition) { |
| this.gridMeasureDetail.appointmentRepetition = this.appointmentRepetitionList[0]; |
| } |
| this.setCurrTimeIfEmpty(this.gridMeasureDetail); |
| } |
| } |
| |
| getAffectedResourcesDistinct() { |
| this.gridMeasureService.getAffectedResourcesDistinct().subscribe(aResource => |
| this.affectedResourcesList = aResource); |
| } |
| |
| public initInactiveFields() { |
| const el: HTMLElement = this.gridMeasureDetailTabContainer.nativeElement as HTMLElement; |
| const fields = el.querySelectorAll('*[id]:not(button)'); |
| for (let index = 0; index < fields.length; index++) { |
| const field = fields[index]; |
| if (this.readOnlyForm || this.isFieldInactive(field['id'])) { |
| field.setAttribute('disabled', 'disabled'); |
| } else { |
| field.removeAttribute('disabled'); |
| } |
| } |
| } |
| |
| private isFieldInactive(fieldName: string): boolean { |
| if ((fieldName === 'fileUploadLabel' || fieldName === 'file') && !this.id) { |
| return true; |
| } else { |
| return this.inactiveFields.filter(field => field === fieldName).length > 0; |
| } |
| } |
| setCurrTimeIfEmpty(gridMeasure: GridMeasure) { |
| |
| const dateFields = [ |
| 'appointmentStartdate', |
| 'plannedStarttimeFirstSinglemeasure' |
| ]; |
| if (gridMeasure.id) { |
| return; |
| } |
| dateFields.forEach(field => { |
| if (gridMeasure[field] === undefined) { |
| gridMeasure[field] = this.getCurrentDateTime(); |
| } |
| }); |
| |
| } |
| |
| public selectedDate(value: any, datepicker?: any) { |
| this.gridMeasureDetail[datepicker] = value.start._d; |
| } |
| onGridMeasureDetailFormValidation(valid: boolean) { |
| this.gridMeasureDetail._isValide = valid; |
| } |
| getCurrentDateTime(): string { |
| return new Date().toISOString(); |
| } |
| checkAppointmentNumberOfValue(event) { |
| if (event < Globals.APPOINTMENT_NUMBER_OF_MAX_VALUE + 1) { |
| this.isAppointmentNumberOfValid = true; |
| } else { |
| this.gridMeasureDetail.appointmentNumberOf = 0; |
| this.isAppointmentNumberOfValid = false; |
| } |
| } |
| onGridMeasureTitleChange(value) { |
| if (value) { |
| this.isValidForSave.emit(true); |
| } else { |
| this.isValidForSave.emit(false); |
| } |
| } |
| |
| handleFileInput(file: FileList) { |
| if (!file || file.length === 0) { |
| return; |
| } |
| |
| if (file.length > 1) { |
| this.toasterMessageService.showWarn('Es kann nur jeweils eine Datei hochgeladen werden! ' |
| + 'Die erste Datei ihrer Auswahl wurde übernommen.'); |
| |
| } |
| |
| this.fileToUpload = file.item(0); |
| this.fileName = this.fileToUpload.name; |
| |
| if (this.gridMeasureDetail.statusId === Globals.STATUS.APPLIED && this.checkIfFileExists(this.fileToUpload.name)) { |
| this.toasterMessageService.showWarn('Im Status Beantragt können Dateien nicht geändert werden!'); |
| return; |
| } |
| |
| if (!this.fileSizeCheck() || !this.fileTypeCheck()) { |
| return; |
| } |
| this.fileSelected = true; |
| } |
| |
| |
| private checkIfFileExists(fileName: string) { |
| if (this.listOfDocumentsNames.includes(fileName)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| private fileTypeCheck(): boolean { |
| const fileType = this.fileToUpload.type; |
| if (!Globals.TYPE_WHITELIST.includes(fileType)) { |
| this.toasterMessageService.showWarn('Dieser Dateityp ist nicht erlaubt!'); |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| private fileSizeCheck(): boolean { |
| const fileUploadSize = this.fileToUpload.size; |
| const allowed = Globals.MEGABYT_UNIT * Globals.MAX_UPLOADFILE_SIZE; |
| if (fileUploadSize > allowed) { |
| // Globals.MAX_UPLOADFILE_SIZE + ' Megabytes!', MessageScopeEn.local); |
| this.toasterMessageService.showWarn('Die ausgewählte Datei überschreitet die maximale zulässige Größe von ' + |
| Globals.MAX_UPLOADFILE_SIZE + ' Megabytes!'); |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| uploadDocument() { |
| if (!this.fileSelected) { |
| return; |
| } |
| this.showSpinnerFileUpload = true; |
| // convertFileToBas64 |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| this.dataURI = reader.result; |
| this.proccessFile(); |
| }; |
| reader.readAsDataURL(this.fileToUpload); |
| } |
| |
| private proccessFile() { |
| const byteString = this.dataURI.split(',')[1]; |
| const documentToUpload = new Document(); |
| documentToUpload.data = byteString; |
| |
| // TODO send to backend to check file type against whitelist |
| // const mimeString = this.dataURI.split(',')[0].split(':')[1].split(';')[0]; |
| documentToUpload.documentName = this.fileToUpload.name; |
| |
| this.documentToUpload = documentToUpload; |
| this.processUpload(); |
| } |
| |
| private processUpload() { |
| this.documentService.uploadGridMeasureAttachments(this.id, this.documentToUpload).subscribe(resp => { |
| this.showSpinnerFileUpload = false; |
| this.getDocumentsForId(); |
| this.fileSelected = false; |
| this.toasterMessageService.showSuccess('Datei erfolgreich hochgeladen!'); |
| }, |
| error => { |
| this.toasterMessageService.showError(ErrorType.upload, ''); |
| this.showSpinnerFileUpload = false; |
| console.log(error); |
| }); |
| } |
| |
| private getDocumentsForId() { |
| this.documentService.getGridMeasureAttachments(this.id).subscribe(gm => { |
| this.listOfDocuments = gm; |
| for (let index = 0; index < this.listOfDocuments.length; index++) { |
| this.listOfDocumentsNames.push(this.listOfDocuments[index].documentName); |
| } |
| }, |
| error => { |
| this.toasterMessageService.showError(ErrorType.retrieve, 'GridMeasure'); |
| console.log(error); |
| }); |
| } |
| |
| downloadDocument(documentId) { |
| this.showSpinnerFileUpload = true; |
| this.documentService.downloadGridMeasureAttachment(documentId).subscribe(resp => { |
| this.saveFile(resp); |
| this.toasterMessageService.showSuccess('Datei erfolgreich heruntergeladen!'); |
| this.showSpinnerFileUpload = false; |
| }, |
| error => { |
| this.toasterMessageService.showError(ErrorType.retrieve, 'Datei'); |
| this.showSpinnerFileUpload = false; |
| console.log(error); |
| }); |
| } |
| |
| deleteDocument(documentId: number, index: number) { |
| this.documentService.deleteGridMeasureAttachment(documentId).subscribe(resp => { |
| this.toasterMessageService.showSuccess('Datei erfolgreich gelöscht!'); |
| this.listOfDocuments.splice(index, 1); |
| }, |
| error => { |
| this.toasterMessageService.showError(ErrorType.delete, 'Datei'); |
| this.showSpinnerFileUpload = false; |
| console.log(error); |
| }); |
| } |
| |
| private saveFile(document: Document) { |
| const byteString = atob(document.data); |
| |
| // write the bytes of the string to an ArrayBuffer |
| const ab = new ArrayBuffer(byteString.length); |
| |
| // create a view into the buffer |
| const ia = new Uint8Array(ab); |
| |
| // set the bytes of the buffer to the correct values |
| for (let i = 0; i < byteString.length; i++) { |
| ia[i] = byteString.charCodeAt(i); |
| } |
| |
| // write the ArrayBuffer to a blob, and you're done |
| const blob = new Blob([ab], { type: 'application/octet-stream' }); |
| saveAs(blob, document.documentName); |
| |
| } |
| allowDrop(ev) { |
| ev.preventDefault(); |
| ev.stopPropagation(); |
| } |
| |
| drop(ev) { |
| ev.preventDefault(); |
| ev.stopPropagation(); |
| |
| // cancel drop if upload is disabled |
| const el: HTMLElement = this.gridMeasureDetailTabContainer.nativeElement as HTMLElement; |
| const uploadField = el.querySelector('#fileUploadLabel'); |
| |
| if (uploadField.getAttribute('disabled')) { |
| this.dragEntered = false; |
| return; |
| } |
| |
| if (!this.readOnlyForm && this.id) { |
| const files = ev.target.files || ev.dataTransfer.files; |
| this.handleFileInput(files); |
| } |
| this.dragEntered = false; |
| } |
| |
| dragenter(ev) { |
| this.dragEntered = true; |
| } |
| |
| dragleave(ev) { |
| this.dragEntered = false; |
| } |
| } |