Merged PR 871: #1662 TK gelöschte Beiträge

#1662 TK gelöschte Beiträge

Related work items: #1662
This commit is contained in:
Andreas Schickinger
2021-09-23 09:10:45 +00:00
committed by Lorenz Hilpert
parent 7c10dde089
commit 4961e580c5
16 changed files with 206 additions and 41 deletions

View File

@@ -1,3 +1,3 @@
export type ProcessingStatusType = 'Approved' | 'InProcess' | 'Completed' | 'Overdue' | 'Archived' | 'Uncompleted';
export type ProcessingStatusType = 'Approved' | 'InProcess' | 'Completed' | 'Overdue' | 'Archived' | 'Uncompleted' | 'Removed';
export type ProcessingStatusList = ProcessingStatusType[];

View File

@@ -168,6 +168,10 @@ export class DomainTaskCalendarService {
processingStatusList.push('Archived');
}
if (!!(processingStatus & 32)) {
processingStatusList.push('Removed');
}
if (!!(processingStatus & 64)) {
processingStatusList.push('Uncompleted');
}

View File

@@ -1,5 +1,9 @@
:host {
@apply flex flex-col;
&.Removed {
@apply opacity-30;
}
}
.info-header {

View File

@@ -1,6 +1,6 @@
import { Clipboard } from '@angular/cdk/clipboard';
import { DatePipe } from '@angular/common';
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, Optional } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, Optional, HostBinding } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { FileDTO } from '@swagger/checkout';
import { DisplayInfoDTO } from '@swagger/eis';
@@ -108,6 +108,11 @@ export class TaskInfoComponent implements OnChanges {
)
);
@HostBinding('class')
get statusClass() {
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
}
constructor(
private dateAdapter: DateAdapter,
private datePipe: DatePipe,

View File

@@ -42,3 +42,11 @@
@apply opacity-30;
}
}
.task-list ::ng-deep page-task-list-item.Removed {
.date,
.shirt-size,
.task-content {
@apply opacity-30 line-through;
}
}

View File

