Skip to content

Commit

Permalink
use pipe with map to generate menu entries
Browse files Browse the repository at this point in the history
  • Loading branch information
kcinay055679 committed Oct 23, 2024
1 parent 29ed668 commit f9cee52
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 122 deletions.
150 changes: 74 additions & 76 deletions frontend/src/app/components/objective/objective.component.html
Original file line number Diff line number Diff line change
@@ -1,82 +1,80 @@
<div *ngIf="objective$ | async as objective">
<div
(click)="openObjectiveDetail(objective.id)"
(keydown.enter)="openObjectiveDetail(objective.id)"
[attr.data-testId]="'objective'"
class="objective rounded-3 bg-white w-100 cursor-pointer focus-outline"
tabindex="0"
>
<div class="row mx-1">
<section class="d-flex mb-3 mt-3 justify-content-between pe-0">
<section class="d-flex gap-2 align-items-start fit-content objective-title">
<img
(click)="$event.stopPropagation()"
[attr.data-testId]="'objective-state'"
[src]="'assets/icons/' + objective.state"
alt="The objectives state"
class="icon"
matTooltip="{{ getStateTooltip() + ' ' + formatObjectiveState(objective.state) }}"
matTooltipPosition="above"
/>
<h2 class="title fit-content">{{ objective.title }}</h2>
</section>
<button
#menuButton
*ngIf="isWritable"
class="icon-button three-dot-menu focus-outline"
[matMenuTriggerFor]="objectiveMenu"
<div
(click)="openObjectiveDetail(objective.id)"
(keydown.enter)="openObjectiveDetail(objective.id)"
*ngIf="objective$ | async as objective"
[attr.data-testId]="'objective'"
class="objective rounded-3 bg-white w-100 cursor-pointer focus-outline"
tabindex="0"
>
<div class="row mx-1">
<section class="d-flex mb-3 mt-3 justify-content-between pe-0">
<section class="d-flex gap-2 align-items-start fit-content objective-title">
<img
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
[attr.data-testId]="'three-dot-menu'"
>
<img src="../assets/icons/three-dot-menu-icon.svg" alt="menu icon" class="text-white menu-scale" />
</button>
[attr.data-testId]="'objective-state'"
[src]="'assets/icons/' + objective.state"
alt="The objectives state"
class="icon"
matTooltip="{{ getStateTooltip() + ' ' + formatObjectiveState(objective.state) }}"
matTooltipPosition="above"
/>
<h2 class="title fit-content">{{ objective.title }}</h2>
</section>
<button
*ngIf="isWritable"
class="icon-button three-dot-menu focus-outline"
[matMenuTriggerFor]="objectiveMenu"
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
[attr.data-testId]="'three-dot-menu'"
>
<img src="../assets/icons/three-dot-menu-icon.svg" alt="menu icon" class="text-white menu-scale" />
</button>
</section>

<div class="d-flex px-3 gap-3 flex-column">
<app-keyresult
*ngFor="let keyResult of objective.keyResults; trackBy: trackByFn"
class="border-0 p-0"
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
[keyResult]="keyResult"
[attr.data-testId]="'keyresult'"
></app-keyresult>
</div>

<section class="p-0 py-2 m-0">
<button
*ngIf="!isObjectiveComplete(this.objective) && isWritable"
mat-button
color="primary"
class="fw-bold px-0 pe-2 ms-2"
[attr.data-testId]="'add-keyResult'"
(click)="openAddKeyResultDialog(); $event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
>
<span class="d-flex align-items-center add-text">
<img alt="Add key-result button" class="add-cross-button" src="../../../assets/icons/new-icon.svg" />
Key Result hinzufügen
</span>
</button>
</section>
<div class="d-flex px-3 gap-3 flex-column">
<app-keyresult
*ngFor="let keyResult of objective.keyResults; trackBy: trackByFn"
class="border-0 p-0"
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
[keyResult]="keyResult"
[attr.data-testId]="'keyresult'"
></app-keyresult>
</div>

