Skip to content

Commit

Permalink
refactor action plan
Browse files Browse the repository at this point in the history
  • Loading branch information
kcinay055679 committed Jan 27, 2025
1 parent 6e70a66 commit b7b627d
Show file tree
Hide file tree
Showing 14 changed files with 218 additions and 221 deletions.
38 changes: 19 additions & 19 deletions frontend/src/app/components/action-plan/action-plan.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,46 @@
<label for="action-list" class="okr-form-label">Action Plan (optional)</label>
<div
cdkDropList
*ngIf="control?.getValue()"
[cdkDropListData]="control | async"
*ngIf="this.form"
(keydown.enter)="preventAddingNewItems($event)"
class="okr-form-col d-flex flex-column gap-2"
(cdkDropListDropped)="drop($event)"
id="action-list"
>
<div
class="action-point-item"
*ngFor="let action of (control | async)!; index as i; trackBy: trackByFn"
*ngFor="let item of getFormControlArray().controls!; index as i; trackBy: trackByFn"
[formGroupName]="i"
cdkDrag
>
<div class="drag-drop-dots">
<img
cdkDragHandle
class="icons"
src="../../../assets/icons/drag_indicator.svg"
src="assets/icons/drag_indicator.svg"
alt="Drag indicator"
/>
</div>
<input
#listItem
(keydown.arrowDown)="handleKeyDown($event, i)"
(keydown.arrowUp)="handleKeyDown($event, i)"
(focusin)="activeItem = i"
(input)="updateActionTexts(control.value!)"
(keydown.arrowUp)="changeItemPosition(i, i - 1)"
(keydown.arrowDown)="changeItemPosition(i, i + 1)"
class="action-input"
[value]="action.action"
formControlName="item"
[attr.data-testId]="'action-input'"
/>
<img
tabindex="0"
(keydown.tab)="increaseActiveItemWithTab()"
(keydown.shift.tab)="decreaseActiveItemWithShiftTab()"
<button
(keydown.enter)="removeAction(i)"
class="icons bin-icon cursor-pointer focus-outline"
src="../../../assets/icons/delete-icon.svg"
alt="Delete bin"
(click)="removeAction(i)"
/>
class="btn btn-link"

><img

class="icons bin-icon cursor-pointer focus-outline"
src="assets/icons/delete-icon.svg"
alt="Delete bin"
/>
</button>
</div>
</div>

