collab
This commit is contained in:
@@ -12,7 +12,9 @@ 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 { AuthService } from '../../auth/auth.service';
|
||||
import { getAuthErrorMessage } from '../../auth/error-message';
|
||||
import { PublicUserSearchResult } from '../../auth/auth.models';
|
||||
import { OnboardingService } from '../../onboarding/onboarding.service';
|
||||
import { ListRealtimeEvent, UserList, UserListItem } from '../lists.models';
|
||||
import { ListsRealtimeService } from '../lists-realtime.service';
|
||||
@@ -39,6 +41,7 @@ import { ListsService } from '../lists.service';
|
||||
export class ListDetailComponent implements OnInit {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly formBuilder = inject(NonNullableFormBuilder);
|
||||
private readonly authService = inject(AuthService);
|
||||
private readonly listsService = inject(ListsService);
|
||||
private readonly listsRealtimeService = inject(ListsRealtimeService);
|
||||
private readonly route = inject(ActivatedRoute);
|
||||
@@ -54,7 +57,28 @@ export class ListDetailComponent implements OnInit {
|
||||
protected readonly addingItem = signal(false);
|
||||
protected readonly errorMessage = signal<string | null>(null);
|
||||
protected readonly updatingItemId = signal<string | null>(null);
|
||||
protected readonly shareSearchTerm = signal('');
|
||||
protected readonly shareSearchResults = signal<PublicUserSearchResult[]>([]);
|
||||
protected readonly searchingUsers = signal(false);
|
||||
protected readonly sharingUserId = signal<string | null>(null);
|
||||
protected readonly removingShareUserId = signal<string | null>(null);
|
||||
protected readonly canEditItems = computed(() => Boolean(this.list()?.id));
|
||||
protected readonly canManageShares = computed(
|
||||
() => this.list()?.accessRole === 'owner' && !this.isCreateMode(),
|
||||
);
|
||||
protected readonly showShareControls = computed(
|
||||
() => this.canManageShares() && this.showEditor(),
|
||||
);
|
||||
protected readonly availableShareSearchResults = computed(() => {
|
||||
const list = this.list();
|
||||
const collaboratorIds = new Set(
|
||||
list?.collaborators.map((collaborator) => collaborator.id) ?? [],
|
||||
);
|
||||
|
||||
return this.shareSearchResults().filter(
|
||||
(user) => user.id !== list?.ownerId && !collaboratorIds.has(user.id),
|
||||
);
|
||||
});
|
||||
protected readonly showEditor = computed(() => this.isCreateMode() || this.editing());
|
||||
|
||||
protected readonly listForm = this.formBuilder.group({
|
||||
@@ -234,6 +258,77 @@ export class ListDetailComponent implements OnInit {
|
||||
return list.items.filter((item) => item.checked).length;
|
||||
}
|
||||
|
||||
protected searchShareUsers(term: string): void {
|
||||
this.shareSearchTerm.set(term);
|
||||
|
||||
if (term.trim().length < 2) {
|
||||
this.shareSearchResults.set([]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchingUsers.set(true);
|
||||
this.authService
|
||||
.searchUsers(term)
|
||||
.pipe(finalize(() => this.searchingUsers.set(false)))
|
||||
.subscribe({
|
||||
next: (users) => this.shareSearchResults.set(users),
|
||||
error: (error: unknown) => {
|
||||
this.shareSearchResults.set([]);
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected shareWithUser(user: PublicUserSearchResult): void {
|
||||
const listId = this.listId();
|
||||
|
||||
if (!listId || this.sharingUserId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sharingUserId.set(user.id);
|
||||
this.listsService
|
||||
.shareList(listId, user.id)
|
||||
.pipe(finalize(() => this.sharingUserId.set(null)))
|
||||
.subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list, !this.showEditor());
|
||||
this.shareSearchTerm.set('');
|
||||
this.shareSearchResults.set([]);
|
||||
this.snackBar.open('Liste geteilt.', 'OK', { duration: 2500 });
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected removeCollaborator(userId: string): void {
|
||||
const listId = this.listId();
|
||||
|
||||
if (!listId || this.removingShareUserId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removingShareUserId.set(userId);
|
||||
this.listsService
|
||||
.removeShare(listId, userId)
|
||||
.pipe(finalize(() => this.removingShareUserId.set(null)))
|
||||
.subscribe({
|
||||
next: (list) => {
|
||||
this.setList(list, !this.showEditor());
|
||||
this.snackBar.open('Freigabe entfernt.', 'OK', { duration: 2500 });
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.snackBar.open(getAuthErrorMessage(error), 'OK', { duration: 5000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected displayUser(user: { name?: string; email: string }): string {
|
||||
return user.name ? `${user.name} (${user.email})` : user.email;
|
||||
}
|
||||
|
||||
protected async backToLists(): Promise<void> {
|
||||
await this.router.navigateByUrl('/lists');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user