Bernd-L/exDateMan

View on GitHub
frontend/src/app/components/edit-inventory/edit-inventory.component.ts

Summary

Maintainability
F
4 days
Test Coverage
import { Component, OnInit } from "@angular/core";
import { Inventory } from "../../models/inventory/inventory";
import { InventoryService } from "../../services/inventory/inventory.service";
import { ActivatedRoute, Router } from "@angular/router";
import { HttpErrorResponse } from "@angular/common/http";
import { MatChipInputEvent } from "@angular/material/chips";
import { MatDialog, MatDialogRef } from "@angular/material/dialog";
import { DeleteConfirmationDialogComponent } from "../delete-confirmation-dialog/delete-confirmation-dialog.component";
import { COMMA, ENTER } from "@angular/cdk/keycodes";
import { User } from "../../models/user/user";
import { UserService } from "../../services/user/user.service";
import {
Validators,
FormControl,
FormGroup,
FormBuilder
} from "@angular/forms";
import { AuthService } from "../../services/auth/auth.service";
 
@Component({
selector: "app-edit-inventory",
templateUrl: "./edit-inventory.component.html",
styleUrls: ["./edit-inventory.component.scss"]
})
export class EditInventoryComponent implements OnInit {
Similar blocks of code found in 3 locations. Consider refactoring.
constructor(
private is: InventoryService,
private as: AuthService,
private route: ActivatedRoute,
public dialog: MatDialog,
private router: Router,
private fb: FormBuilder
) {
this.createForm();
this.formGroup.patchValue({ inventoryName: this.inventory.name });
}
 
// Lading & auth flags
unauthorized = false;
notFound = false;
loading = false;
oof = false;
 
// Operation flags
reallyDelete = false;
userNotFound = false;
 
// Chip flags
visible = true;
selectable = false;
removable = true;
addOnBlur = false;
 
/**
* The keys which should separate the input values
*/
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
 
/**
* The imported inventory
*
TODO found
* // TODO revisit
*/
inventory: Inventory = {} as Inventory;
 
/**
* The owner of the inventory
*/
owner: User;
 
/**
* The users allowed to make changes to the inventory itself
*/
admins: User[] = [];
 
/**
* The users allowed to make changes to the inventories contents
*/
writables: User[] = [];
 
/**
* The users allowed to read data from the inventory
*/
readables: User[] = [];
 
/**
* The intersection flag signals to the isValid method if the lists
* have intersections within.
*
* A user may only either be owner, admin, writable or readable at once.
*
* This flag is true when there is intersection between those roles.
*/
private intersectionFlag = true;
 
/**
* The formGroup of EditInventoryComponent
*/
formGroup: FormGroup;
 
ngOnInit(): void {
this.initIt().then(() => {
console.log("owner");
console.log(this.owner);
 
console.log("admins");
console.log(this.admins);
 
console.log("writables");
console.log(this.writables);
 
console.log("readables");
console.log(this.readables);
});
}
 
/**
* Initializes this component
*/
async initIt(): Promise<void> {
await this.is.ready;
console.log(
"Get inventory from InventoryService: " +
this.route.snapshot.params.inventoryUuid
);
this.inventory = this.is.inventories[
this.route.snapshot.params.inventoryUuid
];
console.log(this.inventory);
 
// Owner
this.owner = await this.as.getUserByUuid(this.inventory.ownerUuid);
 
// Admins
Similar blocks of code found in 2 locations. Consider refactoring.
for (const uuid of this.inventory.adminUuids) {
this.admins.push(await this.as.getUserByUuid(uuid));
}
 
// Writables
Similar blocks of code found in 2 locations. Consider refactoring.
for (const uuid of this.inventory.writableUuids) {
this.writables.push(await this.as.getUserByUuid(uuid));
}
 
// Readables
for (const uuid of this.inventory.readableUuids) {
this.readables.push(await this.as.getUserByUuid(uuid));
}
}
 
/**
* Initiates the formGroup
*/
createForm(): void {
this.formGroup = this.fb.group({
inventoryName: ["", [Validators.required]],
ownerEmail: ["", [Validators.email]],
adminEmail: ["", [Validators.email]],
writableEmail: ["", [Validators.email]],
readableEmail: ["", [Validators.email]]
});
}
 
/**
* Generate an error message for when the email field is invalid
*/
getErrorMessage(): string {
return this.formGroup.controls.inventoryName.hasError("required")
? "You must enter a value"
: "";
}
 
/**
* Handles form submission
*/
Similar blocks of code found in 3 locations. Consider refactoring.
onSubmit(): void {
this.updateInventory().then(() => {
if (!this.oof) {
this.router.navigate(["things"], { relativeTo: this.route });
}
});
}
 
/**
* Uses the InventoryService to update the inventory
*/
async updateInventory(): Promise<void> {
TODO found
// TODO implement
}
 
onDeleteInventory(): void {
this.deleteInventory().then(() => {
if (this.reallyDelete) {
this.router.navigate(["inventories"]);
}
});
}
 
Function `deleteInventory` has a Cognitive Complexity of 11 (exceeds 5 allowed). Consider refactoring.
async deleteInventory(): Promise<void> {
Similar blocks of code found in 3 locations. Consider refactoring.
const dialogRef: MatDialogRef<any> = this.dialog.open(
DeleteConfirmationDialogComponent,
{
data: { inventory: this.inventory }
}
);
 
this.reallyDelete = await dialogRef.afterClosed().toPromise();
 
if (this.reallyDelete) {
try {
const res: unknown = await this.is.deleteInventory(this.inventory);
} catch (error) {
// Catch sending-to-the-server errors
this.oof = true;
if (error instanceof HttpErrorResponse) {
switch (error.status) {
case 401:
// Set flag for html change and timeout above
this.unauthorized = true;
break;
case 404:
this.notFound = true;
}
} else {
console.log("Unknown error in add-stock while creating");
}
}
}
}
 
//
// Chips logic
//
 
// owner
 
/**
* Handles a matChipInputTokenEnd event
*
* @param event The event emitted by the template
*/
onAddOwner(event: MatChipInputEvent): void {
this.addOwner(event).then();
}
 
/**
* Implements the logic required to separate the input-text into chips
*
* @param event The event emitted by the template
*/
async addOwner(event: MatChipInputEvent): Promise<void> {
/**
* The HTML input element the event was emitted from
*/
const input: HTMLInputElement = event.input;
 
/**
* The value of the field when the event was emitted
*/
const value: string = event.value;
 
console.log("The value:");
console.log(value);
 
TODO found
// TODO revisit; maybe remove `if`
if ((value || "").trim()) {
/**
* The user to be appended to a list
*/
let user: User;
try {
// Try to resolve the email address received as input
user = await this.as.resolveUser(value.trim());
this.owner = user;
} catch (error) {
this.userNotFound = true;
}
this.userNotFound = false;
}
 
// Reset the input value
if (input) {
input.value = "";
}
}
 
removeOwner(): void {
this.owner = null;
}
 
// admin
Similar blocks of code found in 3 locations. Consider refactoring.
async addAdmin(event: MatChipInputEvent): Promise<void> {
const input: HTMLInputElement = event.input;
const value: string = event.value;
 
// Add the admin
if ((value || "").trim()) {
let user: User;
try {
user = await this.as.resolveUser(value.trim());
this.inventory.adminUuids.push(user.uuid);
} catch (error) {
this.userNotFound = true;
}
this.userNotFound = false;
}
 
// Reset the input value
if (input) {
input.value = "";
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
removeAdmin(admin: User): void {
const index: number = this.inventory.adminUuids.indexOf(admin.uuid);
 
if (index >= 0) {
this.inventory.adminUuids.splice(index, 1);
}
}
 
// writable
Similar blocks of code found in 3 locations. Consider refactoring.
async addWritable(event: MatChipInputEvent): Promise<void> {
const input: HTMLInputElement = event.input;
const value: string = event.value;
 
// Add our fruit
if ((value || "").trim()) {
let user: User;
try {
user = await this.as.resolveUser(value.trim());
this.inventory.writableUuids.push(user.uuid);
} catch (error) {
this.userNotFound = true;
}
this.userNotFound = false;
}
 
// Reset the input value
if (input) {
input.value = "";
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
removeWritable(writable: User): void {
const index: number = this.inventory.writableUuids.indexOf(writable.uuid);
 
if (index >= 0) {
this.inventory.writableUuids.splice(index, 1);
}
}
 
// readable
Similar blocks of code found in 3 locations. Consider refactoring.
async addReadable(event: MatChipInputEvent): Promise<void> {
const input: HTMLInputElement = event.input;
const value: string = event.value;
 
// Add our fruit
if ((value || "").trim()) {
let user: User;
try {
user = await this.as.resolveUser(value.trim());
this.inventory.readableUuids.push(user.uuid);
} catch (error) {
this.userNotFound = true;
}
this.userNotFound = false;
}
 
// Reset the input value
if (input) {
input.value = "";
}
}
 
removeReadable(readable: User): void {
const index: number = this.inventory.readableUuids.indexOf(readable.uuid);
 
if (index >= 0) {
this.inventory.readableUuids.splice(index, 1);
}
}
 
/**
* A quick-to-compute method returning the state of the forms validity
*
* Checks for the validity of the inventory name, that an owner exists and
* that the input is free of intersection(s).
*
* Used to check if the submit button is to be enabled.
*
* @returns true, if the forms state is valid
*/
isValid(): boolean {
return (
// Check if the inventory name is valid
this.formGroup.valid &&
// Check, if the owner is null
this.owner != null &&
// Check for user intersection
!this.intersectionFlag
);
}
}