@@ -55,7 +55,8 @@ export class TaskListComponent {
}
return false;
});
})
}),
map((list) => list.sort(this.moveRemovedToEnd.bind(this)))
);
ongoingItems$ = combineLatest([this.items$, this.selected$]).pipe(
@@ -81,7 +82,8 @@ export class TaskListComponent {
selectedItems$ = combineLatest([this.items$, this.selected$]).pipe(
map(([items, date]) => items.filter((item) => this.dateAdapter.equals(this.domainTaskCalendarService.getDisplayInfoDate(item), date))),
// Sortierung der aufgaben nach Rot => Gelb => Grau => Grün
map((list) => this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed']))
map((list) => this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed', 'Removed'])),
map((list) => list.sort(this.moveRemovedToEnd.bind(this)))
);
@Output()
@@ -95,6 +97,21 @@ export class TaskListComponent {
private domainPrinterService: DomainPrinterService
) {}
moveRemovedToEnd(a: DisplayInfoDTO, b: DisplayInfoDTO) {
const statusA = this.domainTaskCalendarService.getProcessingStatusList(a)?.includes('Removed');
const statusB = this.domainTaskCalendarService.getProcessingStatusList(b)?.includes('Removed');
if (statusA && statusB) {
return 0;
} else if (statusA && !statusB) {
return 1;
} else if (!statusA && statusB) {
return -1;
}
return 0;
}
/**
* Returns an Array of DisplayInfoDTO, sorted by ProcessingStatus
* Ignores Overdue if Task is already Completed
@@ -105,8 +122,9 @@ export class TaskListComponent {
*/
sort(items: DisplayInfoDTO[], order: ProcessingStatusList) {
let result = [...items];
const reversedOrder = [...order].reverse();
for (const status of [...order].reverse()) {
for (const status of reversedOrder) {
result = result?.sort((a, b) => {
const statusA = this.domainTaskCalendarService.getProcessingStatusList(a);
const statusB = this.domainTaskCalendarService.getProcessingStatusList(b);

View File

@@ -4,4 +4,10 @@
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
</div>
<page-task-info [info]="info"></page-task-info>
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
<button class="btn-close" type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
<div class="actions">
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
Zur neuen Aufgabe
</button>
</div>

View File

@@ -1,5 +1,11 @@
:host {
@apply flex flex-col relative;
&.Removed {
h1 {
@apply opacity-30 line-through;
}
}
}
.header {
@@ -18,10 +24,18 @@ h3 {
@apply absolute m-0 -top-4 p-4 pl-0 text-regular text-active-branch uppercase;
}
button {
.btn-close {
@apply absolute -top-4 -right-4 p-4 outline-none border-none bg-transparent;
ui-icon {
@apply text-inactive-branch;
}
}
.actions {
@apply text-center mb-5 mt-6 sticky bottom-1;
.btn-cta {
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
}
}

View File

@@ -1,7 +1,9 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Component, ChangeDetectionStrategy, HostBinding } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { DisplayInfoDTO } from '@swagger/eis';
import { UiModalRef } from '@ui/modal';
import { Subscription } from 'rxjs';
import { combineLatest, ReplaySubject } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
@Component({
selector: 'page-info-modal',
@@ -12,11 +14,31 @@ import { Subscription } from 'rxjs';
export class InfoModalComponent {
info: DisplayInfoDTO;
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
this.info = this.modalRef.data;
info$ = new ReplaySubject<DisplayInfoDTO>();
processingStatus$ = this.info$.pipe(
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
shareReplay()
);
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
);
@HostBinding('class')
get statusClass() {
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
}
close() {
this.modalRef.close();
constructor(
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
private domainTaskCalendarService: DomainTaskCalendarService
) {
this.info = this.modalRef.data;
this.info$.next(this.info);
}
close(successorId: number = undefined) {
this.modalRef.close({ successorId });
}
}

View File

@@ -4,4 +4,10 @@
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
</div>
<page-task-info [info]="info" showTaskDate="true"></page-task-info>
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
<button class="btn-close" type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>
<div class="actions">
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
Zur neuen Aufgabe
</button>
</div>

View File

@@ -1,5 +1,11 @@
:host {
@apply flex flex-col relative;
&.Removed {
h1 {
@apply opacity-30 line-through;
}
}
}
.header {
@@ -18,10 +24,18 @@ h3 {
@apply absolute m-0 -top-4 p-4 pl-0 text-regular text-active-branch uppercase;
}
button {
.btn-close {
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
ui-icon {
@apply text-inactive-branch;
}
}
.actions {
@apply text-center mb-5 mt-6 sticky bottom-1;
.btn-cta {
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
}
}

View File

@@ -1,6 +1,9 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { DisplayInfoDTO } from '@swagger/eis';
import { UiModalRef } from '@ui/modal';
import { combineLatest, ReplaySubject } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
@Component({
selector: 'page-preinfo-modal',
@@ -11,11 +14,31 @@ import { UiModalRef } from '@ui/modal';
export class PreInfoModalComponent {
info: DisplayInfoDTO;
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
this.info = this.modalRef.data;
info$ = new ReplaySubject<DisplayInfoDTO>();
processingStatus$ = this.info$.pipe(
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
shareReplay()
);
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
);
@HostBinding('class')
get statusClass() {
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
}
close() {
this.modalRef.close();
constructor(
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
private domainTaskCalendarService: DomainTaskCalendarService
) {
this.info = this.modalRef.data;
this.info$.next(this.info);
}
close(successorId: number = undefined) {
this.modalRef.close({ successorId });
}
}

View File

@@ -25,6 +25,9 @@
<button *ngIf="showCompleteEditCta$ | async" class="btn-cta" type="button" (click)="completeEdit()" [disabled]="editDisabled$ | async">
Bearbeitung abschließen
</button>
<button *ngIf="showOpenSuccessorCta$ | async" class="btn-cta" type="button" (click)="close(info.successor?.id)">
Zur neuen Aufgabe
</button>
<div *ngIf="showCameraCta$ | async" [disabled]="editDisabled$ | async">
<ng-container>
<div class="camera-hint">Bitte fotografieren Sie die Präsentation, um die<br />Aufgabe abschließen zu können</div>

View File

@@ -1,5 +1,14 @@
:host {
@apply flex flex-col relative;
&.Removed {
.header {
@apply opacity-30 line-through;
}
.status {
@apply opacity-30;
}
}
}
.header {

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, HostBinding, ViewChild } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { DisplayInfoDTO } from '@swagger/eis';
import { DateAdapter } from '@ui/common';
@@ -6,7 +6,7 @@ import { UiMessageModalComponent, UiModalRef, UiModalService } from '@ui/modal';
import { isNullOrUndefined } from '@utils/common';
import { NativeContainerService } from 'native-container';
import { combineLatest, ReplaySubject } from 'rxjs';
import { map, tap, shareReplay, switchMap } from 'rxjs/operators';
import { map, shareReplay, switchMap } from 'rxjs/operators';
import { CameraCaptureModalComponent } from '../camera/camera-capture-modal.component';
@Component({
@@ -44,6 +44,11 @@ export class TaskModalComponent {
})
);
@HostBinding('class')
get statusClass() {
return this.domainTaskCalendarService.getProcessingStatusList(this.info);
}
editDisabled$ = this.info$.pipe(
map((info) => {
if (info.publicationDate && info.taskDate && info.taskOverdueDate) {
@@ -65,22 +70,37 @@ export class TaskModalComponent {
showStartEditCta$ = this.processingStatus$.pipe(
map(
(processingStatus) =>
!processingStatus.includes('Uncompleted') && !processingStatus.includes('InProcess') && !processingStatus.includes('Completed')
!processingStatus.includes('Uncompleted') &&
!processingStatus.includes('InProcess') &&
!processingStatus.includes('Completed') &&
!processingStatus.includes('Removed')
)
);
showCompleteEditCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
map(([processingStatus, info]) => processingStatus.includes('InProcess') && !info.requiresImageOnConfirmation)
map(
([processingStatus, info]) =>
processingStatus.includes('InProcess') && !info.requiresImageOnConfirmation && !processingStatus.includes('Removed')
)
);
showCameraCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
map(([processingStatus, info]) => processingStatus.includes('InProcess') && info.requiresImageOnConfirmation)
map(
([processingStatus, info]) =>
processingStatus.includes('InProcess') && info.requiresImageOnConfirmation && !processingStatus.includes('Removed')
)
);
showResetEditCta$ = this.processingStatus$.pipe(map((processingStatus) => processingStatus.includes('Completed')));
showResetEditCta$ = this.processingStatus$.pipe(
map((processingStatus) => processingStatus.includes('Completed') && !processingStatus.includes('Removed'))
);
showOpenSuccessorCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
map(([processingStatus, info]) => processingStatus.includes('Removed') && !!info.successor?.id)
);
constructor(
private modalRef: UiModalRef<DisplayInfoDTO>,
private modalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>,
private domainTaskCalendarService: DomainTaskCalendarService,
private uiModal: UiModalService,
private nativeContainer: NativeContainerService,
@@ -90,8 +110,8 @@ export class TaskModalComponent {
this.info$.next(this.info);
}
close() {
this.modalRef.close();
close(successorId: number = undefined) {
this.modalRef.close({ successorId });
}
async startEdit() {

View File

@@ -5,10 +5,10 @@ import { DisplayInfoDTO, InputDTO, ResponseArgsOfIEnumerableOfInputDTO } from '@
import { CalendarIndicator } from '@ui/calendar';
import { DateAdapter } from '@ui/common';
import { Filter, FilterOption, SelectFilter, UiFilterMappingService } from '@ui/filter';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { UiMessageModalComponent, UiModalRef, UiModalResult, UiModalService } from '@ui/modal';
import { clone } from 'lodash';
import { combineLatest, Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, withLatestFrom } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { debounceTime, map, switchMap, withLatestFrom } from 'rxjs/operators';
import { InfoModalComponent } from './modals/info/info-modal.component';
import { PreInfoModalComponent } from './modals/preinfo/preinfo-modal.component';
import { TaskModalComponent } from './modals/task/task-modal.component';
@@ -172,36 +172,45 @@ export class TaskCalendarStore extends ComponentStore<TaskCalendarState> {
open(displayInfoDTO: DisplayInfoDTO) {
const type = this.domainTaskCalendarService.getInfoType(displayInfoDTO);
let taskModalRef: UiModalRef<{ successorId: number }, DisplayInfoDTO>;
switch (type) {
case 'Info':
this.uiModal.open({
taskModalRef = this.uiModal.open({
content: InfoModalComponent,
data: displayInfoDTO,
});
break;
case 'PreInfo':
this.uiModal.open({
taskModalRef = this.uiModal.open({
content: PreInfoModalComponent,
data: displayInfoDTO,
});
break;
case 'Task':
const taskModalRef = this.uiModal.open<string, DisplayInfoDTO>({
taskModalRef = this.uiModal.open({
content: TaskModalComponent,
data: displayInfoDTO,
});
taskModalRef.afterClosed$.subscribe({
complete: () => this.loadItems(),
});
break;
}
// TODO:
// Logik welcher Dialog soll angezeigt werden
taskModalRef?.afterClosed$.subscribe({
next: async (result: UiModalResult<{ successorId: number }>) => {
if (result.data?.successorId) {
const info = await this.domainTaskCalendarService
.getInfoById({ infoId: result.data.successorId })
.pipe(map((res) => res.result))
.toPromise();
if (info) {
this.open(info);
}
}
},
complete: () => this.loadItems(),
});
}
mapInputArrayToFilterArray(source: InputDTO[]): SelectFilter[] {