<section class="p-0 py-2 m-0">
<button
*ngIf="!isObjectiveComplete(this.objective) && isWritable"
mat-button
color="primary"
class="fw-bold px-0 pe-2 ms-2"
[attr.data-testId]="'add-keyResult'"
(click)="openAddKeyResultDialog(); $event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
>
<span class="d-flex align-items-center add-text">
<img alt="Add key-result button" class="add-cross-button" src="../../../assets/icons/new-icon.svg" />
Key Result hinzufügen
</span>
</button>
</section>
</div>
<mat-menu
#objectiveMenu="matMenu"
[class]="'objective-three-dot-menu'"
class="pt-2 pb-2"
xPosition="before"
yPosition="below"
>
<button
(click)="$event.stopPropagation(); console.log('menuEntry', menuEntry)"
*ngFor="let menuEntry of getMenu(objective)"
[attr.data-testId]="'objective-menu'"
class="objective-menu-option"
mat-menu-item
>
{{ menuEntry.displayName }}123
</button>
</mat-menu>
</div>
<mat-menu
#objectiveMenu="matMenu"
[class]="'objective-three-dot-menu'"
class="pt-2 pb-2"
xPosition="before"
yPosition="below"
>
<button
(click)="redirect(menuEntry)"
*ngFor="let menuEntry of menuEntries | async"
[attr.data-testId]="'objective-menu'"
class="objective-menu-option"
mat-menu-item
>
{{ menuEntry.displayName }}
</button>
</mat-menu>
42 changes: 9 additions & 33 deletions frontend/src/app/components/objective/objective.component.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { MenuEntry } from '../../shared/types/menu-entry';
import { ObjectiveMin } from '../../shared/types/model/ObjectiveMin';
import { Router } from '@angular/router';
import { ObjectiveFormComponent } from '../../shared/dialog/objective-dialog/objective-form.component';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, map } from 'rxjs';
import { RefreshDataService } from '../../services/refresh-data.service';
import { State } from '../../shared/types/enums/State';
import { ObjectiveService } from '../../services/objective.service';
import { ConfirmDialogComponent } from '../../shared/dialog/confirm-dialog/confirm-dialog.component';
import { CompleteDialogComponent } from '../../shared/dialog/complete-dialog/complete-dialog.component';
import { Completed } from '../../shared/types/model/Completed';
import { Objective } from '../../shared/types/model/Objective';
import { trackByFn } from '../../shared/common';
import { isObjectiveComplete, trackByFn } from '../../shared/common';
import { KeyresultDialogComponent } from '../keyresult-dialog/keyresult-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import { GJ_REGEX_PATTERN } from '../../shared/constantLibary';
import { DialogService } from '../../services/dialog.service';
import { ObjectiveMenuActionsService, ObjectiveMenuEntry } from '../../services/objective-menu-actions.service';

