Initial
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, OnInit, computed, inject, signal } from '@angular/core';
|
||||
import { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { finalize } from 'rxjs';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { getAuthErrorMessage } from '../../auth/error-message';
|
||||
import { UserList, UserListItem } from '../lists.models';
|
||||
import { ListsService } from '../lists.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-detail',
|
||||
imports: [
|
||||
DatePipe,
|
||||
ReactiveFormsModule,
|
||||
RouterLink,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatCheckboxModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSnackBarModule,
|
||||
],
|
||||
templateUrl: './list-detail.component.html',
|
||||
styleUrl: './list-detail.component.scss',
|
||||
})
|
||||
export class ListDetailComponent implements OnInit {
|
||||
private readonly formBuilder = inject(NonNullableFormBuilder);
|
||||
private readonly listsService = inject(ListsService);
|
||||
private readonly route = inject(ActivatedRoute);
|
||||
private readonly router = inject(Router);
|
||||
private readonly snackBar = inject(MatSnackBar);
|
||||
|
||||
protected readonly list = signal<UserList | null>(null);
|
||||
protected readonly isCreateMode = signal(false);
|
||||
protected readonly loading = signal(true);
|
||||
protected readonly saving = signal(false);
|
||||
protected readonly addingItem = signal(false);
|
||||
protected readonly errorMessage = signal<string | null>(null);
|
||||
protected readonly updatingItemId = signal<string | null>(null);
|
||||
protected readonly canEditItems = computed(() => Boolean(this.list()?.id));
|
||||
|
||||
protected readonly listForm = this.formBuilder.group({
|
||||
name: ['', [Validators.required]],
|
||||
description: [''],
|
||||
});
|
||||
|
||||
protected readonly itemForm = this.formBuilder.group({
|
||||
title: ['', [Validators.required]],
|
||||
required: [true],
|
||||
});
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isCreateMode.set(this.listId() === null);
|
||||
|
||||
if (this.isCreateMode()) {
|
||||
this.loading.set(false);
|
||||
this.listForm.reset({ name: '', description: '' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadList();
|
||||
}
|
||||
|
||||
protected loadList(): void {
|
||||
const listId = this.listId();
|
||||
|
||||
if (!listId) {
|
||||
this.errorMessage.set('Liste wurde nicht gefunden.');
|
||||
this.loading.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading.set(true);
|
||||
this.errorMessage.set(null);
|
||||
|
||||
this.listsService.getList(listId).subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.errorMessage.set(getAuthErrorMessage(error));
|
||||
this.loading.set(false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected saveList(): void {
|
||||
const listId = this.listId();
|
||||
|
||||
if (this.listForm.invalid) {
|
||||
this.listForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
const formValue = this.listForm.getRawValue();
|
||||
const payload = {
|
||||
name: formValue.name.trim(),
|
||||
description: formValue.description.trim() || undefined,
|
||||
};
|
||||
const saveRequest =
|
||||
this.isCreateMode() || !listId
|
||||
? this.listsService.createList(payload)
|
||||
: this.listsService.updateList(listId, payload);
|
||||
|
||||
this.saving.set(true);
|
||||
|
||||
saveRequest.pipe(finalize(() => this.saving.set(false))).subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list);
|
||||
if (this.isCreateMode()) {
|
||||
this.isCreateMode.set(false);
|
||||
void this.router.navigate(['/lists', list.id], { replaceUrl: true });
|
||||
}
|
||||
this.snackBar.open('Liste gespeichert.', 'OK', { duration: 2500 });
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected addItem(): void {
|
||||
const listId = this.listId();
|
||||
|
||||
if (!listId || !this.canEditItems() || this.itemForm.invalid) {
|
||||
this.itemForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
const formValue = this.itemForm.getRawValue();
|
||||
this.addingItem.set(true);
|
||||
|
||||
this.listsService
|
||||
.addItem(listId, {
|
||||
title: formValue.title.trim(),
|
||||
required: formValue.required,
|
||||
})
|
||||
.pipe(finalize(() => this.addingItem.set(false)))
|
||||
.subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list);
|
||||
this.itemForm.reset({ title: '', required: true });
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected toggleItem(item: UserListItem, checked: boolean): void {
|
||||
const listId = this.listId();
|
||||
const currentList = this.list();
|
||||
|
||||
if (!listId || !currentList || this.updatingItemId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updatingItemId.set(item.id);
|
||||
this.list.set({
|
||||
...currentList,
|
||||
items: currentList.items.map((existingItem) =>
|
||||
existingItem.id === item.id ? { ...existingItem, checked } : existingItem,
|
||||
),
|
||||
});
|
||||
|
||||
this.listsService
|
||||
.updateItem(listId, item.id, { checked })
|
||||
.pipe(finalize(() => this.updatingItemId.set(null)))
|
||||
.subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list);
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.list.set(currentList);
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected checkedCount(list: UserList): number {
|
||||
return list.items.filter((item) => item.checked).length;
|
||||
}
|
||||
|
||||
protected async backToLists(): Promise<void> {
|
||||
await this.router.navigateByUrl('/lists');
|
||||
}
|
||||
|
||||
private setList(list: UserList): void {
|
||||
this.list.set(list);
|
||||
this.listForm.reset({
|
||||
name: list.name,
|
||||
description: list.description ?? '',
|
||||
});
|
||||
}
|
||||
|
||||
private listId(): string | null {
|
||||
return this.route.snapshot.paramMap.get('listId');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user