| @@ -3,7 +3,7 @@ | |||
| <h2>{{ 'basic.documents' | translate }}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewDocument()">{{'basic.new-document' | translate}}</button> | |||
| </div> | |||
| <table mat-table [dataSource]="dataSource" matSort (matSortChange)="onSortChange($event)" | |||
| <table mat-table [dataSource]="documentsDataSource" matSort (matSortChange)="onSortChange($event)" | |||
| class="mat-elevation-z8 mb-3"> | |||
| <ng-container matColumnDef="pos"> | |||
| @@ -11,7 +11,7 @@ | |||
| {{ 'overview.number' | translate }} | |||
| </th> | |||
| <td mat-cell | |||
| *matCellDef="let element">{{ (pageSize * pageIndex) + dataSource.filteredData.indexOf(element) + 1 }} | |||
| *matCellDef="let element">{{ (documentsPageSize * documentsPageIndex) + documentsDataSource.filteredData.indexOf(element) + 1 }} | |||
| </td> | |||
| </ng-container> | |||
| @@ -44,10 +44,10 @@ | |||
| </table> | |||
| <mat-paginator class="rounded-1" | |||
| [pageSizeOptions]="[10,25,50]" | |||
| [length]="length" | |||
| [length]="documentsLength" | |||
| (page)="handlePageEvent($event)" | |||
| [pageSize]="pageSize" | |||
| [pageIndex]="pageIndex" | |||
| [pageSize]="documentsPageSize" | |||
| [pageIndex]="documentsPageIndex" | |||
| showFirstLastButtons> | |||
| </mat-paginator> | |||
| </div> | |||
| @@ -2,15 +2,17 @@ import {ChangeDetectorRef, Component, ViewChild} from '@angular/core'; | |||
| import {MatSort, MatSortModule, Sort} from "@angular/material/sort"; | |||
| import {MatPaginator, MatPaginatorIntl, MatPaginatorModule, PageEvent} from "@angular/material/paginator"; | |||
| import {Subscription} from "rxjs"; | |||
| import {PartnerJsonld} from "@app/core/api/v1"; | |||
| import {DocumentJsonldDocumentObjectRead, DocumentService, PartnerJsonld, ProductJsonld} from "@app/core/api/v1"; | |||
| import {Router, RouterLink, RouterLinkActive} from "@angular/router"; | |||
| import {MatTableDataSource, MatTableModule} from "@angular/material/table"; | |||
| import {OrderFilter} from "@app/_models/orderFilter"; | |||
| import {NgIf} from "@angular/common"; | |||
| import {ModalComponent} from "@app/_components/modal/modal.component"; | |||
| import {NgbModal} from "@ng-bootstrap/ng-bootstrap"; | |||
| import {NgbModal, NgbModalOptions} from "@ng-bootstrap/ng-bootstrap"; | |||
| import {NewDocumentComponent} from "@app/documents/new-document/new-document.component"; | |||
| import {TranslateModule} from "@ngx-translate/core"; | |||
| import {NewProductComponent} from "@app/products/new-product/new-product.component"; | |||
| import {ModalStatus} from "@app/_helpers/modal.states"; | |||
| @Component({ | |||
| selector: 'app-documents', | |||
| @@ -21,71 +23,67 @@ import {TranslateModule} from "@ngx-translate/core"; | |||
| }) | |||
| export class DocumentsComponent { | |||
| @ViewChild(MatSort) sort; | |||
| @ViewChild(MatPaginator) paginator: MatPaginator; | |||
| @ViewChild(MatPaginator) documentsPaginator: MatPaginator; | |||
| protected documentsSub: Subscription; | |||
| protected documents: Array<PartnerJsonld>; | |||
| protected dataType!: string; | |||
| protected dataSource; | |||
| protected displayedColumns: string[]; | |||
| protected length: number; | |||
| protected pageEvent: PageEvent; | |||
| protected pageSize: number; | |||
| protected pageIndex: number; | |||
| protected documentsSub: Subscription; | |||
| protected documents: Array<DocumentJsonldDocumentObjectRead>; | |||
| protected documentsDataSource; | |||
| protected documentsLength: number; | |||
| protected documentsPageEvent: PageEvent; | |||
| protected documentsPageSize: number; | |||
| protected documentsPageIndex: number; | |||
| protected modalOptions: NgbModalOptions = { | |||
| centered: true | |||
| }; | |||
| constructor( | |||
| private router: Router, | |||
| private modalService: NgbModal | |||
| private modalService: NgbModal, | |||
| private documentService: DocumentService | |||
| ) { | |||
| this.sort = new MatSort(); | |||
| this.paginator = new MatPaginator(new MatPaginatorIntl(), ChangeDetectorRef.prototype); | |||
| this.dataSource = new MatTableDataSource; //<DocumentJsonld>(this.documents) | |||
| this.displayedColumns = ['pos', 'name', 'type', 'date']; | |||
| this.documentsSub = new Subscription(); | |||
| this.documents = []; | |||
| this.length = 0; | |||
| this.pageEvent = new PageEvent(); | |||
| this.pageSize = 10; | |||
| this.pageIndex = 0; | |||
| this.documentsPaginator = new MatPaginator(new MatPaginatorIntl(), ChangeDetectorRef.prototype); | |||
| this.documentsDataSource = new MatTableDataSource<DocumentJsonldDocumentObjectRead>(this.documents); | |||
| this.documentsLength = 0; | |||
| this.documentsPageEvent = new PageEvent(); | |||
| this.documentsPageSize = 10; | |||
| this.documentsPageIndex = 0; | |||
| } | |||
| ngOnInit() { | |||
| this.getData(); | |||
| this.getDocumentsData(); | |||
| } | |||
| ngAfterViewInit() { | |||
| this.dataSource.sort = this.sort; | |||
| this.dataSource.paginator = this.paginator; | |||
| this.documentsDataSource.sort = this.sort; | |||
| this.documentsDataSource.paginator = this.documentsPaginator; | |||
| } | |||
| getData() { | |||
| // this.documentsSub = this.documentService.documentsGetCollection( | |||
| // this.pageIndex + 1, | |||
| // this.pageSize, | |||
| // this.dataType, | |||
| // undefined, | |||
| // this.nameOrderAsc, | |||
| // this.storageOrderAsc, | |||
| // this.numberOrderAsc | |||
| // ).subscribe( | |||
| // data => { | |||
| // this.documents = data["hydra:member"]; | |||
| // this.dataSource = new MatTableDataSource<DocumentJsonld>(this.documents); | |||
| // console.log(data); | |||
| // this.length = Number(data["hydra:totalItems"]); | |||
| // this.paginator.length = this.length; | |||
| // } | |||
| // ); | |||
| getDocumentsData() { | |||
| this.documentsSub = this.documentService.documentsGetCollection( | |||
| this.documentsPageIndex + 1, | |||
| this.documentsPageSize | |||
| ).subscribe( | |||
| data => { | |||
| this.documents = data["hydra:member"]; | |||
| this.documentsDataSource = new MatTableDataSource<DocumentJsonldDocumentObjectRead>(this.documents); | |||
| this.documentsLength = Number(data["hydra:totalItems"]); | |||
| this.documentsPaginator.length = this.documentsLength; | |||
| } | |||
| ); | |||
| } | |||
| /** Announce the change in sort state for assistive technology. */ | |||
| onSortChange(sortState: Sort) { | |||
| // Reset page index to first page | |||
| this.pageIndex = 0; | |||
| this.documentsPageIndex = 0; | |||
| let order: OrderFilter; | |||
| if (sortState.direction === "") { | |||
| @@ -108,15 +106,15 @@ export class DocumentsComponent { | |||
| // this.websiteOrderAsc = order; | |||
| // break; | |||
| // } | |||
| this.getData(); | |||
| this.getDocumentsData(); | |||
| } | |||
| handlePageEvent(e: PageEvent) { | |||
| this.pageEvent = e; | |||
| this.length = e.length; | |||
| this.pageIndex = e.pageIndex.valueOf(); | |||
| this.pageSize = e.pageSize.valueOf(); | |||
| this.getData(); | |||
| this.documentsPageEvent = e; | |||
| this.documentsLength = e.length; | |||
| this.documentsPageIndex = e.pageIndex.valueOf(); | |||
| this.documentsPageSize = e.pageSize.valueOf(); | |||
| this.getDocumentsData(); | |||
| } | |||
| navigateToDocumentFile(element: any) { | |||
| @@ -127,7 +125,16 @@ export class DocumentsComponent { | |||
| } | |||
| openModalNewDocument() { | |||
| const modalRef = this.modalService.open(ModalComponent); | |||
| modalRef.componentInstance.dynamicComponent = NewDocumentComponent; | |||
| const modalRefDocument = this.modalService.open(NewDocumentComponent, this.modalOptions); | |||
| // TODO: Warum muss ich einen leeren String übergeben, damit es funktioniert? | |||
| let document: ProductJsonld = {} as ProductJsonld; | |||
| document.name = ""; | |||
| modalRefDocument.componentInstance.document = document; | |||
| modalRefDocument.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefDocument.dismiss(); | |||
| this.getDocumentsData(); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| @@ -1 +1,12 @@ | |||
| <p>new-document works!</p> | |||
| <h2 *ngIf="!document.id">{{'basic.new-document' | translate}}</h2> | |||
| <h2 *ngIf="document.id">{{'basic.edit-document' | translate}}</h2> | |||
| <div class="spt-form"> | |||
| <form [formGroup]="documentForm" (ngSubmit)="onSubmit()"> | |||
| <div class="mb-3"> | |||
| <label for="image" class="form-label">{{'form.upload-image' | translate}}:</label> | |||
| <input type="file" class="form-control" id="image" (change)="onFileSelected($event)" accept="image/*" /> | |||
| </div> | |||
| <button type="submit" class="btn btn-primary" [disabled]="documentForm.invalid">{{'form.send' | translate}}</button> | |||
| </form> | |||
| </div> | |||
| @@ -1,10 +1,70 @@ | |||
| import { Component } from '@angular/core'; | |||
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |||
| import { | |||
| DocumentJsonldDocumentObjectRead, | |||
| DocumentService, | |||
| MediaService, | |||
| ProductJsonld, | |||
| ProductService | |||
| } from "@app/core/api/v1"; | |||
| import {ModalStatus} from "@app/_helpers/modal.states"; | |||
| import {FormGroup} from "@angular/forms"; | |||
| import {Subscription} from "rxjs"; | |||
| import {TranslateService} from "@ngx-translate/core"; | |||
| import {FormGroupInitializer} from "@app/_helpers/formgroup.initializer"; | |||
| import {ApiConverter} from "@app/_helpers/api.converter"; | |||
| import {documentDocumentObjectReadForm} from "@app/_forms/apiForms"; | |||
| @Component({ | |||
| selector: 'app-new-document', | |||
| templateUrl: './new-document.component.html', | |||
| styleUrl: './new-document.component.scss' | |||
| }) | |||
| export class NewDocumentComponent { | |||
| export class NewDocumentComponent implements OnInit { | |||
| @Input() public document!: DocumentJsonldDocumentObjectRead; | |||
| @Output() public submit: EventEmitter<ModalStatus> = new EventEmitter<ModalStatus>(); | |||
| protected documentForm: FormGroup; | |||
| protected documentSub: Subscription; | |||
| protected selectedImage: File | null; | |||
| protected mediaSub: Subscription; | |||
| constructor( | |||
| private documentService: DocumentService, | |||
| private mediaService: MediaService, | |||
| private translateService: TranslateService | |||
| ) { | |||
| this.documentForm = documentDocumentObjectReadForm; | |||
| this.documentSub = new Subscription(); | |||
| this.selectedImage = null; | |||
| this.mediaSub = new Subscription(); | |||
| } | |||
| ngOnInit(): void { | |||
| this.documentForm = FormGroupInitializer.initFormGroup(this.documentForm, this.document); | |||
| } | |||
| onSubmit() { | |||
| // if (this.documentForm.valid) { | |||
| // if (this.document.id === null || this.document.id === undefined) { | |||
| // // Create new product | |||
| // this.documentSub = this.documentService.documentsPost( | |||
| // this.documentForm.value as DocumentJsonldDocumentObjectRead | |||
| // ).subscribe( | |||
| // data => { | |||
| // this.documentForm.reset(); | |||
| // this.submit.emit(ModalStatus.Submitted); | |||
| // } | |||
| // ); | |||
| // } | |||
| // } | |||
| } | |||
| onFileSelected(event: any) { | |||
| const file: File = event.target.files[0]; | |||
| if (file) { | |||
| this.selectedImage = file; | |||
| } | |||
| } | |||
| } | |||
| @@ -26,8 +26,9 @@ | |||
| </dl> | |||
| </div> | |||
| <div class="col-4"> | |||
| <img *ngIf="partner.logoUrl !== null && partner.logoUrl !== undefined" src="{{partner.logoUrl}}" width="247" | |||
| height="94" alt="{{partner.name}}" title="{{partner.name}}" /> | |||
| <img *ngIf="partner.logoUrl !== null && partner.logoUrl !== undefined" src="{{partner.logoUrl}}" | |||
| width="247" | |||
| height="94" alt="{{partner.name}}" title="{{partner.name}}"/> | |||
| </div> | |||
| <span class="position-absolute bi bi-pencil p-2" data-type="user-tool" data-action="edit" | |||
| (click)="openModalEditPartner()"></span> | |||
| @@ -37,8 +38,9 @@ | |||
| <div class="spt-container"> | |||
| <div class="contacts"> | |||
| <div class="d-flex justify-content-between align-items-start"> | |||
| <h2>{{'basic.contacts' | translate}}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewContact()">{{'basic.new-contact' | translate}}</button> | |||
| <h2>{{ 'basic.contacts' | translate }}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewContact()">{{ 'basic.new-contact' | translate }} | |||
| </button> | |||
| </div> | |||
| <div class="row"> | |||
| <div class="col-4" *ngFor="let contact of contacts"> | |||
| @@ -59,7 +61,8 @@ | |||
| </div> | |||
| </div> | |||
| <div class="d-flex justify-content-end mt-1 mb-4"> | |||
| <span role="button" (click)="navigateToContactDetails(contact)" class="badge bg-secondary p-2">{{'basic.details' | translate}}</span> | |||
| <span role="button" (click)="navigateToContactDetails(contact)" | |||
| class="badge bg-secondary p-2">{{ 'basic.details' | translate }}</span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -101,46 +104,55 @@ | |||
| <div class="spt-container"> | |||
| <div class="spt-accordion"> | |||
| <div class="d-flex justify-content-between align-items-start"> | |||
| <h2>{{'basic.tasks' | translate}}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewTask()">{{'basic.new-task' | translate}}</button> | |||
| <h2>{{ 'basic.tasks' | translate }}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewTask()">{{ 'basic.new-task' | translate }}</button> | |||
| </div> | |||
| <div class="tasks mb-3" *ngFor="let task of tasks"> | |||
| <div class="card p-3"> | |||
| <div class="position-relative" data-bs-toggle="collapse" [attr.data-bs-target]="'#collapse-' + ApiConverter.extractId(task.id)" | |||
| <div class="position-relative" data-bs-toggle="collapse" | |||
| [attr.data-bs-target]="'#collapse-' + ApiConverter.extractId(task.id)" | |||
| aria-expanded="false" | |||
| aria-controls="collapseExample"> | |||
| <h3 class="m-0">{{task.partner}}</h3> | |||
| <h3 class="m-0">{{ task.partnerName }}</h3> | |||
| <span class="info d-flex position-absolute"> | |||
| <span class="due-date">{{ task.dueAt | date:'dd.MM.YYYY HH:mm':'GMT+0000' }}</span> | |||
| <span class="importance" [attr.data-importance]="task.prio"></span> | |||
| </span> | |||
| <h2 class="m-0">{{task.headline}}</h2> | |||
| <h2 class="m-0">{{ task.headline }}</h2> | |||
| </div> | |||
| <div class="collapse" id="collapse-{{ApiConverter.extractId(task.id)}}"> | |||
| <div class="pt-3 pe-5 position-relative"> | |||
| <p class="m-0">{{task.description}}</p> | |||
| <p>Zugewiesen an: {{task.assignedTo}}</p> | |||
| <p class="m-0">{{ task.description }}</p> | |||
| <p>Zugewiesen an: {{ task.assignedToName }}</p> | |||
| <span *ngIf="task.createdBy === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" data-action="edit" (click)="openModalEditTask(task)"></span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="card ms-5" *ngFor="let taskNote of task.taskNotes"> | |||
| <div class="card-body"> | |||
| <div class="d-flex justify-content-between align-items-center"> | |||
| <p>{{ taskNote.createdAt | date:'dd.MM.YYYY HH:mm' }}</p> | |||
| <p>{{ taskNote.ownerName }}</p> | |||
| </div> | |||
| <div> | |||
| <p>{{ taskNote.message }}</p> | |||
| <div *ngIf="task.id && taskNotesVisibility.get(task.id)"> | |||
| <div class="card ms-5" *ngFor="let taskNote of task.taskNotes"> | |||
| <div class="card-body"> | |||
| <div class="d-flex justify-content-between align-items-center"> | |||
| <p>{{ taskNote.createdAt | date:'dd.MM.YYYY HH:mm' }}</p> | |||
| <p>{{ taskNote.ownerName }}</p> | |||
| </div> | |||
| <div> | |||
| <p>{{ taskNote.message }}</p> | |||
| </div> | |||
| <span *ngIf="taskNote.owner === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" data-action="edit" (click)="openModalEditTaskNote(taskNote)"></span> | |||
| </div> | |||
| <span *ngIf="taskNote.owner === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" data-action="edit" (click)="openModalEditTaskNote(taskNote)"></span> | |||
| </div> | |||
| </div> | |||
| <div class="d-flex justify-content-end mt-1"> | |||
| <span role="button" class="badge bg-secondary p-2" (click)="openModalNewTaskNote(task)">{{'basic.comment-it' | translate}}</span> | |||
| <span *ngIf="task.taskNotes?.length !== 0" role="button" class="badge bg-secondary p-2 me-2" | |||
| (click)="showTaskNotes(task)"> | |||
| <ng-container *ngIf="task.id && taskNotesVisibility.get(task.id)">{{ 'basic.hide-comments' | translate }}</ng-container> | |||
| <ng-container *ngIf="task.id && !taskNotesVisibility.get(task.id)">{{ 'basic.show-comments' | translate }}</ng-container> | |||
| </span> | |||
| <span role="button" class="badge bg-secondary p-2" | |||
| (click)="openModalNewTaskNote(task)">{{ 'basic.comment-it' | translate }}</span> | |||
| </div> | |||
| </div> | |||
| <mat-paginator *ngIf="tasks.length > 0" class="rounded-1" | |||
| @@ -156,8 +168,8 @@ | |||
| <div class="spt-container"> | |||
| <div class="posts"> | |||
| <div class="d-flex justify-content-between align-items-start"> | |||
| <h2>{{'basic.posts' | translate}}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewPosting()">{{'basic.new-post' | translate}}</button> | |||
| <h2>{{ 'basic.posts' | translate }}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewPosting()">{{ 'basic.new-post' | translate }}</button> | |||
| </div> | |||
| <div class="post mb-3" *ngFor="let post of posts"> | |||
| <div class="card"> | |||
| @@ -170,7 +182,8 @@ | |||
| <h3>{{ post.headline }}</h3> | |||
| <p>{{ post.message }}</p> | |||
| </div> | |||
| <span *ngIf="post.owner === user?.id" class="position-absolute bi bi-pencil p-2" data-type="user-tool" | |||
| <span *ngIf="post.owner === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" | |||
| data-action="edit" (click)="openModalEditPosting(post)"></span> | |||
| </div> | |||
| </div> | |||
| @@ -189,7 +202,8 @@ | |||
| </div> | |||
| <div class="d-flex justify-content-end mt-1"> | |||
| <span role="button" class="badge bg-secondary p-2" (click)="openModalNewComment(post)">{{'basic.comment-it' | translate}}</span> | |||
| <span role="button" class="badge bg-secondary p-2" | |||
| (click)="openModalNewComment(post)">{{ 'basic.comment-it' | translate }}</span> | |||
| </div> | |||
| </div> | |||
| <mat-paginator *ngIf="posts.length > 0" class="rounded-1" | |||
| @@ -61,6 +61,8 @@ export class PartnersDetailComponent implements OnInit, AfterViewInit { | |||
| protected tasksPageSize: number; | |||
| protected tasksPageIndex: number; | |||
| protected taskNotesVisibility: Map<string, boolean>; | |||
| protected postsSub: Subscription; | |||
| protected posts: Array<PostJsonld>; | |||
| protected postsDataSource; | |||
| @@ -108,6 +110,7 @@ export class PartnersDetailComponent implements OnInit, AfterViewInit { | |||
| this.tasksPageEvent = new PageEvent(); | |||
| this.tasksPageSize = 10; | |||
| this.tasksPageIndex = 0; | |||
| this.taskNotesVisibility = new Map<string, boolean>(); | |||
| this.postsSub = new Subscription(); | |||
| this.posts = []; | |||
| @@ -184,6 +187,11 @@ export class PartnersDetailComponent implements OnInit, AfterViewInit { | |||
| data => { | |||
| this.tasks = data["hydra:member"]; | |||
| this.tasksLength = Number(data["hydra:totalItems"]); | |||
| this.tasks.forEach(task => { | |||
| if (task.id) { | |||
| this.taskNotesVisibility.set(task.id, false); | |||
| } | |||
| }); | |||
| console.log(this.tasks); | |||
| } | |||
| ); | |||
| @@ -339,4 +347,11 @@ export class PartnersDetailComponent implements OnInit, AfterViewInit { | |||
| } | |||
| }); | |||
| } | |||
| showTaskNotes(task: TaskJsonld) { | |||
| if (task.id) { | |||
| const currentVisibility = this.taskNotesVisibility.get(task.id); | |||
| this.taskNotesVisibility.set(task.id, !currentVisibility); | |||
| } | |||
| } | |||
| } | |||
| @@ -84,7 +84,7 @@ export class PartnersComponent implements OnInit, AfterViewInit { | |||
| this.translateService.get('basic.' + this.dataType + 'One').subscribe((translation: string) => { | |||
| this.partnerNameOne = translation; | |||
| }); | |||
| this.getData(); | |||
| this.getPartnersData(); | |||
| } | |||
| ngAfterViewInit() { | |||
| @@ -92,7 +92,7 @@ export class PartnersComponent implements OnInit, AfterViewInit { | |||
| this.dataSource.paginator = this.paginator; | |||
| } | |||
| getData() { | |||
| getPartnersData() { | |||
| this.partnersSub = this.partnerService.partnersGetCollection( | |||
| this.pageIndex + 1, | |||
| this.pageSize, | |||
| @@ -138,7 +138,7 @@ export class PartnersComponent implements OnInit, AfterViewInit { | |||
| this.websiteOrderAsc = order; | |||
| break; | |||
| } | |||
| this.getData(); | |||
| this.getPartnersData(); | |||
| } | |||
| handlePageEvent(e: PageEvent) { | |||
| @@ -146,7 +146,7 @@ export class PartnersComponent implements OnInit, AfterViewInit { | |||
| this.length = e.length; | |||
| this.pageIndex = e.pageIndex.valueOf(); | |||
| this.pageSize = e.pageSize.valueOf(); | |||
| this.getData(); | |||
| this.getPartnersData(); | |||
| } | |||
| navigateToPartnerDetails(element: any) { | |||
| @@ -163,7 +163,7 @@ export class PartnersComponent implements OnInit, AfterViewInit { | |||
| modalRefContact.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefContact.dismiss(); | |||
| this.getData(); | |||
| this.getPartnersData(); | |||
| } | |||
| }); | |||
| } | |||
| @@ -11,7 +11,7 @@ | |||
| {{ 'overview.number' | translate }} | |||
| </th> | |||
| <td mat-cell | |||
| *matCellDef="let element">{{ (productsPageSize * productPageIndex) + productsDataSource.filteredData.indexOf(element) + 1 }} | |||
| *matCellDef="let element">{{ (productsPageSize * productsPageIndex) + productsDataSource.filteredData.indexOf(element) + 1 }} | |||
| </td> | |||
| </ng-container> | |||
| @@ -61,7 +61,7 @@ | |||
| [length]="productsLength" | |||
| (page)="handlePageEvent($event)" | |||
| [pageSize]="productsPageSize" | |||
| [pageIndex]="productPageIndex" | |||
| [pageIndex]="productsPageIndex" | |||
| showFirstLastButtons> | |||
| </mat-paginator> | |||
| </div> | |||
| @@ -32,7 +32,7 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| protected productsLength: number; | |||
| protected productsPageEvent: PageEvent; | |||
| protected productsPageSize: number; | |||
| protected productPageIndex: number; | |||
| protected productsPageIndex: number; | |||
| protected modalOptions: NgbModalOptions = { | |||
| centered: true | |||
| @@ -53,11 +53,11 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| this.productsLength = 0; | |||
| this.productsPageEvent = new PageEvent(); | |||
| this.productsPageSize = 10; | |||
| this.productPageIndex = 0; | |||
| this.productsPageIndex = 0; | |||
| } | |||
| ngOnInit() { | |||
| this.getProductData(); | |||
| this.getProductsData(); | |||
| } | |||
| ngAfterViewInit() { | |||
| @@ -65,9 +65,9 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| this.productsDataSource.paginator = this.productsPaginator; | |||
| } | |||
| getProductData() { | |||
| getProductsData() { | |||
| this.productsSub = this.productService.productsGetCollection( | |||
| this.productPageIndex + 1, | |||
| this.productsPageIndex + 1, | |||
| this.productsPageSize | |||
| ).subscribe( | |||
| data => { | |||
| @@ -82,7 +82,7 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| /** Announce the change in sort state for assistive technology. */ | |||
| onSortChange(sortState: Sort) { | |||
| // Reset page index to first page | |||
| this.productPageIndex = 0; | |||
| this.productsPageIndex = 0; | |||
| let order: OrderFilter; | |||
| if (sortState.direction === "") { | |||
| @@ -105,15 +105,15 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| // this.websiteOrderAsc = order; | |||
| // break; | |||
| // } | |||
| this.getProductData(); | |||
| this.getProductsData(); | |||
| } | |||
| handlePageEvent(e: PageEvent) { | |||
| this.productsPageEvent = e; | |||
| this.productsLength = e.length; | |||
| this.productPageIndex = e.pageIndex.valueOf(); | |||
| this.productsPageIndex = e.pageIndex.valueOf(); | |||
| this.productsPageSize = e.pageSize.valueOf(); | |||
| this.getProductData(); | |||
| this.getProductsData(); | |||
| } | |||
| navigateToProductDetails(element: any) { | |||
| @@ -130,7 +130,7 @@ export class ProductsComponent implements OnInit, AfterViewInit { | |||
| modalRefProduct.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefProduct.dismiss(); | |||
| this.getProductData(); | |||
| this.getProductsData(); | |||
| } | |||
| }); | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| <h2 *ngIf="!taskNote.id">{{'basic.new-comment' | translate}}</h2> | |||
| <h2 *ngIf="taskNote.id">{{'basic.edit-comment' | translate}}</h2> | |||
| <h2 *ngIf="!taskNote.id">{{'basic.new-task-note' | translate}}</h2> | |||
| <h2 *ngIf="taskNote.id">{{'basic.edit-task-note' | translate}}</h2> | |||
| <div class="spt-form"> | |||
| <form [formGroup]="taskNoteForm" (ngSubmit)="onSubmit()"> | |||
| <div class="mb-3"> | |||
| @@ -18,6 +18,17 @@ | |||
| </div> | |||
| </div> | |||
| <div class="mb-3" *ngIf="task.partner == null"> | |||
| <label for="partner" class="form-label">{{'form.partner' | translate}}:</label> | |||
| <select class="form-control" id="partner" formControlName="partner"> | |||
| <!-- ALLE PARTNER LADEN ODER BESSER: ELASTIC SEARCH --> | |||
| <option value="/api/partners/101">CatalystX SAS</option> | |||
| </select> | |||
| <div class="form-text" *ngIf="taskForm.get('partner')?.invalid && taskForm.get('partner')?.touched"> | |||
| {{'form.partner' | translate}} {{'form.mandatory' | translate}}. | |||
| </div> | |||
| </div> | |||
| <div class="mb-3"> | |||
| <label for="assignedTo" class="form-label">{{'form.assign-to' | translate}}:</label> | |||
| <input type="text" class="form-control" id="assignedTo" [ngbTypeahead]="search" [inputFormatter]="formatter" | |||
| @@ -1,5 +1,62 @@ | |||
| <div class="d-flex justify-content-between align-items-start"> | |||
| <h2>{{'basic.tasks' | translate}}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewTask()">{{'basic.new-product' | translate}}</button> | |||
| </div> | |||
| <p>tasks works!</p> | |||
| <div class="spt-container"> | |||
| <div class="spt-accordion"> | |||
| <div class="d-flex justify-content-between align-items-start"> | |||
| <h2>{{'basic.tasks' | translate}}</h2> | |||
| <button class="btn btn-primary" (click)="openModalNewTask()">{{'basic.new-task' | translate}}</button> | |||
| </div> | |||
| <div class="tasks mb-3" *ngFor="let task of tasks"> | |||
| <div class="card p-3"> | |||
| <div class="position-relative" data-bs-toggle="collapse" [attr.data-bs-target]="'#collapse-' + ApiConverter.extractId(task.id)" | |||
| aria-expanded="false" | |||
| aria-controls="collapseExample"> | |||
| <h3 class="m-0">{{task.partnerName}}</h3> | |||
| <span class="info d-flex position-absolute"> | |||
| <span class="due-date">{{ task.dueAt | date:'dd.MM.YYYY HH:mm':'GMT+0000' }}</span> | |||
| <span class="importance" [attr.data-importance]="task.prio"></span> | |||
| </span> | |||
| <h2 class="m-0">{{task.headline}}</h2> | |||
| </div> | |||
| <div class="collapse" id="collapse-{{ApiConverter.extractId(task.id)}}"> | |||
| <div class="pt-3 pe-5 position-relative"> | |||
| <p class="m-0">{{task.description}}</p> | |||
| <p>Zugewiesen an: {{task.assignedToName}}</p> | |||
| <span *ngIf="task.createdBy === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" data-action="edit" (click)="openModalEditTask(task)"></span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div *ngIf="task.id && taskNotesVisibility.get(task.id)"> | |||
| <div class="card ms-5" *ngFor="let taskNote of task.taskNotes"> | |||
| <div class="card-body"> | |||
| <div class="d-flex justify-content-between align-items-center"> | |||
| <p>{{ taskNote.createdAt | date:'dd.MM.YYYY HH:mm' }}</p> | |||
| <p>{{ taskNote.ownerName }}</p> | |||
| </div> | |||
| <div> | |||
| <p>{{ taskNote.message }}</p> | |||
| </div> | |||
| <span *ngIf="taskNote.owner === user?.id" class="position-absolute bi bi-pencil p-2" | |||
| data-type="user-tool" data-action="edit" (click)="openModalEditTaskNote(taskNote)"></span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="d-flex justify-content-end mt-1"> | |||
| <span *ngIf="task.taskNotes?.length !== 0" role="button" class="badge bg-secondary p-2 me-2" | |||
| (click)="showTaskNotes(task)"> | |||
| <ng-container *ngIf="task.id && taskNotesVisibility.get(task.id)">{{ 'basic.hide-comments' | translate }}</ng-container> | |||
| <ng-container *ngIf="task.id && !taskNotesVisibility.get(task.id)">{{ 'basic.show-comments' | translate }}</ng-container> | |||
| </span> | |||
| <span role="button" class="badge bg-secondary p-2" (click)="openModalNewTaskNote(task)">{{'basic.comment-it' | translate}}</span> | |||
| </div> | |||
| </div> | |||
| <mat-paginator *ngIf="tasks.length > 0" class="rounded-1" | |||
| [pageSizeOptions]="[10,20,30]" | |||
| [length]="tasksLength" | |||
| (page)="tasksHandlePageEvent($event)" | |||
| [pageSize]="tasksPageSize" | |||
| [pageIndex]="tasksPageIndex" | |||
| showFirstLastButtons> | |||
| </mat-paginator> | |||
| </div> | |||
| </div> | |||
| @@ -1,27 +1,149 @@ | |||
| import {Component, OnInit} from '@angular/core'; | |||
| import {AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core'; | |||
| import {NewTaskComponent} from "@app/tasks/new-task/new-task.component"; | |||
| import {NgbModal} from "@ng-bootstrap/ng-bootstrap"; | |||
| import {NgbModal, NgbModalOptions} from "@ng-bootstrap/ng-bootstrap"; | |||
| import {ModalComponent} from "@app/_components/modal/modal.component"; | |||
| import {ApiConverter} from "@app/_helpers/api.converter"; | |||
| import {Subscription} from "rxjs"; | |||
| import {TaskJsonld, TaskNoteJsonld, TaskService} from "@app/core/api/v1"; | |||
| import {MatPaginator, MatPaginatorIntl, PageEvent} from "@angular/material/paginator"; | |||
| import {MatTableDataSource} from "@angular/material/table"; | |||
| import {User} from "@app/_models"; | |||
| import {AccountService} from "@app/_services"; | |||
| import {ModalStatus} from "@app/_helpers/modal.states"; | |||
| import {NewTaskNoteComponent} from "@app/tasks/new-task-note/new-task-note.component"; | |||
| @Component({ | |||
| selector: 'app-tasks', | |||
| templateUrl: './tasks.component.html', | |||
| styleUrl: './tasks.component.scss' | |||
| selector: 'app-tasks', | |||
| templateUrl: './tasks.component.html', | |||
| styleUrl: './tasks.component.scss' | |||
| }) | |||
| export class TasksComponent implements OnInit { | |||
| export class TasksComponent implements OnInit, AfterViewInit { | |||
| @ViewChild(MatPaginator) tasksPaginator: MatPaginator; | |||
| constructor( | |||
| private modalService: NgbModal | |||
| ) { | |||
| protected user: User | null; | |||
| protected readonly ApiConverter = ApiConverter; | |||
| } | |||
| protected tasksSub: Subscription; | |||
| protected tasks: Array<TaskJsonld>; | |||
| protected tasksDataSource; | |||
| protected tasksLength: number; | |||
| protected tasksPageEvent: PageEvent; | |||
| protected tasksPageSize: number; | |||
| protected tasksPageIndex: number; | |||
| ngOnInit() { | |||
| protected taskNotesVisibility: Map<string, boolean>; | |||
| } | |||
| protected modalOptions: NgbModalOptions = { | |||
| centered: true | |||
| }; | |||
| openModalNewTask() { | |||
| const modalRef = this.modalService.open(ModalComponent); | |||
| modalRef.componentInstance.dynamicComponent = NewTaskComponent; | |||
| } | |||
| constructor( | |||
| private modalService: NgbModal, | |||
| private accountService: AccountService, | |||
| private taskService: TaskService | |||
| ) { | |||
| this.user = this.accountService.userValue; | |||
| this.tasksSub = new Subscription(); | |||
| this.tasks = []; | |||
| this.tasksPaginator = new MatPaginator(new MatPaginatorIntl(), ChangeDetectorRef.prototype); | |||
| this.tasksDataSource = new MatTableDataSource<TaskJsonld>(this.tasks); | |||
| this.tasksLength = 0; | |||
| this.tasksPageEvent = new PageEvent(); | |||
| this.tasksPageSize = 10; | |||
| this.tasksPageIndex = 0; | |||
| this.taskNotesVisibility = new Map<string, boolean>(); | |||
| } | |||
| ngOnInit() { | |||
| this.getTasksData(); | |||
| } | |||
| ngAfterViewInit() { | |||
| this.tasksDataSource.paginator = this.tasksPaginator; | |||
| } | |||
| getTasksData() { | |||
| this.tasksSub = this.taskService.tasksGetCollection( | |||
| this.tasksPageIndex + 1, | |||
| this.tasksPageSize, | |||
| // TODO: User-ID muss übergeben werden können, damit man nur die Tasks bekommt, die einem User zugewiesen sind | |||
| ).subscribe( | |||
| data => { | |||
| this.tasks = data["hydra:member"]; | |||
| this.tasksLength = Number(data["hydra:totalItems"]); | |||
| this.tasks.forEach(task => { | |||
| if (task.id) { | |||
| this.taskNotesVisibility.set(task.id, false); | |||
| } | |||
| }); | |||
| console.log(this.tasks); | |||
| } | |||
| ); | |||
| } | |||
| tasksHandlePageEvent(e: PageEvent) { | |||
| this.tasksPageEvent = e; | |||
| this.tasksLength = e.length; | |||
| this.tasksPageIndex = e.pageIndex.valueOf(); | |||
| this.tasksPageSize = e.pageSize.valueOf(); | |||
| this.getTasksData(); | |||
| } | |||
| openModalNewTask() { | |||
| const modalRefTask = this.modalService.open(NewTaskComponent, this.modalOptions); | |||
| let task: TaskJsonld = {} as TaskJsonld; | |||
| task.partner = null; | |||
| task.completed = false; | |||
| modalRefTask.componentInstance.task = task; | |||
| modalRefTask.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefTask.dismiss(); | |||
| this.getTasksData(); | |||
| } | |||
| }); | |||
| } | |||
| openModalNewTaskNote(task: TaskJsonld) { | |||
| const modalRefTaskNote = this.modalService.open(NewTaskNoteComponent, this.modalOptions); | |||
| let taskNote: TaskNoteJsonld = {} as TaskNoteJsonld; | |||
| taskNote.task = task.id ?? null; | |||
| modalRefTaskNote.componentInstance.taskNote = taskNote; | |||
| modalRefTaskNote.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefTaskNote.dismiss(); | |||
| this.getTasksData(); | |||
| } | |||
| }); | |||
| } | |||
| openModalEditTask(task: TaskJsonld) { | |||
| const modalRefTaskEdit = this.modalService.open(NewTaskComponent, this.modalOptions); | |||
| modalRefTaskEdit.componentInstance.task = task; | |||
| modalRefTaskEdit.componentInstance.dueAtValue = ApiConverter.convertDate(task.dueAt); | |||
| modalRefTaskEdit.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefTaskEdit.dismiss(); | |||
| this.getTasksData(); | |||
| } | |||
| }); | |||
| } | |||
| openModalEditTaskNote(taskNote: TaskNoteJsonld) { | |||
| const modalRefTaskNote = this.modalService.open(NewTaskNoteComponent, this.modalOptions); | |||
| modalRefTaskNote.componentInstance.taskNote = taskNote; | |||
| modalRefTaskNote.componentInstance.submit.subscribe((modalStatus: ModalStatus) => { | |||
| if (modalStatus === ModalStatus.Submitted) { | |||
| modalRefTaskNote.dismiss(); | |||
| this.getTasksData(); | |||
| } | |||
| }); | |||
| } | |||
| showTaskNotes(task: TaskJsonld) { | |||
| if (task.id) { | |||
| const currentVisibility = this.taskNotesVisibility.get(task.id); | |||
| this.taskNotesVisibility.set(task.id, !currentVisibility); | |||
| } | |||
| } | |||
| } | |||
| @@ -26,6 +26,7 @@ | |||
| "new-contact": "Neuer Kontakt", | |||
| "new-post": "Neue Notiz", | |||
| "new-comment": "Neuer Kommentar", | |||
| "new-task-note": "Neue Anmerkung", | |||
| "edit-before": "", | |||
| "edit-after": "bearbeiten", | |||
| "edit-product": "Produkt bearbeiten", | |||
| @@ -34,8 +35,11 @@ | |||
| "edit-contact": "Kontakt bearbeiten", | |||
| "edit-post": "Notiz bearbeiten", | |||
| "edit-comment": "Kommentar bearbeiten", | |||
| "edit-task-note": "Anmerkung bearbeiten", | |||
| "details": "Details", | |||
| "comment-it": "Kommentieren", | |||
| "show-comments": "Kommentare anzeigen", | |||
| "hide-comments": "Kommentare ausblenden", | |||
| "back": "Zurück" | |||
| }, | |||
| "user": | |||
| @@ -85,6 +89,7 @@ | |||
| "prio-low": "niedrig", | |||
| "prio-medium": "mittel", | |||
| "prio-high": "hoch", | |||
| "partner": "Partner", | |||
| "send": "Abschicken" | |||
| } | |||
| } | |||