Expand All @@ -24,11 +20,13 @@ import { ObjectiveMenuActionsService, ObjectiveMenuEntry } from '../../services/
styleUrls: ['./objective.component.scss'],
})
export class ObjectiveComponent implements OnInit {
@Input()
isWritable!: boolean;
@Input() isWritable!: boolean;
isComplete: boolean = false;
public objective$ = new BehaviorSubject<ObjectiveMin>({} as ObjectiveMin);
menuEntries = this.objective$.pipe(map((objective) => this.objectiveMenuActionsService.getMenu(objective)));
protected readonly trackByFn = trackByFn;
@ViewChild('menuButton') private menuButton!: ElementRef;
protected readonly console = console;
protected readonly isObjectiveComplete = isObjectiveComplete;

constructor(
private dialogService: DialogService,
Expand All @@ -39,13 +37,10 @@ export class ObjectiveComponent implements OnInit {
private objectiveMenuActionsService: ObjectiveMenuActionsService,
) {}

@Input()
set objective(objective: ObjectiveMin) {
@Input() set objective(objective: ObjectiveMin) {
this.objective$.next(objective);
}

public objective$ = new BehaviorSubject<ObjectiveMin>({} as ObjectiveMin);

ngOnInit() {}

formatObjectiveState(state: string): string {
Expand All @@ -61,23 +56,6 @@ export class ObjectiveComponent implements OnInit {
return this.translate.instant('INFORMATION.OBJECTIVE_STATE_TOOLTIP');
}

isObjectiveComplete(objective: ObjectiveMin): boolean {
return objective.state == State.SUCCESSFUL || objective.state == State.NOTSUCCESSFUL;
}

getMenu(objective: ObjectiveMin): ObjectiveMenuEntry[] {
console.log('get');
if (this.isObjectiveComplete(objective)) {
return this.objectiveMenuActionsService.getCompletedMenuActions(objective);
} else if (objective.state === State.ONGOING) {
return this.objectiveMenuActionsService.getOngoingMenuActions(objective);
} else if (objective.state === State.DRAFT) {
return this.objectiveMenuActionsService.getDraftMenuActions(objective);
}
//Probably throw an error here
return [];
}

redirect(menuEntry: ObjectiveMenuEntry) {
console.log('test');
console.log(menuEntry.action);
Expand Down Expand Up @@ -172,6 +150,4 @@ export class ObjectiveComponent implements OnInit {
this.refreshDataService.markDataRefresh();
});
}

protected readonly console = console;
}
35 changes: 22 additions & 13 deletions frontend/src/app/services/objective-menu-actions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { MatDialogRef } from '@angular/material/dialog';
import { ObjectiveFormComponent } from '../shared/dialog/objective-dialog/objective-form.component';
import { CompleteDialogComponent } from '../shared/dialog/complete-dialog/complete-dialog.component';
import { ObjectiveMin } from '../shared/types/model/ObjectiveMin';
import { GJ_REGEX_PATTERN } from '../shared/constantLibary';
import { State } from '../shared/types/enums/State';
import { isInBacklogQuarter, isObjectiveComplete } from '../shared/common';

export type ObjectiveMenuAction = () => MatDialogRef<any>;

Expand All @@ -20,48 +21,56 @@ export interface ObjectiveMenuEntry {
export class ObjectiveMenuActionsService {
constructor(private readonly dialogService: DialogService) {}

isInBacklogQuarter(objective: ObjectiveMin) {
return !GJ_REGEX_PATTERN.test(objective.quarter.label);
getMenu(objective: ObjectiveMin): ObjectiveMenuEntry[] {
if (isObjectiveComplete(objective)) {
return this.getCompletedMenuActions(objective);
} else if (objective.state === State.ONGOING) {
return this.getOngoingMenuActions(objective);
} else if (objective.state === State.DRAFT) {
return this.getDraftMenuActions(objective);
}
//Probably throw an error here
return [];
}

getOngoingMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
private getOngoingMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
return [
...this.getDefaultActions(objective),
this.saveObjectiveAsDraftAction(),
this.completeObjectiveAction(objective),
];
}

getDefaultActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
private getDefaultActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
return [this.editObjectiveAction(objective), this.duplicateObjectiveAction(objective)];
}

getDraftMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
const releaseAction = this.isInBacklogQuarter(objective)
private getDraftMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
const releaseAction = isInBacklogQuarter(objective)
? this.releaseFromDraftInBacklogAction(objective)
: this.releaseFromDraftAction(objective);
return [releaseAction];
}

releaseFromDraftAction(objective: ObjectiveMin): ObjectiveMenuEntry {
private releaseFromDraftAction(objective: ObjectiveMin): ObjectiveMenuEntry {
const action = () => this.dialogService.openConfirmDialog('CONFIRMATION.RELEASE');
return { displayName: 'Objective veröffentlichen', action: action };
}

releaseFromDraftInBacklogAction(objective: ObjectiveMin): ObjectiveMenuEntry {
const config = { data: { action: 'releaseBacklog', objectiveId: objective } };
private releaseFromDraftInBacklogAction(objective: ObjectiveMin): ObjectiveMenuEntry {
const config = { data: { objective: { objectiveId: objective }, action: 'releaseBacklog' } };
const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, config);
return { displayName: 'Objective veröffentlichen', action: action };
}

private editObjectiveAction(objective: ObjectiveMin): ObjectiveMenuEntry {
const config = { data: { objectiveId: objective.id } };
const config = { data: { objective: { objectiveId: objective.id } } };
const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, config);
return { displayName: 'Objective bearbeiten', action: action };
}

private duplicateObjectiveAction(objective: ObjectiveMin): ObjectiveMenuEntry {
const config = { data: { objectiveId: objective.id } };
const config = { data: { objective: { objectiveId: objective.id } } };
const action = () => this.dialogService.open(ObjectiveFormComponent, config);
return { displayName: 'Objective duplizieren', action: action };
}
Expand All @@ -79,7 +88,7 @@ export class ObjectiveMenuActionsService {
return { displayName: 'Objective als Draft speicherns', action: action };
}

getCompletedMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
private getCompletedMenuActions(objective: ObjectiveMin): ObjectiveMenuEntry[] {
return [];
}
}
11 changes: 11 additions & 0 deletions frontend/src/app/shared/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { FormGroup } from '@angular/forms';
import { KeyResultMetricMin } from './types/model/KeyResultMetricMin';
import { ObjectiveMin } from './types/model/ObjectiveMin';
import { State } from './types/enums/State';
import { GJ_REGEX_PATTERN } from './constantLibary';

export function getNumberOrNull(str: string | null | undefined): number | null {
if (str === null || str === undefined || str.toString().trim() === '') {
Expand Down Expand Up @@ -95,6 +98,14 @@ export function isMobileDevice() {
return window.navigator.userAgent.toLowerCase().includes('mobile');
}

export function isInBacklogQuarter(objective: ObjectiveMin) {
return !GJ_REGEX_PATTERN.test(objective.quarter.label);
}

export function isObjectiveComplete(objective: ObjectiveMin): boolean {
return objective.state == State.SUCCESSFUL || objective.state == State.NOTSUCCESSFUL;
}

export function hasFormFieldErrors(formGroup: FormGroup, field: string) {
if (formGroup.get(field)?.dirty || formGroup.get(field)?.touched) {
return formGroup.get(field)?.errors;
Expand Down

0 comments on commit f9cee52

Please sign in to comment.