fix: category bulk-delete had no confirmation, single-delete used native dialogs
Bulk-delete called facade.applyBulkDelete() straight from the button with zero confirmation. Single-delete had a confirm gate but via raw window.confirm/alert instead of the themed dialog used elsewhere. Migrated both to app-confirm-dialog (single + new bulk), and the delete-blocked message to a themed app-dialog instead of window.alert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AdminCategoriesFacade } from '../facade/admin-categories.facade';
|
||||
import { AdminCategoriesListComponent } from '../components/admin-categories-list.component';
|
||||
import { LanguageService } from '../../../../services/language.service';
|
||||
import { TranslateService } from '../../../../i18n/translate.service';
|
||||
import { ConfirmDialogComponent } from '../../../../shared/ui/confirm-dialog/confirm-dialog.component';
|
||||
import { DialogComponent } from '../../../../shared/ui/dialog/dialog.component';
|
||||
import { ButtonComponent } from '../../../../shared/ui/button/button.component';
|
||||
import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-categories-list-page',
|
||||
standalone: true,
|
||||
imports: [AdminCategoriesListComponent],
|
||||
imports: [AdminCategoriesListComponent, ConfirmDialogComponent, DialogComponent, ButtonComponent, TranslatePipe],
|
||||
template: `<app-admin-categories-list
|
||||
[treeRows]="facade.visibleTreeRows()"
|
||||
[flatCategories]="facade.filteredCategories()"
|
||||
@@ -37,14 +41,36 @@ import { TranslateService } from '../../../../i18n/translate.service';
|
||||
(selectionChange)="facade.toggleSelection($event.id, $event.checked)"
|
||||
(selectAll)="facade.toggleAll($event)"
|
||||
(bulkVisibility)="facade.applyBulkVisibility($event)"
|
||||
(bulkDelete)="facade.applyBulkDelete()"
|
||||
(bulkDelete)="bulkDelete()"
|
||||
(bulkDuplicate)="facade.applyBulkDuplicate()"
|
||||
(bulkAssignParent)="facade.applyBulkAssignParent($event)"
|
||||
(bulkAssignImage)="facade.applyBulkAssignImage($event)"
|
||||
(bulkExport)="facade.exportSelectedAsCsv()"
|
||||
(viewModeChange)="facade.setViewMode($event)"
|
||||
(densityChange)="facade.setDensity($event)"
|
||||
(columnToggle)="facade.setColumnVisible($event.column, $event.visible)" />`,
|
||||
(columnToggle)="facade.setColumnVisible($event.column, $event.visible)" />
|
||||
<app-confirm-dialog
|
||||
[open]="!!pendingDeleteId()"
|
||||
[titleText]="'adminCategories.deleteTitle' | translate"
|
||||
[message]="'adminCategories.confirmDelete' | translate"
|
||||
[destructive]="true"
|
||||
(confirmed)="confirmDelete()"
|
||||
(cancelled)="pendingDeleteId.set(null)" />
|
||||
<app-confirm-dialog
|
||||
[open]="bulkDeleteConfirmOpen()"
|
||||
[titleText]="'adminCategories.deleteTitle' | translate"
|
||||
[message]="'adminCategories.confirmBulkDelete' | translate"
|
||||
[destructive]="true"
|
||||
(confirmed)="confirmBulkDelete()"
|
||||
(cancelled)="bulkDeleteConfirmOpen.set(false)" />
|
||||
@if (deleteBlockedMessage()) {
|
||||
<app-dialog [open]="true" [titleText]="'adminCategories.deleteBlocked' | translate" size="sm" (closed)="deleteBlockedMessage.set(null)">
|
||||
<p>{{ deleteBlockedMessage() }}</p>
|
||||
<div class="app-confirm-dialog__actions">
|
||||
<app-button variant="primary" (click)="deleteBlockedMessage.set(null)">{{ 'common.confirm' | translate }}</app-button>
|
||||
</div>
|
||||
</app-dialog>
|
||||
}`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AdminCategoriesListPageComponent {
|
||||
@@ -57,6 +83,10 @@ export class AdminCategoriesListPageComponent {
|
||||
readonly isExpandedFn = (id: string) => this.facade.isExpanded(id);
|
||||
readonly canDeleteFn = (id: string) => this.facade.canDelete(id);
|
||||
|
||||
readonly pendingDeleteId = signal<string | null>(null);
|
||||
readonly bulkDeleteConfirmOpen = signal(false);
|
||||
readonly deleteBlockedMessage = signal<string | null>(null);
|
||||
|
||||
constructor() {
|
||||
this.facade.loadList();
|
||||
this.facade.loadDashboardStats();
|
||||
@@ -75,12 +105,27 @@ export class AdminCategoriesListPageComponent {
|
||||
|
||||
deleteOne(id: string): void {
|
||||
if (!this.facade.canDelete(id)) {
|
||||
window.alert(this.translate.t('adminCategories.deleteBlocked'));
|
||||
this.deleteBlockedMessage.set(this.translate.t('adminCategories.deleteBlocked'));
|
||||
return;
|
||||
}
|
||||
if (window.confirm(this.translate.t('adminCategories.confirmDelete'))) {
|
||||
this.pendingDeleteId.set(id);
|
||||
}
|
||||
|
||||
confirmDelete(): void {
|
||||
const id = this.pendingDeleteId();
|
||||
if (id) {
|
||||
this.facade.deleteOne(id);
|
||||
}
|
||||
this.pendingDeleteId.set(null);
|
||||
}
|
||||
|
||||
bulkDelete(): void {
|
||||
this.bulkDeleteConfirmOpen.set(true);
|
||||
}
|
||||
|
||||
confirmBulkDelete(): void {
|
||||
this.facade.applyBulkDelete();
|
||||
this.bulkDeleteConfirmOpen.set(false);
|
||||
}
|
||||
|
||||
private lang(): string {
|
||||
|
||||
@@ -1549,6 +1549,8 @@ export const en: Translations = {
|
||||
saveDraft: 'Save draft',
|
||||
publish: 'Publish',
|
||||
confirmDelete: 'Delete this category? This cannot be undone.',
|
||||
confirmBulkDelete: 'Delete the selected categories? This cannot be undone.',
|
||||
deleteTitle: 'Delete category',
|
||||
confirmLeaveUnsaved: 'You have unsaved changes. Leave without saving?',
|
||||
deleteBlocked: 'This category can\'t be deleted while it has subcategories or assigned products.',
|
||||
emptyTitle: 'No categories yet',
|
||||
|
||||
@@ -1544,6 +1544,8 @@ export const hy: Translations = {
|
||||
saveDraft: 'Պահպանել սևագիրը',
|
||||
publish: 'Հրապարակել',
|
||||
confirmDelete: 'Ջնջե՞լ այս կատեգորիան։ Հնարավոր չէ հետարկել։',
|
||||
confirmBulkDelete: 'Ջնջե՞լ ընտրված կատեգորիաները։ Հնարավոր չէ հետարկել։',
|
||||
deleteTitle: 'Ջնջել կատեգորիան',
|
||||
confirmLeaveUnsaved: 'Դուք ունեք չպահպանված փոփոխություններ։ Դո՞ւրս գալ առանց պահպանելու։',
|
||||
deleteBlocked: 'Այս կատեգորիան հնարավոր չէ ջնջել, քանի դեռ ունի ենթակատեգորիաներ կամ նշանակված ապրանքներ։',
|
||||
emptyTitle: 'Կատեգորիաներ դեռ չկան',
|
||||
|
||||
@@ -1544,6 +1544,8 @@ export const ru: Translations = {
|
||||
saveDraft: 'Сохранить черновик',
|
||||
publish: 'Опубликовать',
|
||||
confirmDelete: 'Удалить эту категорию? Это действие нельзя отменить.',
|
||||
confirmBulkDelete: 'Удалить выбранные категории? Это действие нельзя отменить.',
|
||||
deleteTitle: 'Удалить категорию',
|
||||
confirmLeaveUnsaved: 'У вас есть несохранённые изменения. Выйти без сохранения?',
|
||||
deleteBlocked: 'Эту категорию нельзя удалить, пока у неё есть подкатегории или назначенные товары.',
|
||||
emptyTitle: 'Категорий пока нет',
|
||||
|
||||
@@ -1557,6 +1557,8 @@ export interface Translations {
|
||||
saveDraft: string;
|
||||
publish: string;
|
||||
confirmDelete: string;
|
||||
confirmBulkDelete: string;
|
||||
deleteTitle: string;
|
||||
confirmLeaveUnsaved: string;
|
||||
deleteBlocked: string;
|
||||
emptyTitle: string;
|
||||
|
||||
Reference in New Issue
Block a user