Expand All @@ -52,11 +52,11 @@
class="fw-bold col-auto"
id="add-action-button"
[attr.data-testId]="'add-action-plan-line'"
(click)="addNewAction()"
(click)="addNewItem()"
>
<span class="d-flex align-items-center add-text">
<img
src="../../../assets/icons/new-icon.svg"
src="assets/icons/new-icon.svg"
alt="Add action icon"
class="add-cross-button"
id="add-action-icon"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('ActionPlanComponent', () => {
it('should add new action with empty text into array', () => {
component.control = new BehaviorSubject<Action[] | null>([]);
component.keyResultId = addedAction.keyResultId;
component.addNewAction();
component.addNewItem();
expect(component.control.getValue())
.toHaveLength(1);
expect(component.control.getValue()![0])
Expand Down
176 changes: 77 additions & 99 deletions frontend/src/app/components/action-plan/action-plan.component.ts
Original file line number Diff line number Diff line change
@@ -1,138 +1,102 @@
import { Component, ElementRef, Input, QueryList, ViewChildren } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { AfterContentInit, Component, ElementRef, Input, QueryList, ViewChildren } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { Action } from '../../shared/types/model/action';
import { ActionService } from '../../services/action.service';
import { BehaviorSubject } from 'rxjs';
import { trackByFn } from '../../shared/common';
import { DialogService } from '../../services/dialog.service';
import {
AbstractControl,
ControlContainer,
FormArray,
FormArrayName,
FormControl,
FormGroup,
FormGroupDirective
} from '@angular/forms';
import { Observable } from 'rxjs';

export type FormControlsOf<T> = {
[P in keyof T]: AbstractControl<T[P]>;
};

export interface Item {
id: number | undefined;
item: string;
isChecked: boolean;
}

@Component({
selector: 'app-action-plan',
templateUrl: './action-plan.component.html',
styleUrls: ['./action-plan.component.scss'],
standalone: false
standalone: false,
viewProviders: [{ provide: ControlContainer,
useExisting: FormArrayName }]
})
export class ActionPlanComponent {
@Input() control: BehaviorSubject<Action[] | null> = new BehaviorSubject<Action[] | null>([]);

@Input() keyResultId?: number;
export class ActionPlanComponent implements AfterContentInit {
form?: FormGroup;

activeItem = 0;
@Input() onDelete: (index: number) => Observable<any> = () => new Observable();

@ViewChildren('listItem')
listItems!: QueryList<ElementRef>;

constructor(private actionService: ActionService,
public dialogService: DialogService) {
}

handleKeyDown(event: Event, currentIndex: number) {
let newIndex = currentIndex;
if ((event as KeyboardEvent).key === 'ArrowDown') {
if (newIndex + 1 <= this.control.getValue()!.length - 1) {
newIndex += 1;
}
} else if ((event as KeyboardEvent).key === 'ArrowUp') {
if (newIndex - 1 >= 0) {
newIndex -= 1;
}
}
this.changeItemPosition(newIndex, currentIndex);
this.listItems.get(this.activeItem)?.nativeElement.focus();
}

changeItemPosition(newIndex: number, currentIndex: number) {
this.activeItem = newIndex;
const currentActionPlan: Action[] = this.control.getValue()!;
this.updateActionTexts(currentActionPlan);
moveItemInArray(currentActionPlan, currentIndex, newIndex);
currentActionPlan.forEach((action: Action, index: number) => action.priority = index);
this.control.next(currentActionPlan);
}

updateActionTexts(currentActionPlan: Action[]) {
const texts = Array.from(this.listItems)
.map((input: any) => input.nativeElement.value);
currentActionPlan.forEach((action: Action, index: number) => action.action = texts[index]);
}

increaseActiveItemWithTab() {
if (this.activeItem <= this.control.getValue()!.length - 2) {
this.activeItem++;
}
constructor(
private actionService: ActionService,
public dialogService: DialogService, private parentF: FormGroupDirective, private formArrayNameF: FormArrayName
) {
}

decreaseActiveItemWithShiftTab() {
if (this.activeItem > 0) {
this.activeItem--;
}
changeItemPosition(currentIndex: number, newIndex: number) {
const value = this.getFormControlArray().value as Item[];
moveItemInArray(value, currentIndex, newIndex);
this.getFormControlArray()
.setValue(value);
this.focusItem(newIndex);
}

drop(event: CdkDragDrop<Action[] | null>) {
const value: string = (event.container.element.nativeElement.children[event.previousIndex].children[1] as HTMLInputElement).value;
const actions: Action[] = this.control.getValue()!;
if (actions[event.previousIndex].action == '' && value != '') {
actions[event.previousIndex] = {
...actions[event.previousIndex],
action: value
};
this.control.next(actions);
}
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data!, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data!, event.container.data!, event.previousIndex, event.currentIndex
);
}
this.adjustPriorities();
this.activeItem = event.currentIndex;
this.changeItemPosition(event.previousIndex, event.currentIndex);
}

adjustPriorities() {
const actions: Action[] = this.control.getValue()!;
actions.forEach(function(action: Action, index: number) {
action.priority = index;
});
this.control.next(actions);
focusItem(index: number) {
this.listItems.get(index)?.nativeElement.focus();
this.listItems.get(index)?.nativeElement.scrollIntoView();
}

removeAction(index: number) {
const actions: Action[] = this.control.getValue()!;
if (this.activeItem == index && this.activeItem > 0) {
this.activeItem--;
}
if (actions[index].action !== '' || actions[index].id) {
const itemGroup = this.getFormControlArray()
.at(index) as FormGroup;
const itemValue = itemGroup.get('item')?.value;
const itemId = itemGroup.get('id')?.value;

if (itemValue !== '' || itemId) {
this.dialogService
.openConfirmDialog('CONFIRMATION.DELETE.ACTION')
.afterClosed()
.subscribe((result) => {
if (result) {
if (actions[index].id) {
this.actionService.deleteAction(actions[index].id)
.subscribe();
}
actions.splice(index, 1);
this.control.next(actions);
this.adjustPriorities();
this.getFormControlArray()
.removeAt(index);

this.onDelete(itemId)
.subscribe();
}
});
} else {
actions.splice(index, 1);
this.control.next(actions);
this.adjustPriorities();
this.getFormControlArray()
.removeAt(index);
}
}

addNewAction() {
const actions: Action[] = this.control.getValue()!;
actions.push({
action: '',
priority: actions.length,
keyResultId: this.keyResultId
} as Action);
this.control.next(actions);
this.activeItem = actions.length - 1;
addNewItem() {
const newFormGroup = new FormGroup({
item: new FormControl<string>(''),
id: new FormControl<number | undefined>(undefined),
isChecked: new FormControl<boolean>(false)
} as FormControlsOf<Item>);
this.getFormControlArray()
?.push(newFormGroup);
}

/*
Expand All @@ -144,4 +108,18 @@ export class ActionPlanComponent {
}

protected readonly trackByFn = trackByFn;

getFormControlArray() {
return this.form?.get(`${this.formArrayNameF.name}`) as FormArray<FormGroup<FormControlsOf<Item>>>;
}

ngAfterContentInit(): void {
this.form = this.parentF.form;
if (this.getFormControlArray()
?.getRawValue().length === 0) {
this.addNewItem();
this.addNewItem();
this.addNewItem();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
</div>

<ng-template #actionPlanComponent>
<app-action-plan [control]="actionList$" [keyResultId]="keyResult.id"></app-action-plan>
<div formArrayName="arrayList">
<app-action-plan></app-action-plan>
</div>
<button
mat-flat-button
color="primary"
Expand Down
Loading

0 comments on commit b7b627d

Please sign in to comment.