From 446d1b89709128b2ada94271319896129a483176 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 2 Jul 2026 11:45:47 -0300 Subject: [PATCH] feat(modal): add confirm and confirm delete modals with tests - Implemented ConfirmModalComponent and ConfirmDeleteModalComponent for confirmation dialogs. - Added modal service methods to open confirm and confirm delete modals. - Created corresponding HTML and SCSS files for both modal components. - Updated ReutilizablesTestPageComponent to utilize new modals. - Enhanced modal service tests to cover new functionality. - Refactored existing tests to accommodate changes in modal behavior and structure. --- src/app/core/services/modal.service.spec.ts | 65 ++++++- src/app/core/services/modal.service.ts | 51 ++++++ .../reutilizables-test-page.component.html | 148 ++++++++++----- .../reutilizables-test-page.component.spec.ts | 89 ++++++--- .../reutilizables-test-page.component.ts | 169 ++++++++---------- .../confirm-delete-modal.component.html | 12 ++ .../confirm-delete-modal.component.scss | 19 ++ .../confirm-delete-modal.component.spec.ts | 96 ++++++++++ .../confirm-delete-modal.component.ts | 28 +++ .../confirm-modal.component.html | 12 ++ .../confirm-modal.component.scss | 19 ++ .../confirm-modal.component.spec.ts | 95 ++++++++++ .../confirm-modal/confirm-modal.component.ts | 28 +++ .../modal-shell/modal-shell.component.scss | 10 ++ 14 files changed, 677 insertions(+), 164 deletions(-) create mode 100644 src/app/shared/components/confirm-delete-modal/confirm-delete-modal.component.html create mode 100644 src/app/shared/components/confirm-delete-modal/confirm-delete-modal.component.scss create mode 100644 src/app/shared/components/confirm-delete-modal/confirm-delete-modal.component.spec.ts create mode 100644 src/app/shared/components/confirm-delete-modal/confirm-delete-modal.component.ts create mode 100644 src/app/shared/components/confirm-modal/confirm-modal.component.html create mode 100644 src/app/shared/components/confirm-modal/confirm-modal.component.scss create mode 100644 src/app/shared/components/confirm-modal/confirm-modal.component.spec.ts create mode 100644 src/app/shared/components/confirm-modal/confirm-modal.component.ts diff --git a/src/app/core/services/modal.service.spec.ts b/src/app/core/services/modal.service.spec.ts index 82e63a6..98b125c 100644 --- a/src/app/core/services/modal.service.spec.ts +++ b/src/app/core/services/modal.service.spec.ts @@ -5,8 +5,18 @@ import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing'; -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { + afterEach, + beforeAll, + beforeEach, + describe, + expect, + it, + vi +} from 'vitest'; +import { ConfirmDeleteModalComponent } from '../../shared/components/confirm-delete-modal/confirm-delete-modal.component'; +import { ConfirmModalComponent } from '../../shared/components/confirm-modal/confirm-modal.component'; import { MODAL_DATA, ModalRef, @@ -122,6 +132,59 @@ describe('ModalService', () => { expect(activeModal?.config.data).toEqual({ amount: 3 }); expect(activeModal?.ref).toBe(ref); }); + + it('opens the standard confirm modal with default labels', () => { + const ref = service.openConfirm({ + title: 'Confirmar compra', + content: 'Esto confirmara la compra actual.' + }); + + const activeModal = service.activeModal(); + + expect(activeModal?.component).toBe(ConfirmModalComponent); + expect(activeModal?.ref).toBe(ref); + expect(activeModal?.config).toEqual({ + title: 'Confirmar compra', + data: { + content: 'Esto confirmara la compra actual.', + confirmLabel: 'Confirmar', + cancelLabel: 'Cancelar' + }, + size: 'md', + closeOnBackdrop: true, + closeOnEscape: true, + showCloseButton: true + }); + }); + + it('opens the delete confirm modal preserving modal overrides', () => { + service.openConfirmDelete({ + title: 'Eliminar producto', + content: 'Se eliminara el producto.', + confirmLabel: 'Eliminar', + cancelLabel: 'Conservar', + size: 'lg', + closeOnBackdrop: false, + closeOnEscape: false, + showCloseButton: false + }); + + const activeModal = service.activeModal(); + + expect(activeModal?.component).toBe(ConfirmDeleteModalComponent); + expect(activeModal?.config).toEqual({ + title: 'Eliminar producto', + data: { + content: 'Se eliminara el producto.', + confirmLabel: 'Eliminar', + cancelLabel: 'Conservar' + }, + size: 'lg', + closeOnBackdrop: false, + closeOnEscape: false, + showCloseButton: false + }); + }); }); @Component({ diff --git a/src/app/core/services/modal.service.ts b/src/app/core/services/modal.service.ts index 19131e6..256d4ce 100644 --- a/src/app/core/services/modal.service.ts +++ b/src/app/core/services/modal.service.ts @@ -1,5 +1,7 @@ import { InjectionToken, Injectable, Type, signal } from '@angular/core'; import { Observable, Subject } from 'rxjs'; +import { ConfirmDeleteModalComponent } from '../../shared/components/confirm-delete-modal/confirm-delete-modal.component'; +import { ConfirmModalComponent } from '../../shared/components/confirm-modal/confirm-modal.component'; export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'; export type ModalDismissReason = @@ -28,6 +30,19 @@ export interface NormalizedModalConfig showCloseButton: boolean; } +export interface ConfirmModalData { + content: string; + confirmLabel: string; + cancelLabel: string; +} + +export interface ConfirmModalConfig + extends Omit, 'data'> { + content: string; + confirmLabel?: string; + cancelLabel?: string; +} + export interface ActiveModalState { component: Type; config: NormalizedModalConfig; @@ -46,6 +61,11 @@ const DEFAULT_MODAL_CONFIG: Pick< showCloseButton: true }; +const DEFAULT_CONFIRM_MODAL_LABELS = { + confirmLabel: 'Confirmar', + cancelLabel: 'Cancelar' +} satisfies Pick; + export class ModalRef { private readonly afterClosedSubject = new Subject(); private closed = false; @@ -115,6 +135,17 @@ export class ModalService { return ref; } + openConfirm(config: ConfirmModalConfig): ModalRef { + return this.open(ConfirmModalComponent, this.buildConfirmModalConfig(config)); + } + + openConfirmDelete(config: ConfirmModalConfig): ModalRef { + return this.open( + ConfirmDeleteModalComponent, + this.buildConfirmModalConfig(config) + ); + } + private close(ref: ModalRef, result?: TResult): void { if (this.activeModalState()?.ref !== ref) { return; @@ -144,4 +175,24 @@ export class ModalService { ...config }; } + + private buildConfirmModalConfig( + config: ConfirmModalConfig + ): ModalConfig { + const { + content, + confirmLabel = DEFAULT_CONFIRM_MODAL_LABELS.confirmLabel, + cancelLabel = DEFAULT_CONFIRM_MODAL_LABELS.cancelLabel, + ...modalConfig + } = config; + + return { + ...modalConfig, + data: { + content, + confirmLabel, + cancelLabel + } + }; + } } diff --git a/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.html b/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.html index c67cc48..c53e29d 100644 --- a/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.html +++ b/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.html @@ -26,7 +26,9 @@ Secondary Danger - Danger secondary + + Danger secondary + Cancel @@ -46,29 +48,49 @@

Toasts

Trigger Info - Trigger Success - Trigger Danger + + Trigger Success + + + Trigger Danger +

Toasts Persistentes (No se van)

- Info Persistente - Success Persistente - Danger Persistente + + Info Persistente + + + Success Persistente + + + Danger Persistente +

Modal

- Demo del modal global con servicio, host y devolución de resultado. + Demo del modal global con servicio, host y devolucion de resultado.

- Abrir modal simple - Abrir modal bloqueado - Abrir modal ancho + Abrir confirm modal + + Abrir confirm delete + + + Abrir modal bloqueado + + + Abrir modal ancho +