fix(admin): products canDeactivate guard, unblock npm, drop dead deps
RC-01 Phase 1 mechanical fixes (verified against current repo state, not blindly reapplied from TODO.md): - admin/products create/edit/duplicate now protected by an unsaved- changes guard (adminProductDirtyGuard), mirroring the existing categories pattern. AdminProductsFacade had zero dirty-tracking before this - added a dirty signal, set true on updateDraft(), cleared on load/create/successful save. Added confirmLeaveUnsaved to the adminProducts i18n section (en/ru/hy) - categories already had its own copy of this key, products didn't. - barry-cache bumped ^0.1.0 -> ^0.9.3 (the pinned range no longer resolved on the registry - ETARGET - which had been silently blocking every npm install/uninstall all cycle). - Removed primeng/primeicons (npm uninstall, now unblocked) - the only consumer (items-carousel) was already deleted in RC PERF-01. - Removed core/search/services/search-history.service.ts, a dead 1-line re-export with zero importers (verified: the real implementation is features/search/services/search-history.service.ts, used by search.facade.ts). Left core/search/models/* alone - those ARE live, imported by catalog components. Verified before touching: HeaderConfig.showProfile toggle is already removed from the header-section editor template (TODO.md was stale on this one) - no change needed, will correct the tracking doc separately. tsc --noEmit clean, npm run build green (bundle unchanged, primeng was already tree-shaken out, this just removes the dead dependency declaration itself). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,7 @@ export class AdminProductsFacade {
|
||||
readonly loading = signal(false);
|
||||
readonly selectedIds = signal<string[]>([]);
|
||||
readonly draft = signal<AdminProduct | null>(null);
|
||||
readonly dirty = signal(false);
|
||||
readonly editorMode = signal<AdminProductEditorMode>('create');
|
||||
|
||||
readonly hasSelection = computed(() => this.selectedIds().length > 0);
|
||||
@@ -283,20 +284,22 @@ export class AdminProductsFacade {
|
||||
startCreate(): void {
|
||||
this.editorMode.set('create');
|
||||
this.draft.set(this.formFactory.createEmpty());
|
||||
this.dirty.set(false);
|
||||
}
|
||||
|
||||
loadForEdit(id: string, mode: AdminProductEditorMode = 'edit'): void {
|
||||
this.editorMode.set(mode);
|
||||
if (mode === 'duplicate') {
|
||||
this.gateway.duplicateProduct(id).pipe(take(1)).subscribe({ next: product => this.draft.set(product) });
|
||||
this.gateway.duplicateProduct(id).pipe(take(1)).subscribe({ next: product => { this.draft.set(product); this.dirty.set(false); } });
|
||||
return;
|
||||
}
|
||||
|
||||
this.gateway.loadProduct(id).pipe(take(1)).subscribe({ next: product => this.draft.set(product ? { ...product } : null) });
|
||||
this.gateway.loadProduct(id).pipe(take(1)).subscribe({ next: product => { this.draft.set(product ? { ...product } : null); this.dirty.set(false); } });
|
||||
}
|
||||
|
||||
updateDraft(patch: Partial<AdminProduct>): void {
|
||||
this.draft.update(current => current ? ({ ...current, ...patch, updatedAt: new Date().toISOString() }) : current);
|
||||
this.dirty.set(true);
|
||||
}
|
||||
|
||||
saveDraft(): void {
|
||||
@@ -307,7 +310,7 @@ export class AdminProductsFacade {
|
||||
? this.gateway.createProduct(draft)
|
||||
: this.gateway.updateProduct(draft);
|
||||
|
||||
request.pipe(take(1)).subscribe({ next: () => this.loadList() });
|
||||
request.pipe(take(1)).subscribe({ next: () => { this.dirty.set(false); this.loadList(); } });
|
||||
}
|
||||
|
||||
deleteOne(id: string): void {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { CanDeactivateFn } from '@angular/router';
|
||||
import { AdminProductsFacade } from '../facade/admin-products.facade';
|
||||
import { AdminProductEditorPageComponent } from '../pages/admin-product-editor-page.component';
|
||||
import { TranslateService } from '../../../../i18n/translate.service';
|
||||
|
||||
export const adminProductDirtyGuard: CanDeactivateFn<AdminProductEditorPageComponent> = () => {
|
||||
const facade = inject(AdminProductsFacade);
|
||||
if (!facade.dirty()) {
|
||||
return true;
|
||||
}
|
||||
const translate = inject(TranslateService);
|
||||
return window.confirm(translate.t('adminProducts.confirmLeaveUnsaved'));
|
||||
};
|
||||
Reference in New Issue
Block a user