fix: no error feedback on failed save/delete/role-change, editors navigated away before save result was known
Products/Categories saveDraft() and deleteOne(), and Users setRole()/setStatus()/invite(), had no error handler at all - a failed mutation was completely silent. Also found and fixed the same premature-navigation bug as the Phase 1 cart fix: both product and category editor pages called router.navigate() immediately after facade.saveDraft(), before the save had resolved - so even after adding error feedback, the user would already be gone from the page before it could show. saveDraft() now takes an onSuccess callback and only the page navigates on actual success; on failure it stays put and shows a themed error dialog. Added a mutationError signal to all three facades and a themed app-dialog error alert on the products/categories editor + list pages and the users page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ export class AdminUsersFacade {
|
||||
readonly invitations = signal<AdminInvitation[]>([]);
|
||||
readonly loading = signal(false);
|
||||
readonly error = signal(false);
|
||||
readonly mutationError = signal<string | null>(null);
|
||||
readonly sessionsTarget = signal<AdminUser | null>(null);
|
||||
readonly sessions = signal<AdminSession[]>([]);
|
||||
readonly auditTarget = signal<AdminUser | null>(null);
|
||||
@@ -33,16 +34,28 @@ export class AdminUsersFacade {
|
||||
}
|
||||
|
||||
setRole(userId: string, roleId: string): void {
|
||||
this.gateway.setUserRole(userId, roleId).pipe(take(1)).subscribe({ next: () => this.loadAll() });
|
||||
this.mutationError.set(null);
|
||||
this.gateway.setUserRole(userId, roleId).pipe(take(1)).subscribe({
|
||||
next: () => this.loadAll(),
|
||||
error: () => this.mutationError.set('common.errorDescription')
|
||||
});
|
||||
}
|
||||
|
||||
setStatus(userId: string, status: AdminUserStatus): void {
|
||||
this.gateway.setUserStatus(userId, status).pipe(take(1)).subscribe({ next: () => this.loadAll() });
|
||||
this.mutationError.set(null);
|
||||
this.gateway.setUserStatus(userId, status).pipe(take(1)).subscribe({
|
||||
next: () => this.loadAll(),
|
||||
error: () => this.mutationError.set('common.errorDescription')
|
||||
});
|
||||
}
|
||||
|
||||
invite(email: string, roleId: string, scope: AdminUserScope): void {
|
||||
if (!email.trim()) return;
|
||||
this.gateway.inviteUser(email.trim(), roleId, scope).pipe(take(1)).subscribe({ next: () => this.loadAll() });
|
||||
this.mutationError.set(null);
|
||||
this.gateway.inviteUser(email.trim(), roleId, scope).pipe(take(1)).subscribe({
|
||||
next: () => this.loadAll(),
|
||||
error: () => this.mutationError.set('common.errorDescription')
|
||||
});
|
||||
}
|
||||
|
||||
revokeInvitation(id: string): void {
|
||||
|
||||
@@ -128,4 +128,13 @@
|
||||
[destructive]="true"
|
||||
(confirmed)="confirmSuspend()"
|
||||
(cancelled)="pendingSuspendUserId.set(null)" />
|
||||
|
||||
@if (facade.mutationError()) {
|
||||
<app-dialog [open]="true" [titleText]="'common.errorTitle' | translate" size="sm" (closed)="facade.mutationError.set(null)">
|
||||
<p>{{ 'common.errorDescription' | translate }}</p>
|
||||
<div class="app-confirm-dialog__actions">
|
||||
<app-button variant="primary" (click)="facade.mutationError.set(null)">{{ 'common.confirm' | translate }}</app-button>
|
||||
</div>
|
||||
</app-dialog>
|
||||
}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user