diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts index f2ee0ef04a1a37219a85db48a5b894dd0229123b..057b39b29c7de8819c69e745af44cda24e300859 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component.ts @@ -24,6 +24,7 @@ import { contains, enterWith } from '../../support/cypress.util'; import { uploadFile } from '../../support/file-upload'; import { getAdjustedDateGerman } from '../../support/tech.util'; +import Chainable = Cypress.Chainable; export class VorgangBescheidWizardE2EComponent { private readonly bewilligtButton: string = 'button-bewilligt'; @@ -43,10 +44,8 @@ export class VorgangBescheidWizardE2EComponent { private readonly closeButton: string = 'close-bescheid'; private readonly closeDialog: string = 'bescheid-close-dialog'; private readonly bescheidResultBox: string = 'bescheiden-result'; - private readonly bescheidVerwerfenButton: string = - 'bescheiderstellung-abbrechen-entwurf-verwerfen'; - private readonly bescheidSpeichernButton: string = - 'bescheiderstellung-abbrechen-entwurf-speichern'; + private readonly bescheidVerwerfenButton: string = 'bescheiderstellung-abbrechen-entwurf-verwerfen'; + private readonly bescheidSpeichernButton: string = 'bescheiderstellung-abbrechen-entwurf-speichern'; private readonly uploadBescheidFileButton: string = '-single-file-upload-button'; private readonly uploadAttachmentButton: string = 'Anhang_hochladen-file-upload-button'; private readonly uploadAutomaticBescheid: string = 'create-bescheid-document-button'; @@ -60,18 +59,15 @@ export class VorgangBescheidWizardE2EComponent { private readonly fileBescheidValid: string = 'Bescheid_validpdf-file-item'; private readonly fileAnhangValid: string = 'Anhang_validpdf-file-item'; - private readonly fileAutomaticBescheid: string = - 'KFAS_LIVE_KI_10_Haltverbot_befristetpdf-file-item'; + private readonly fileAutomaticBescheid: string = 'KFAS_LIVE_KI_10_Haltverbot_befristetpdf-file-item'; private readonly bescheidDocument: string = 'bescheid-document'; private readonly attachmentDocument: string = 'bescheid-attachments'; - private readonly bescheidUploadSpinner: string = - '[data-test-id="bescheid-document"] ods-spinner-icon'; - private readonly attachmentUploadSpinner: string = - '[data-test-id="bescheid-attachments"] ods-spinner-icon'; - private readonly bescheidSaveSpinner: string = - '[data-test-id="confirm-and-save-button"] ods-spinner-icon'; + private readonly bescheidUploadSpinner: string = '[data-test-id="bescheid-document"] ods-spinner-icon'; + private readonly attachmentUploadSpinner: string = '[data-test-id="bescheid-attachments"] ods-spinner-icon'; + private readonly bescheidSaveSpinner: string = '[data-test-id="confirm-and-save-button"] ods-spinner-icon'; private readonly sendenSpinner: string = '[data-test-id="send-button"] ods-spinner-icon'; + private readonly missingBescheidDocumentMessage: string = 'missing-bescheid-document-error-message'; private locatorRoot: string = 'bescheid-wizard'; @@ -93,6 +89,7 @@ export class VorgangBescheidWizardE2EComponent { public getUeberspringenButton(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.ueberspringenButton); } + public getStatusText(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.statusText); } @@ -112,6 +109,7 @@ export class VorgangBescheidWizardE2EComponent { public getDateInput(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.dateInput); } + public getDateError(): Cypress.Chainable<JQuery<HTMLElement>> { return cy.getTestElement(this.dateError); } @@ -292,4 +290,8 @@ export class VorgangBescheidWizardE2EComponent { public closeDialogIsShown(): void { this.getCloseDialog().should('exist'); } + + public getMissingBescheidDocumentMessage(): Chainable<Element> { + return cy.getTestElement(this.missingBescheidDocumentMessage); + } } diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts index 85aceeb252469b106e0ff87864712d178b2b5797..7292aa333e4233b18c846485f02d316a080b6dc4 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-abbrechen.cy.ts @@ -26,11 +26,7 @@ import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; import { VorgangBescheidWizardE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component'; import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; -import { - VorgangE2E, - VorgangStatusE2E, - vorgangStatusLabelE2E, -} from 'apps/alfa-e2e/src/model/vorgang'; +import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from 'apps/alfa-e2e/src/model/vorgang'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -39,10 +35,7 @@ import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main. import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; import { contains, exist, haveText, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from '../../../support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -64,8 +57,7 @@ describe('Vorgang - Bescheid abbrechen', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); before(() => { initVorgaenge([bescheidVorgang]); @@ -81,7 +73,7 @@ describe('Vorgang - Bescheid abbrechen', () => { dropCollections(); }); - describe.skip('Sollte gefixt sein nach OZG-6185 - Discard changes after click on Verwerfen', () => { + describe('Discard changes after click on Verwerfen', () => { it('should click abgelehnt, enter date, and continue to step 2', () => { vorgangList.getListItem(bescheidVorgang.name).getRoot().click(); waitForSpinnerToDisappear(); @@ -118,14 +110,18 @@ describe('Vorgang - Bescheid abbrechen', () => { }); it('should show status In Bearbeitung', () => { - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); }); }); describe('Keep changes after click on Entwurf speichern', () => { + it('should navigate to vorgang list page', () => { + vorgangPage.getSubnavigation().getBackButton().click(); + waitForSpinnerToDisappear(); + + exist(vorgangList.getRoot()); + }); + it('click Vorgang', () => { vorgangList.getListItem(bescheidVorgang.name).getRoot().click(); waitForSpinnerToDisappear(); @@ -160,10 +156,7 @@ describe('Vorgang - Bescheid abbrechen', () => { }); it('should show status In Bearbeitung', () => { - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); }); it('should keep date and status from current Bescheid in progress', () => { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts index 5fa34c5a3e560c4f2a343c38e071550be99856a2..2f0235885f20f005854b6a72df819534cbd15c6c 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-dokumente-hochladen.cy.ts @@ -33,16 +33,8 @@ import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-lis import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections, getTestElement } from '../../../support/cypress-helper'; -import { contains, exist, haveValue, notContains, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_BIG, - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, - TEST_FILE_JPEG, - TEST_FILE_JPG, - TEST_FILE_PNG, - TEST_FILE_WITH_CONTENT, -} from '../../../support/data.util'; +import { contains, exist, haveText, haveValue, notContains, notExist } from '../../../support/cypress.util'; +import { TEST_FILE_BESCHEID_ANHANG_BIG, TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID, TEST_FILE_JPEG, TEST_FILE_JPG, TEST_FILE_PNG, TEST_FILE_WITH_CONTENT, } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -60,12 +52,11 @@ describe('Bescheid Dokumente hochladen', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); const documentError: string = 'Erlaubte Dateiendungen'; const sizeError: string = 'Anhänge größer'; - const missingBescheidError: string = 'Bitte fügen Sie'; + const missingBescheidError: string = 'Bitte fügen Sie ein Bescheiddokument hinzu.'; const nachrichtHeader: string = 'Neue Nachricht'; const antragstellerName: string = 'An: Max Testermann'; const betreffText: string = 'Ihr Bescheid zum Antrag'; @@ -127,17 +118,11 @@ describe('Bescheid Dokumente hochladen', () => { }); it('should delete files on clicking X button', () => { - bescheidWizard - .getDeleteButtonOfElement( - bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_ANHANG_VALID), - ) - .click(); + bescheidWizard.getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_ANHANG_VALID)).click(); notExist(bescheidWizard.getFileAnhangValidInWizard()); exist(bescheidWizard.getFileBescheidValidInWizard()); - bescheidWizard - .getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_VALID)) - .click(); + bescheidWizard.getDeleteButtonOfElement(bescheidWizard.getElementFromFileName(TEST_FILE_BESCHEID_VALID)).click(); notExist(bescheidWizard.getFileBescheidValidInWizard()); }); @@ -169,7 +154,8 @@ describe('Bescheid Dokumente hochladen', () => { describe('do not continue without attached Bescheid', () => { it('should show error if no Bescheid is attached and step 3 is clicked', () => { bescheidWizard.getWeiterButton().click(); - contains(bescheidWizard.getBescheidDocument(), missingBescheidError); + exist(bescheidWizard.getMissingBescheidDocumentMessage()); + haveText(bescheidWizard.getMissingBescheidDocumentMessage(), missingBescheidError); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts index 30031db94e06f4edfbd0d265a38d3d04bdd78069..0507e30112e6638ca225665737c64002a6ec99f0 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-historie.cy.ts @@ -29,16 +29,10 @@ import { VorgangBescheideE2EComponent } from 'apps/alfa-e2e/src/components/vorga import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; import { VorgangFormularDatenE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular.e2e.component'; import { VorgangSubnavigationE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation'; -import { - BescheidHistorieItemE2EComponent, - VorgangFormularDatenHistorieItemE2EComponent, -} from 'apps/alfa-e2e/src/components/vorgang/vorgang.formular-daten.historie.e2e.component'; +import { BescheidHistorieItemE2EComponent, VorgangFormularDatenHistorieItemE2EComponent, } from 'apps/alfa-e2e/src/components/vorgang/vorgang.formular-daten.historie.e2e.component'; import { HistorieHeadlineE2E } from 'apps/alfa-e2e/src/model/historie'; import { VorgangE2E, VorgangStatusE2E } from 'apps/alfa-e2e/src/model/vorgang'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from 'apps/alfa-e2e/src/support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from 'apps/alfa-e2e/src/support/data.util'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -79,14 +73,11 @@ describe('Bescheid History', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangDatenFormular: VorgangFormularDatenE2EComponent = - vorgangPage.getFormularDatenContainer(); + const vorgangDatenFormular: VorgangFormularDatenE2EComponent = vorgangPage.getFormularDatenContainer(); - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); - const vorgangSubnavigationButtons: VorgangSubnavigationE2EComponent = - vorgangPage.getSubnavigation(); + const vorgangSubnavigationButtons: VorgangSubnavigationE2EComponent = vorgangPage.getSubnavigation(); const bescheide: VorgangBescheideE2EComponent = vorgangPage.getBescheide(); @@ -125,16 +116,14 @@ describe('Bescheid History', () => { waitForSpinnerToDisappear(); vorgangDatenFormular.getHistorieTab().click(); - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); contains(historieItem.getHeadline(), HistorieHeadlineE2E.BESCHEID_ERSTELLT); contains(historieItem.getUser(), userName); }); it('should show detailed info after click on arrow', () => { - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItem.getBescheid(); historieItem.getExpandButton().click(); @@ -160,8 +149,7 @@ describe('Bescheid History', () => { waitForSpinnerToDisappear(); vorgangDatenFormular.getHistorieTab().click(); - const historieItem: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItem: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItem.getBescheid(); historieItem.getExpandButton().click(); @@ -172,7 +160,7 @@ describe('Bescheid History', () => { }); }); - describe.skip('Show history entry after sending Bescheid', () => { + describe('Show history entry after sending Bescheid', () => { it('should show Bescheid entry on history tab after sending message', () => { vorgangSubnavigationButtons.getBackButton().click(); vorgangList.getListItem(bescheidSendenVorgang.name).getRoot().click(); @@ -194,8 +182,7 @@ describe('Bescheid History', () => { notExist(bescheidWizard.getSendenSpinner()); vorgangDatenFormular.getHistorieTab().click(); - const historieItemExpand: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(0); + const historieItemExpand: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(0); const bescheidItem: BescheidHistorieItemE2EComponent = historieItemExpand.getBescheid(); historieItemExpand.getExpandButton().click(); @@ -206,13 +193,11 @@ describe('Bescheid History', () => { }); it('should show history entries for sent Bescheid and message', () => { - const historieItemSent: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(1); + const historieItemSent: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(1); contains(historieItemSent.getHeadline(), HistorieHeadlineE2E.BESCHEID_VERSCHICKT); contains(historieItemSent.getUser(), userName); - const historieItemMessage: VorgangFormularDatenHistorieItemE2EComponent = - vorgangDatenFormular.getHistorieItemByIndex(3); + const historieItemMessage: VorgangFormularDatenHistorieItemE2EComponent = vorgangDatenFormular.getHistorieItemByIndex(3); contains(historieItemMessage.getHeadline(), HistorieHeadlineE2E.SEND_POSTFACH_NACHRICHT); contains(historieItemMessage.getUser(), userName); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts index b75f8c43401365ded80a0f22ae2571b78f9dd6d5..d2e2df9695234a26ff907b7cdde54563df9ca977 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-nur-speichern.cy.ts @@ -26,11 +26,7 @@ import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; import { VorgangBescheidWizardE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-bescheid-wizard.e2e.component'; import { VorgangFormularButtonsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-formular-buttons.e2e.components'; -import { - VorgangE2E, - VorgangStatusE2E, - vorgangStatusLabelE2E, -} from 'apps/alfa-e2e/src/model/vorgang'; +import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from 'apps/alfa-e2e/src/model/vorgang'; import { uploadFile } from 'apps/alfa-e2e/src/support/file-upload'; import { getAdjustedDateGerman } from 'apps/alfa-e2e/src/support/tech.util'; import 'cypress-real-events/support'; @@ -39,10 +35,7 @@ import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main. import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; import { contains, enterWith, exist, haveText, notExist } from '../../../support/cypress.util'; -import { - TEST_FILE_BESCHEID_ANHANG_VALID, - TEST_FILE_BESCHEID_VALID, -} from '../../../support/data.util'; +import { TEST_FILE_BESCHEID_ANHANG_VALID, TEST_FILE_BESCHEID_VALID } from '../../../support/data.util'; import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; @@ -53,7 +46,7 @@ describe('Bescheid speichern', () => { const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); const abgelehntText: string = 'Abgelehnt am'; - const manuellText: string = 'Bescheid muss manuell'; + const manuellText: string = 'Der Bescheid muss manuell versendet werden.'; const vorgangPage: VorgangPage = new VorgangPage(); const bescheidWizard: VorgangBescheidWizardE2EComponent = vorgangPage.getBescheidWizard(); @@ -63,8 +56,7 @@ describe('Bescheid speichern', () => { status: VorgangStatusE2E.IN_BEARBEITUNG, }; - const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = - vorgangPage.getFormularButtons(); + const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); before(() => { initVorgaenge([bescheidVorgang]); @@ -108,10 +100,7 @@ describe('Bescheid speichern', () => { notExist(bescheidWizard.getRoot()); waitForSpinnerToDisappear(); - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.BESCHIEDEN], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.BESCHIEDEN]); }); }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts index 5a6c54ccfacecba703c2c89e30cc7fac777ec114..35a608b28271ff395579092f156f23ad0fc1f445 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts @@ -22,10 +22,10 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CommandOrder, CommandResource } from '@alfa-client/command-shared'; -import { ApiError } from '@alfa-client/tech-shared'; +import { ApiError, createEmptyStateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Action } from '@ngrx/store'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createCommandResource, createSuccessfullyDoneCommandStateResource } from 'libs/command-shared/test/command'; import { createApiError } from 'libs/tech-shared/test/error'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BescheidState, initialState, reducer } from './bescheid.reducer'; @@ -55,7 +55,21 @@ describe('Bescheid Reducer', () => { const state: BescheidState = reducer(initialState, action); - expect(state.bescheidCommand.loading).toBeTruthy(); + expect(state.bescheidCommand).toEqual(createEmptyStateResource(true)); + }); + + it('should replace state resource with loading', () => { + const initialState: BescheidState = { bescheidCommand: createSuccessfullyDoneCommandStateResource() }; + const resource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const action: Action = CommandActions.createCommand({ + resource, + linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT, + command: { ...createCommandResource(), order: CommandOrder.CREATE_BESCHEID }, + }); + + const state: BescheidState = reducer(initialState, action); + + expect(state.bescheidCommand).toEqual(createEmptyStateResource(true)); }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts index 0e804a1d07360070a1b3eaab5411a9c841c0e473..870d54c9df087e333cb44249f93ab9f133562396 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts @@ -21,19 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - CommandProps, - CommandResource, - CreateCommandFailureProps, - CreateCommandProps, -} from '@alfa-client/command-shared'; -import { - ApiError, - StateResource, - createEmptyStateResource, - createErrorStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; +import { CommandProps, CommandResource, CreateCommandFailureProps, CreateCommandProps } from '@alfa-client/command-shared'; +import { ApiError, createEmptyStateResource, createErrorStateResource, createStateResource, StateResource, } from '@alfa-client/tech-shared'; import { HttpErrorResponse } from '@angular/common/http'; import { Action, ActionReducer, createReducer, on } from '@ngrx/store'; import { isCreateBescheidCommand } from '../bescheid.util'; @@ -56,35 +45,22 @@ export const initialState: BescheidState = { const bescheidReducer: ActionReducer<BescheidState, Action> = createReducer( initialState, - on( - CommandActions.createCommand, - (state: BescheidState, props: CreateCommandProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { ...state, bescheidCommand: { ...state.bescheidCommand, loading: true } } - : state; - }, - ), - on( - CommandActions.createCommandSuccess, - (state: BescheidState, props: CommandProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { ...state, bescheidCommand: createStateResource(props.command) } - : state; - }, - ), - on( - CommandActions.createCommandFailure, - (state: BescheidState, props: CreateCommandFailureProps): BescheidState => { - return isCreateBescheidCommand(props.command.order) ? - { - ...state, - bescheidCommand: createErrorStateResource( - <ApiError>(<HttpErrorResponse>props.error).error, - ), - } - : state; - }, - ), + on(CommandActions.createCommand, (state: BescheidState, props: CreateCommandProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? { ...state, bescheidCommand: createEmptyStateResource(true) } : state; + }), + on(CommandActions.createCommandSuccess, (state: BescheidState, props: CommandProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? + { ...state, bescheidCommand: createStateResource(props.command) } + : state; + }), + on(CommandActions.createCommandFailure, (state: BescheidState, props: CreateCommandFailureProps): BescheidState => { + return isCreateBescheidCommand(props.command.order) ? + { + ...state, + bescheidCommand: createErrorStateResource(<ApiError>(<HttpErrorResponse>props.error).error), + } + : state; + }), ); export function reducer(state: BescheidState, action: Action): BescheidState { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab266d7734797b1e6fdf8b845ba8793696893a8e --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid-resource-service.ts @@ -0,0 +1,25 @@ +import { CommandOrder, CommandResourceService, CommandService } from '@alfa-client/command-shared'; +import { ResourceRepository, ResourceServiceConfig } from '@alfa-client/tech-shared'; +import { VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { BescheidLinkRel } from './bescheid.linkrel'; +import { BescheidResource } from './bescheid.model'; + +export class BescheidResourceService extends CommandResourceService<VorgangWithEingangResource, BescheidResource> {} + +export function createBescheidResourceService( + repository: ResourceRepository, + commandService: CommandService, + vorgangService: VorgangService, +): CommandResourceService<VorgangWithEingangResource, BescheidResource> { + console.info('Create Bescheid Resource Service'); + return new CommandResourceService(buildConfig(vorgangService), repository, commandService); +} + +function buildConfig(vorgangService: VorgangService): ResourceServiceConfig<VorgangWithEingangResource> { + return { + resource: vorgangService.getVorgangWithEingang(), + getLinkRel: VorgangWithEingangLinkRel.BESCHEID_DRAFT, + delete: { linkRel: BescheidLinkRel.DELETE, order: CommandOrder.DELETE_BESCHEID }, + edit: { linkRel: BescheidLinkRel.UPDATE, order: CommandOrder.UPDATE_BESCHEID }, + }; +} diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts index b661c130f51fb8e2e2239a68a525b6f25d24c598..6fee5ec006a52da9172c6491cc0bf38c4a0ba0df 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.model.ts @@ -21,8 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { HttpError, ListResource } from '@alfa-client/tech-shared'; -import { Resource } from '@ngxp/rest'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, HttpError, ListResource, StateResource } from '@alfa-client/tech-shared'; +import { Resource, ResourceUri } from '@ngxp/rest'; export enum BescheidStatus { DRAFT = 'DRAFT', @@ -64,3 +66,55 @@ export enum BescheidWizardStep { export interface BescheidWizardDialogResult { reloadVorgang: boolean; } + +export interface BescheidDocument { + upload: UploadFileInProgress; + create: StateResource<CommandResource>; + documentUri?: ResourceUri; + resource?: BinaryFileResource; +} + +export function createEmptyBescheidDocument(): BescheidDocument { + return { + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + }; +} + +export interface BescheidAttachments { + upload: UploadFileInProgress; + uploadStateResource: StateResource<BinaryFileResource>; + items: BinaryFileResource[]; +} + +export function createEmptyBescheidAttachments(): BescheidAttachments { + return { + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + items: [], + }; +} + +export function createEmptyUploadInProgress(): UploadFileInProgress { + return { + loading: false, + fileName: null, + }; +} + +export interface Wizard { + activeStep: BescheidWizardStep; + sendBy: BescheidSendBy; + canBeSend: boolean; + bescheidCreated: boolean; + empfaenger?: string; +} + +export function createInitialWizard(): Wizard { + return { + activeStep: BescheidWizardStep.AntragBescheiden, + sendBy: BescheidSendBy.NACHRICHT, + canBeSend: true, + bescheidCreated: false, + }; +} diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..977ca30abc3c3200416749391b488b397e75731c --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.spec.ts @@ -0,0 +1,975 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BinaryFileListLinkRel, BinaryFileListResource, BinaryFileResource, BinaryFileService, } from '@alfa-client/binary-file-shared'; +import { CommandOrder, CommandResource, CommandResourceService, CommandService, CreateCommandProps, getEffectedResourceUrl, } from '@alfa-client/command-shared'; +import { PostfachService } from '@alfa-client/postfach-shared'; +import { createEmptyStateResource, createErrorStateResource, createLoadingStateResource, createStateResource, EMPTY_STRING, getEmbeddedResources, StateResource, } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { VorgangCommandService, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker'; +import { getUrl, LinkRel, ResourceUri } from '@ngxp/rest'; +import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; +import { createProblemDetail } from 'libs/tech-shared/test/error'; +import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; +import { EMPTY, Observable, of } from 'rxjs'; +import { createBinaryFileListResource, createBinaryFileResource } from '../../../binary-file-shared/test/binary-file'; +import { createCommandErrorStateResource, createCommandResource, createCommandStateResource, createCreateCommandProps, createSuccessfullyDoneCommandStateResource, } from '../../../command-shared/test/command'; +import { ResourceRepository } from '../../../tech-shared/src/lib/resource/resource.repository'; +import { createFile } from '../../../tech-shared/test/file'; +import { singleCold, singleColdCompleted } from '../../../tech-shared/test/marbles'; +import { createBescheid, createBescheidAttachments, createBescheidDocument, createBescheidResource } from '../test/bescheid'; +import { createDocumentResource } from '../test/document'; +import { BescheidFacade } from './+state/bescheid.facade'; +import { BescheidResourceService } from './bescheid-resource-service'; +import { BescheidLinkRel } from './bescheid.linkrel'; +import { Bescheid, BescheidAttachments, BescheidDocument, BescheidResource, BescheidWizardStep, createEmptyBescheidAttachments, createEmptyBescheidDocument, createEmptyUploadInProgress, createInitialWizard, } from './bescheid.model'; +import { BescheidService2 } from './bescheid2.service'; +import { DocumentLinkRel } from './document.linkrel'; +import { DocumentResource } from './document.model'; + +import { expect } from '@jest/globals'; +import * as BescheidUtil from './bescheid.util'; + +describe('BescheidService', () => { + let service: BescheidService2; + + let facade: Mock<BescheidFacade>; + let vorgangService: Mock<VorgangService>; + let resourceRepository: Mock<ResourceRepository>; + let commandService: Mock<CommandService>; + let vorgangCommandService: Mock<VorgangCommandService>; + let binaryFileService: Mock<BinaryFileService>; + let postfachService: Mock<PostfachService>; + let bescheidResourceService: Mock<BescheidResourceService>; + + const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = + createStateResource(vorgangWithEingangResource); + const bescheidResource: BescheidResource = createBescheidResource(); + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + + beforeEach(() => { + facade = mock(BescheidFacade); + resourceRepository = mock(ResourceRepository); + commandService = mock(CommandService); + vorgangCommandService = mock(VorgangCommandService); + vorgangService = mock(VorgangService); + vorgangService.getVorgangWithEingang.mockReturnValue(of(vorgangWithEingangStateResource)); + binaryFileService = mock(BinaryFileService); + postfachService = mock(PostfachService); + bescheidResourceService = mock(CommandResourceService); + + TestBed.configureTestingModule({ + providers: [ + { provide: BescheidFacade, useValue: facade }, + { provide: VorgangService, useValue: vorgangService }, + { provide: ResourceRepository, useValue: resourceRepository }, + { provide: CommandService, useValue: commandService }, + { provide: VorgangCommandService, useValue: vorgangCommandService }, + { provide: BinaryFileService, useValue: binaryFileService }, + { + provide: PostfachService, + useValue: postfachService, + }, + { provide: BescheidResourceService, useValue: bescheidResourceService }, + BescheidService2, + ], + }); + + service = TestBed.inject(BescheidService2); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('init', () => { + it('should init state', () => { + service.setActiveStep(2); + + service.init(); + + expect(service.getWizard()).toBeObservable(singleCold(createInitialWizard())); + expect(service.getActiveStep()).toBeObservable(singleCold(BescheidWizardStep.AntragBescheiden)); + expect(service.getBescheidCreated()).toBeObservable(singleCold(false)); + expect(service.getBescheidDocument()).toBeObservable(singleCold(createEmptyBescheidDocument())); + expect(service.getAttachments()).toBeObservable(singleCold(createEmptyBescheidAttachments())); + }); + }); + + describe('exit', () => { + it('should reload postfach list', () => { + service.exit(); + + expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); + }); + }); + + describe('skipBescheidCreation', () => { + beforeEach(() => { + service.deleteBescheidAndCompleteVorgang = jest.fn().mockReturnValue(of(commandStateResource)); + }); + + it('should complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, null); + + expect(vorgangCommandService.abschliessen).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should NOT complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, bescheidResource); + + expect(vorgangCommandService.abschliessen).not.toHaveBeenCalled(); + }); + + it('should delete bescheid and complete vorgang', () => { + service.skipBescheidCreation(vorgangWithEingangResource, bescheidResource).subscribe(); + + expect(service.deleteBescheidAndCompleteVorgang).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should return command', () => { + const command$: Observable<StateResource<CommandResource>> = service.skipBescheidCreation( + vorgangWithEingangResource, + bescheidResource, + ); + + expect(command$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('deleteBescheidAndCompleteVorgang', () => { + beforeEach(() => { + service.deleteBescheid = jest.fn().mockReturnValue(of(createCommandStateResource)); + vorgangCommandService.abschliessen.mockReturnValue(EMPTY); + }); + + it('should complete vorgang', () => { + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(vorgangCommandService.abschliessen).toHaveBeenCalledWith(vorgangWithEingangResource); + }); + + it('should delete bescheid', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).toHaveBeenCalled(); + }); + + it('should NOT delete bescheid on loading', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createEmptyStateResource(true))); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).not.toHaveBeenCalled(); + }); + + it('should NOT delete bescheid on error', () => { + vorgangCommandService.abschliessen.mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource).subscribe(); + + expect(service.deleteBescheid).not.toHaveBeenCalled(); + }); + + it('should return vorgang abschliessen command', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + vorgangCommandService.abschliessen.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = + service.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('delete bescheid', () => { + it('should create command', () => { + service.deleteBescheid(); + + expect(bescheidResourceService.delete).toHaveBeenCalled(); + }); + + it('should return command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidResourceService.delete.mockReturnValue(of(commandStateResource)); + + const createdCommand$: Observable<StateResource<CommandResource>> = service.deleteBescheid(); + + expect(createdCommand$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('loadFiles', () => { + beforeEach(() => { + service.loadBescheidDocument = jest.fn(); + service.loadAttachments = jest.fn(); + }); + + it('should bescheid document', () => { + service.loadFiles(bescheidResource); + + expect(service.loadBescheidDocument).toHaveBeenCalledWith(bescheidResource); + }); + + it('should load attachments', () => { + service.loadFiles(bescheidResource); + + expect(service.loadAttachments).toHaveBeenCalledWith(bescheidResource); + }); + }); + + describe('create bescheid document', () => { + beforeEach(() => { + service.doCreateBescheidDocument = jest.fn().mockReturnValue(EMPTY); + service.handleCreateBescheidDocumentResponse = jest.fn(); + }); + + it('should emit bescheid document', () => { + service.createBescheidDocument(bescheidResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), create: createEmptyStateResource(true) }), + ); + }); + + it('should do create bescheid document', () => { + service.createBescheidDocument(bescheidResource); + + expect(service.doCreateBescheidDocument).toHaveBeenCalledWith(bescheidResource); + }); + + it('should handle create response on loaded', () => { + service.doCreateBescheidDocument = jest.fn().mockReturnValue(of(commandStateResource)); + + service.createBescheidDocument(bescheidResource); + + expect(service.handleCreateBescheidDocumentResponse).toHaveBeenCalledWith(commandStateResource); + }); + + it('should handle create response on error', () => { + const commandError: StateResource<CommandResource> = createCommandErrorStateResource(); + service.doCreateBescheidDocument = jest.fn().mockReturnValue(of(commandError)); + + service.createBescheidDocument(bescheidResource); + + expect(service.handleCreateBescheidDocumentResponse).toHaveBeenCalledWith(commandError); + }); + }); + + describe('doCreateBescheidDocument', () => { + it('should create command by props', () => { + service.doCreateBescheidDocument(bescheidResource); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ + resource: bescheidResource, + linkRel: BescheidLinkRel.CREATE_DOCUMENT, + command: { + order: CommandOrder.CREATE_BESCHEID_DOCUMENT, + body: null, + }, + snackBarMessage: EMPTY_STRING, + }); + }); + }); + + describe('handleCreateBescheidDocumentResponse', () => { + const commandStateResource: StateResource<CommandResource> = createStateResource( + createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), + ); + + beforeEach(() => { + service.loadBescheidDocumentByUri = jest.fn(); + service.emitBescheidDocumentError = jest.fn(); + }); + + it('should emit error', () => { + const commandErrorStateResource: StateResource<CommandResource> = createCommandErrorStateResource(); + + service.handleCreateBescheidDocumentResponse(commandErrorStateResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), create: commandErrorStateResource } as BescheidDocument), + ); + }); + + it('should emit bescheid document state', () => { + service.handleCreateBescheidDocumentResponse(commandStateResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + documentUri: getEffectedResourceUrl(commandStateResource.resource), + }), + ); + }); + + it('should load document by uri', () => { + service.handleCreateBescheidDocumentResponse(commandStateResource); + + expect(service.loadBescheidDocumentByUri).toHaveBeenCalledWith(getEffectedResourceUrl(commandStateResource.resource)); + }); + }); + + describe('emitBescheidDocumentError', () => { + it('should emit', () => { + const commandError: StateResource<CommandResource> = createCommandErrorStateResource(); + + service.emitBescheidDocumentError(commandError); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + upload: { ...createEmptyUploadInProgress(), loading: false, error: commandError.error }, + }), + ); + }); + }); + + describe('loadBescheidDocument', () => { + beforeEach(() => { + service.loadBescheidDocumentByUri = jest.fn(); + }); + + it('should load by uri', () => { + const bescheidResource: BescheidResource = createBescheidResource([BescheidLinkRel.BESCHEID_DOCUMENT]); + + service.loadBescheidDocument(bescheidResource); + + expect(service.loadBescheidDocumentByUri).toHaveBeenCalledWith(getUrl(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)); + }); + + it('should NOT load by uri', () => { + service.loadBescheidDocument(bescheidResource); + + expect(service.loadBescheidDocumentByUri).not.toHaveBeenCalled(); + }); + }); + + describe('loadBescheidDocumentByUri', () => { + const resourceUri: ResourceUri = faker.internet.url(); + + beforeEach(() => { + resourceRepository.getResource.mockReturnValue(EMPTY); + service.loadBescheidDocumentFile = jest.fn(); + }); + + it('should get resource', () => { + service.loadBescheidDocumentByUri(resourceUri); + + expect(resourceRepository.getResource).toHaveBeenCalledWith(resourceUri); + }); + + it('should load bescheid document file', () => { + const documentResource: DocumentResource = createDocumentResource(); + resourceRepository.getResource.mockReturnValue(of(documentResource)); + + service.loadBescheidDocumentByUri(resourceUri); + + expect(service.loadBescheidDocumentFile).toHaveBeenCalledWith(documentResource); + }); + }); + + describe('load bescheid document file', () => { + const document: DocumentResource = createDocumentResource([DocumentLinkRel.FILE]); + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + beforeEach(() => { + binaryFileService.getFile.mockReturnValue(of(binaryFileStateResource)); + }); + + it('should call binary file service', () => { + service.loadBescheidDocumentFile(document); + + expect(binaryFileService.getFile).toHaveBeenCalledWith(getUrl(document, DocumentLinkRel.FILE)); + }); + + it('should emit bescheid document state', () => { + service.loadBescheidDocumentFile(document); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + resource: binaryFileStateResource.resource, + documentUri: getUrl(document, LinkRel.Self), + }), + ); + }); + }); + + describe('loadAttachments', () => { + const bescheidResourceWithAttachments: BescheidResource = createBescheidResource([BescheidLinkRel.ATTACHMENTS]); + + beforeEach(() => { + binaryFileService.getFiles.mockReturnValue(EMPTY); + }); + + it('should call binary file service', () => { + service.loadAttachments(bescheidResourceWithAttachments); + + expect(binaryFileService.getFiles).toHaveBeenCalledWith(bescheidResourceWithAttachments, BescheidLinkRel.ATTACHMENTS); + }); + + it('should NOT call binary file service', () => { + service.loadAttachments(bescheidResource); + + expect(binaryFileService.getFiles).not.toHaveBeenCalled(); + }); + + it('should emit attachments state', () => { + const binaryFileListStateResource: StateResource<BinaryFileListResource> = + createStateResource(createBinaryFileListResource()); + binaryFileService.getFiles.mockReturnValue(of(binaryFileListStateResource)); + service.loadAttachments(bescheidResourceWithAttachments); + + expect(binaryFileService.getFiles).toHaveBeenCalledWith(bescheidResourceWithAttachments, BescheidLinkRel.ATTACHMENTS); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: getEmbeddedResources(binaryFileListStateResource, BinaryFileListLinkRel.FILE_LIST), + }), + ); + }); + }); + + describe('uploadAttachment', () => { + const attachment: File = createFile(); + + beforeEach(() => { + binaryFileService.uploadFile.mockReturnValue(EMPTY); + service.handleAttachmentUpload = jest.fn(); + }); + + it('should emit upload loading', () => { + service.uploadAttachment(attachment, bescheidResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + upload: { fileName: attachment.name, loading: true }, + uploadStateResource: createLoadingStateResource(), + } as BescheidAttachments), + ); + }); + + it('should call binary file service', () => { + service.uploadAttachment(attachment, bescheidResource); + + expect(binaryFileService.uploadFile).toHaveBeenCalledWith( + bescheidResource, + BescheidLinkRel.UPLOAD_ATTACHMENT, + attachment, + false, + ); + }); + + it('should handle attachment upload', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + binaryFileService.uploadFile.mockReturnValue(of(binaryFileStateResource)); + + service.uploadAttachment(attachment, bescheidResource); + + expect(service.handleAttachmentUpload).toHaveBeenCalledWith(binaryFileStateResource); + }); + }); + + describe('handleAttachmentUpload', () => { + it('should emit state on success', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: [binaryFileStateResource.resource], + uploadStateResource: binaryFileStateResource, + upload: { + ...createEmptyUploadInProgress(), + error: binaryFileStateResource.error, + loading: binaryFileStateResource.loading, + }, + } as BescheidAttachments), + ); + }); + + it('should emit state on error', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createErrorStateResource(createProblemDetail()); + + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...createEmptyBescheidAttachments(), + items: [], + uploadStateResource: binaryFileStateResource, + upload: { + ...createEmptyUploadInProgress(), + error: binaryFileStateResource.error, + loading: binaryFileStateResource.loading, + }, + }), + ); + }); + }); + + describe('deleteAttachment', () => { + it('should delete', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + service.handleAttachmentUpload(binaryFileStateResource); + + service.deleteAttachment(binaryFileStateResource.resource); + + expect(service.getAttachments()).toBeObservable( + singleCold({ ...createEmptyBescheidAttachments(), uploadStateResource: binaryFileStateResource } as BescheidAttachments), + ); + }); + }); + + describe('upload bescheid document', () => { + const documentFile: File = createFile(); + + beforeEach(() => { + binaryFileService.uploadFile.mockReturnValue(EMPTY); + service.handleUploadBescheidDocumentResponse = jest.fn(); + }); + + it('should emit bescheid document state', () => { + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ ...createEmptyBescheidDocument(), upload: { fileName: documentFile.name, loading: true } }), + ); + }); + + it('should call binary file service', () => { + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(binaryFileService.uploadFile).toHaveBeenCalledWith( + bescheidResource, + BescheidLinkRel.UPLOAD_BESCHEID_FILE, + documentFile, + false, + ); + }); + + it('should handle upload response', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + binaryFileService.uploadFile.mockReturnValue(of(binaryFileStateResource)); + + service.uploadBescheidDocument(documentFile, bescheidResource); + + expect(service.handleUploadBescheidDocumentResponse).toHaveBeenCalledWith(bescheidResource, binaryFileStateResource); + }); + }); + + describe('handleUploadBescheidDocumentResponse', () => { + beforeEach(() => { + service.emitBescheidDocumentError = jest.fn(); + service.createBescheidDocumentFromFile = jest.fn(); + }); + + it('should emit error', () => { + const errorStateResource: StateResource<BinaryFileResource> = createErrorStateResource(createProblemDetail()); + + service.handleUploadBescheidDocumentResponse(bescheidResource, errorStateResource); + + expect(service.emitBescheidDocumentError).toHaveBeenCalledWith(errorStateResource); + }); + + it('should create bescheid document from file', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource()); + + service.handleUploadBescheidDocumentResponse(bescheidResource, binaryFileStateResource); + + expect(service.createBescheidDocumentFromFile).toHaveBeenCalledWith(bescheidResource, binaryFileStateResource.resource); + }); + }); + + describe('create bescheid document from file', () => { + const bescheid: BescheidResource = createBescheidResource(); + const binaryFile: BinaryFileResource = createBinaryFileResource(); + + const createCommandProps: CreateCommandProps = createCreateCommandProps(); + let buildCreateBescheidDocumentFromFilePropsSpy; + + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + + beforeEach(() => { + buildCreateBescheidDocumentFromFilePropsSpy = jest + .spyOn(BescheidUtil, 'buildCreateBescheidDocumentFromFileProps') + .mockReturnValue(createCommandProps); + commandService.createCommandByProps.mockReturnValue(of(commandStateResource)); + }); + + it('should call command sevice', () => { + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps); + }); + + it('should build create command document from file props', () => { + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(buildCreateBescheidDocumentFromFilePropsSpy).toHaveBeenCalledWith(bescheid, binaryFile); + }); + + it('should call handle create bescheid document from file response', () => { + service.handleCreateBescheidDocumentFromFileResponse = jest.fn(); + + service.createBescheidDocumentFromFile(bescheid, binaryFile); + + expect(service.handleCreateBescheidDocumentFromFileResponse).toHaveBeenCalledWith(commandStateResource, binaryFile); + }); + }); + + describe('handleCreateBescheidDocumentFromFileResponse', () => { + const commandStateResource: StateResource<CommandResource> = createStateResource( + createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), + ); + + beforeEach(() => { + service.emitBescheidDocumentError = jest.fn(); + }); + + it('should emit error', () => { + const errorStateResource: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + + service.handleCreateBescheidDocumentFromFileResponse(errorStateResource, createBinaryFileResource()); + + expect(service.emitBescheidDocumentError).toHaveBeenCalledWith(errorStateResource); + }); + + it('should NOT emit error', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + service.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFileResource); + + expect(service.emitBescheidDocumentError).not.toHaveBeenCalled(); + }); + + it('should emit bescheid document state', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + service.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFileResource); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...createEmptyBescheidDocument(), + documentUri: getEffectedResourceUrl(commandStateResource.resource), + upload: createEmptyUploadInProgress(), + resource: binaryFileResource, + }), + ); + }); + + it('should NOT emit bescheid document state', () => { + const errorStateResource: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + + service.handleCreateBescheidDocumentFromFileResponse(errorStateResource, createBinaryFileResource()); + + expect(service.getBescheidDocument()).toBeObservable(singleCold(createEmptyBescheidDocument())); + }); + }); + + describe('createBescheid', () => { + const vorgangWithEingang: VorgangWithEingangResource = createVorgangWithEingangResource(); + const command: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + const commandStateResource: StateResource<CommandResource> = createStateResource(command); + + beforeEach(() => { + service.updateBescheidDraft = jest.fn(); + }); + + beforeEach(() => { + facade.getBescheidCommand.mockReturnValue(of(commandStateResource)); + (service as any).bescheidResourceService.loadByResourceUri = jest.fn(); + }); + + it('should call facade', () => { + service.createBescheid(vorgangWithEingang).subscribe(); + + expect(facade.createBescheidDraft).toHaveBeenCalledWith(vorgangWithEingang, { + order: CommandOrder.CREATE_BESCHEID, + body: null, + }); + }); + + it('should update bescheid draft', () => { + service.createBescheid(vorgangWithEingang).subscribe(); + + expect(service.updateBescheidDraft).toHaveBeenCalledWith(commandStateResource.resource); + }); + }); + + describe('updateBescheidDraft', () => { + const command: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + + beforeEach(() => { + (service as any).bescheidResourceService.loadByResourceUri = jest.fn(); + }); + + it('should load resource by uri', () => { + service.updateBescheidDraft(command); + + expect((service as any).bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith( + getUrl(command, CommandLinkRel.EFFECTED_RESOURCE), + ); + }); + + it('should emit bescheid created', () => { + service.updateBescheidDraft({ ...command, order: CommandOrder.CREATE_BESCHEID }); + + expect(service.getBescheidCreated()).toBeObservable(singleCold(true)); + }); + }); + + describe('updateBescheid', () => { + const bescheid: Bescheid = createBescheid(); + const commandResource: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + const commandStateResource: StateResource<CommandResource> = createStateResource(commandResource); + + beforeEach(() => { + service.doUpdateBescheid = jest.fn().mockReturnValue(EMPTY); + service.updateBescheidDraft = jest.fn().mockReturnValue(EMPTY); + }); + + it('should do update bescheid', () => { + service.updateBescheid(bescheidResource, bescheid); + + expect(service.doUpdateBescheid).toHaveBeenCalledWith(bescheidResource, bescheid); + }); + + it('should update bescheid draft', () => { + service.doUpdateBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + service.updateBescheid(bescheidResource, bescheid).subscribe(); + + expect(service.updateBescheidDraft).toHaveBeenCalledWith(commandResource); + }); + }); + + describe('do update bescheid', () => { + const bescheid: Bescheid = createBescheid(); + const bescheidResource: BescheidResource = createBescheidResource(); + + const createCommandProps: CreateCommandProps = createCreateCommandProps(); + let buildUpdateBescheidCommandPropsSpy: jest.SpyInstance; + + beforeEach(() => { + buildUpdateBescheidCommandPropsSpy = jest + .spyOn(BescheidUtil, 'buildUpdateBescheidCommandProps') + .mockReturnValue(createCommandProps); + commandService.createCommandByProps.mockClear(); + commandService.createCommandByProps.mockReturnValue(of(createCommandStateResource())); + }); + + it('should build update bescheid command props', () => { + service.doUpdateBescheid(bescheidResource, bescheid); + + expect(buildUpdateBescheidCommandPropsSpy).toHaveBeenCalledWith(bescheidResource, bescheid); + }); + + it('should call command service', () => { + service.doUpdateBescheid(bescheidResource, bescheid).subscribe(); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps); + }); + }); + + describe('sendBescheidManually', () => { + beforeEach(() => { + service.sendBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + it('should send bescheid', () => { + service.sendBescheidManually().subscribe(); + + expect(service.sendBescheid).toHaveBeenCalledWith(BescheidLinkRel.BESCHEIDEN); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service.sendBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheidManually(); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('sendBescheid', () => { + beforeEach(() => { + service.getBescheidDraft = jest.fn().mockReturnValue(of(createStateResource(bescheidResource))); + commandService.createCommandByProps.mockReturnValue(EMPTY); + }); + + it('should get bescheid draft', () => { + service.sendBescheidManually().subscribe(); + + expect(service.getBescheidDraft).toHaveBeenCalled(); + }); + + it('should create command', () => { + service.sendBescheid(BescheidLinkRel.BESCHEIDEN).subscribe(); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ + resource: bescheidResource, + linkRel: BescheidLinkRel.BESCHEIDEN, + command: { + order: CommandOrder.SEND_BESCHEID, + body: null, + }, + snackBarMessage: EMPTY_STRING, + } as CreateCommandProps); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + commandService.createCommandByProps = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheid( + BescheidLinkRel.BESCHEIDEN, + ); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('sendBescheidMessage', () => { + beforeEach(() => { + service.getBescheidDraft = jest.fn().mockReturnValue(createStateResource(bescheidResource)); + service.sendBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + it('should send bescheid', () => { + service.sendBescheidMessage().subscribe(); + + expect(service.sendBescheid).toHaveBeenCalledWith(BescheidLinkRel.BESCHEIDEN_UND_SENDEN); + }); + + it('should return send bescheid command', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service.sendBescheid = jest.fn().mockReturnValue(of(commandStateResource)); + + const sendCommandStateResource$: Observable<StateResource<CommandResource>> = service.sendBescheidMessage(); + + expect(sendCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('setActiveStep', () => { + it('should emit changed active step', () => { + service.setActiveStep(BescheidWizardStep.DokumenteHochladen); + + expect(service.getActiveStep()).toBeObservable(singleCold(BescheidWizardStep.DokumenteHochladen)); + }); + }); + + describe('getBescheidDraft', () => { + const bescheidDraft: BescheidResource = createBescheidResource(); + const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraft); + + it('should call resource service', () => { + bescheidResourceService.get = jest.fn(); + + service.getBescheidDraft(); + + expect(bescheidResourceService.get).toHaveBeenCalled(); + }); + + it('should return value', () => { + bescheidResourceService.get = jest.fn().mockReturnValue(singleCold(bescheidDraftStateResource)); + + const bescheidStateResource$: Observable<StateResource<BescheidResource>> = service.getBescheidDraft(); + + expect(bescheidStateResource$).toBeObservable(singleCold(bescheidDraftStateResource)); + }); + }); + + describe('setNachrichtEmpfaenger', () => { + it('should change wizard state', () => { + const empfaenger: string = faker.person.fullName(); + + service.setNachrichtEmpfaenger(empfaenger); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), empfaenger })); + }); + }); + + describe('lockBescheidSending', () => { + it('should change wizard state', () => { + service.lockBescheidSending(); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), canBeSend: false })); + }); + }); + + describe('unlockBescheidSending', () => { + it('should change wizard state', () => { + service.unlockBescheidSending(); + + expect(service.getWizard()).toBeObservable(singleCold({ ...createInitialWizard(), canBeSend: true })); + }); + }); + + describe('finishAddingAttachments', () => { + it('should update state', () => { + const attachments: BescheidAttachments = createBescheidAttachments(); + service._attachments$.next(attachments); + + service.finishAddingAttachments(); + + expect(service.getAttachments()).toBeObservable( + singleCold({ + ...attachments, + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + } as BescheidAttachments), + ); + }); + }); + + describe('finishAddingBescheidDocument', () => { + it('should update state', () => { + const bescheidDocument: BescheidDocument = createBescheidDocument(); + service._bescheidDocument$.next(bescheidDocument); + + service.finishAddingBescheidDocument(); + + expect(service.getBescheidDocument()).toBeObservable( + singleCold({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createEmptyUploadInProgress(), + } as BescheidDocument), + ); + }); + }); +}); diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c5d8191390993f76b6456a8577d895b57dd6f55 --- /dev/null +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid2.service.ts @@ -0,0 +1,387 @@ +import { + Bescheid, + BescheidAttachments, + BescheidDocument, + BescheidLinkRel, + BescheidResource, + BescheidSendBy, + BescheidWizardStep, + buildCreateBescheidCommand, + buildCreateBescheidDocumentCommandProps, + buildCreateBescheidDocumentFromFileProps, + buildSendBescheidCommandProps, + buildUpdateBescheidCommandProps, + createEmptyBescheidAttachments, + createEmptyBescheidDocument, + createEmptyUploadInProgress, + createInitialWizard, + DocumentResource, + Wizard, +} from '@alfa-client/bescheid-shared'; +import { + BinaryFileListLinkRel, + BinaryFileListResource, + BinaryFileResource, + BinaryFileService, +} from '@alfa-client/binary-file-shared'; +import { + CommandOrder, + CommandResource, + CommandService, + getEffectedResourceUrl, + notHasCommandError, + tapOnCommandSuccessfullyDone, +} from '@alfa-client/command-shared'; +import { PostfachService } from '@alfa-client/postfach-shared'; +import { + createEmptyStateResource, + createLoadingStateResource, + filterIsLoadedOrHasError, + getEmbeddedResources, + hasStateResourceError, + isLoaded, + ResourceRepository, + StateResource, +} from '@alfa-client/tech-shared'; +import { VorgangCommandService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { inject, Injectable } from '@angular/core'; +import { getUrl, hasLink, LinkRel, Resource, ResourceUri } from '@ngxp/rest'; +import { isNil } from 'lodash-es'; +import { BehaviorSubject, filter, first, map, Observable, switchMap } from 'rxjs'; +import { BescheidFacade } from './+state/bescheid.facade'; +import { BescheidResourceService } from './bescheid-resource-service'; +import { DocumentLinkRel } from './document.linkrel'; + +@Injectable() +export class BescheidService2 { + private readonly bescheidFacade = inject(BescheidFacade); + private readonly commandService = inject(CommandService); + private readonly vorgangCommandService = inject(VorgangCommandService); + private readonly binaryFileService = inject(BinaryFileService); + private readonly resourceRepository = inject(ResourceRepository); + private readonly postfachService = inject(PostfachService); + private readonly bescheidResourceService = inject(BescheidResourceService); + + readonly _bescheidDocument$: BehaviorSubject<BescheidDocument> = new BehaviorSubject(createEmptyBescheidDocument()); + readonly _attachments$: BehaviorSubject<BescheidAttachments> = new BehaviorSubject(createEmptyBescheidAttachments()); + readonly _wizard$: BehaviorSubject<Wizard> = new BehaviorSubject(createInitialWizard()); + + public init(): void { + this._wizard$.next(createInitialWizard()); + this._bescheidDocument$.next(createEmptyBescheidDocument()); + this._attachments$.next(createEmptyBescheidAttachments()); + } + + public exit(): void { + this.postfachService.setPostfachMailOnReload(); + } + + public skipBescheidCreation( + vorgangWithEingangResource: VorgangWithEingangResource, + bescheidResource: BescheidResource, + ): Observable<StateResource<CommandResource>> { + if (isNil(bescheidResource)) { + return this.vorgangCommandService.abschliessen(vorgangWithEingangResource); + } + return this.deleteBescheidAndCompleteVorgang(vorgangWithEingangResource); + } + + deleteBescheidAndCompleteVorgang( + vorgangWithEingangResource: VorgangWithEingangResource, + ): Observable<StateResource<CommandResource>> { + return this.vorgangCommandService + .abschliessen(vorgangWithEingangResource) + .pipe(tapOnCommandSuccessfullyDone(() => this.deleteBescheid())); + } + + public deleteBescheid(): Observable<StateResource<CommandResource>> { + return this.bescheidResourceService.delete(); + } + + public loadFiles(bescheidResource: BescheidResource): void { + this.loadBescheidDocument(bescheidResource); + this.loadAttachments(bescheidResource); + } + + public createBescheidDocument(bescheidResource: BescheidResource): void { + this._bescheidDocument$.next({ ...createEmptyBescheidDocument(), create: createEmptyStateResource(true) }); + this.doCreateBescheidDocument(bescheidResource) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((commandStateResource: StateResource<CommandResource>) => + this.handleCreateBescheidDocumentResponse(commandStateResource), + ); + } + + doCreateBescheidDocument(bescheidResource: BescheidResource): Observable<StateResource<CommandResource>> { + return this.commandService.createCommandByProps(buildCreateBescheidDocumentCommandProps(bescheidResource)); + } + + handleCreateBescheidDocumentResponse(commandStateResource: StateResource<CommandResource>): void { + if (notHasCommandError(commandStateResource.resource)) { + const documentUri: ResourceUri = getEffectedResourceUrl(commandStateResource.resource); + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, documentUri }); + this.loadBescheidDocumentByUri(documentUri); + } else { + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, create: commandStateResource }); + } + } + + emitBescheidDocumentError(stateResource: StateResource<Resource>): void { + const value: BescheidDocument = this._bescheidDocument$.value; + this._bescheidDocument$.next({ + ...value, + upload: { ...value.upload, loading: false, error: stateResource.error }, + }); + } + + loadBescheidDocument(bescheidResource: BescheidResource): void { + if (hasLink(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)) { + this.loadBescheidDocumentByUri(getUrl(bescheidResource, BescheidLinkRel.BESCHEID_DOCUMENT)); + } + } + + public loadBescheidDocumentByUri(resourceUri: ResourceUri): void { + this.resourceRepository + .getResource(resourceUri) + .pipe(first()) + .subscribe((document: DocumentResource) => this.loadBescheidDocumentFile(document)); + } + + loadBescheidDocumentFile(document: DocumentResource): void { + this.binaryFileService + .getFile(getUrl(document, DocumentLinkRel.FILE)) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFile: StateResource<BinaryFileResource>) => { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + resource: binaryFile.resource, + documentUri: getUrl(document, LinkRel.Self), + }); + }); + } + + loadAttachments(bescheidResource: BescheidResource): void { + if (hasLink(bescheidResource, BescheidLinkRel.ATTACHMENTS)) { + this.binaryFileService + .getFiles(bescheidResource, BescheidLinkRel.ATTACHMENTS) + .pipe( + filterIsLoadedOrHasError(), + first(), + map((stateResource: StateResource<BinaryFileListResource>) => + getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST), + ), + ) + .subscribe((files: BinaryFileResource[]) => this._attachments$.next({ ...this._attachments$.value, items: files })); + } + } + + public uploadAttachment(attachment: File, bescheidResource: BescheidResource): void { + this._attachments$.next({ + ...this._attachments$.value, + upload: { fileName: attachment.name, loading: true }, + uploadStateResource: createLoadingStateResource(), + }); + this.binaryFileService + .uploadFile(bescheidResource, BescheidLinkRel.UPLOAD_ATTACHMENT, attachment, false) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFileStateResource: StateResource<BinaryFileResource>) => + this.handleAttachmentUpload(binaryFileStateResource), + ); + } + + handleAttachmentUpload(binaryFileStateResource: StateResource<BinaryFileResource>) { + const value: BescheidAttachments = this._attachments$.value; + if (hasStateResourceError(binaryFileStateResource)) { + this._attachments$.next({ + ...value, + uploadStateResource: binaryFileStateResource, + upload: { ...value.upload, error: binaryFileStateResource.error, loading: binaryFileStateResource.loading }, + }); + } else { + this._attachments$.next({ + ...value, + uploadStateResource: binaryFileStateResource, + items: [...value.items, binaryFileStateResource.resource], + upload: { ...value.upload, error: binaryFileStateResource.error, loading: binaryFileStateResource.loading }, + }); + } + } + + public deleteAttachment(attachment: BinaryFileResource): void { + const value: BescheidAttachments = this._attachments$.value; + this._attachments$.next({ + ...value, + items: value.items.filter((each: BinaryFileResource) => getUrl(each) !== getUrl(attachment)), + }); + } + + public uploadBescheidDocument(document: File, bescheid: BescheidResource): void { + this._bescheidDocument$.next({ ...this._bescheidDocument$.value, upload: { fileName: document.name, loading: true } }); + this.binaryFileService + .uploadFile(bescheid, BescheidLinkRel.UPLOAD_BESCHEID_FILE, document, false) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((binaryFileStateResource: StateResource<BinaryFileResource>) => + this.handleUploadBescheidDocumentResponse(bescheid, binaryFileStateResource), + ); + } + + handleUploadBescheidDocumentResponse( + bescheid: BescheidResource, + binaryFileStateResource: StateResource<BinaryFileResource>, + ): void { + if (hasStateResourceError(binaryFileStateResource)) { + this.emitBescheidDocumentError(binaryFileStateResource); + } else { + this.createBescheidDocumentFromFile(bescheid, binaryFileStateResource.resource); + } + } + + createBescheidDocumentFromFile(bescheid: BescheidResource, binaryFile: BinaryFileResource): void { + this.commandService + .createCommandByProps(buildCreateBescheidDocumentFromFileProps(bescheid, binaryFile)) + .pipe(filterIsLoadedOrHasError(), first()) + .subscribe((commandStateResource: StateResource<CommandResource>) => + this.handleCreateBescheidDocumentFromFileResponse(commandStateResource, binaryFile), + ); + } + + handleCreateBescheidDocumentFromFileResponse( + commandStateResource: StateResource<CommandResource>, + binaryFile: BinaryFileResource, + ): void { + if (hasStateResourceError(commandStateResource)) { + this.emitBescheidDocumentError(commandStateResource); + } else { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + documentUri: getEffectedResourceUrl(commandStateResource.resource), + upload: createEmptyUploadInProgress(), + resource: binaryFile, + }); + } + } + + public createBescheid( + vorgangWithEingang: VorgangWithEingangResource, + bescheid?: Bescheid, + ): Observable<StateResource<CommandResource>> { + this.bescheidFacade.createBescheidDraft(vorgangWithEingang, buildCreateBescheidCommand(bescheid)); + return this.bescheidFacade + .getBescheidCommand() + .pipe( + tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => + this.updateBescheidDraft(commandStateResource.resource), + ), + ); + } + + updateBescheidDraft(command: CommandResource): void { + this.bescheidResourceService.loadByResourceUri(getEffectedResourceUrl(command)); + if (command.order === CommandOrder.CREATE_BESCHEID) { + this._wizard$.next({ ...this._wizard$.value, bescheidCreated: true }); + } + } + + public updateBescheid( + bescheidResource: BescheidResource, + updatedBescheid: Bescheid, + ): Observable<StateResource<CommandResource>> { + return this.doUpdateBescheid(bescheidResource, updatedBescheid).pipe( + tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => { + this.updateBescheidDraft(commandStateResource.resource); + }), + ); + } + + doUpdateBescheid(bescheidResource: BescheidResource, bescheid: Bescheid): Observable<StateResource<CommandResource>> { + return this.commandService.createCommandByProps(buildUpdateBescheidCommandProps(bescheidResource, bescheid)); + } + + public sendBescheidManually(): Observable<StateResource<CommandResource>> { + return this.sendBescheid(BescheidLinkRel.BESCHEIDEN); + } + + public sendBescheidMessage(): Observable<StateResource<CommandResource>> { + return this.sendBescheid(BescheidLinkRel.BESCHEIDEN_UND_SENDEN); + } + + sendBescheid(linkRel: BescheidLinkRel): Observable<StateResource<CommandResource>> { + return this.getBescheidDraft().pipe( + filter(isLoaded), + map((stateResource: StateResource<BescheidResource>) => stateResource.resource), + switchMap((bescheidResource: BescheidResource) => + this.commandService.createCommandByProps(buildSendBescheidCommandProps(bescheidResource, linkRel)), + ), + ); + } + + public getBescheidDraft(): Observable<StateResource<BescheidResource>> { + return this.bescheidResourceService.get(); + } + + public getAttachments(): Observable<BescheidAttachments> { + return this._attachments$.asObservable(); + } + + public getBescheidDocument(): Observable<BescheidDocument> { + return this._bescheidDocument$.asObservable(); + } + + public deleteBescheidDocument(): void { + this._bescheidDocument$.next(createEmptyBescheidDocument()); + } + + public getActiveStep(): Observable<BescheidWizardStep> { + return this._wizard$.asObservable().pipe(map((wizard: Wizard) => wizard.activeStep)); + } + + public setActiveStep(step: BescheidWizardStep): void { + this._wizard$.next({ ...this._wizard$.value, activeStep: step }); + } + + public getBescheidCreated(): Observable<boolean> { + return this._wizard$.asObservable().pipe(map((wizard: Wizard) => wizard.bescheidCreated)); + } + + public selectBescheidResource(): Observable<StateResource<BescheidResource>> { + return this.bescheidResourceService.selectResource(); + } + + public getWizard(): Observable<Wizard> { + return this._wizard$.asObservable(); + } + + public setSendBy(sendBy: BescheidSendBy): void { + this._wizard$.next({ ...this._wizard$.value, sendBy: sendBy }); + } + + public setNachrichtEmpfaenger(empfaenger: string): void { + this._wizard$.next({ ...this._wizard$.value, empfaenger: empfaenger }); + } + + public lockBescheidSending(): void { + this._wizard$.next({ ...this._wizard$.value, canBeSend: false }); + } + + public unlockBescheidSending(): void { + this._wizard$.next({ ...this._wizard$.value, canBeSend: true }); + } + + public finishAddingAttachments(): void { + this._attachments$.next({ + ...this._attachments$.value, + upload: createEmptyUploadInProgress(), + uploadStateResource: createEmptyStateResource(), + }); + } + + public finishAddingBescheidDocument(): void { + this._bescheidDocument$.next({ + ...this._bescheidDocument$.value, + upload: createEmptyUploadInProgress(), + create: createEmptyStateResource(), + }); + } +} diff --git a/alfa-client/libs/bescheid-shared/src/test/bescheid.ts b/alfa-client/libs/bescheid-shared/src/test/bescheid.ts index d9140137173742b27c72af02134df8c57475f2e1..b8f118a56164cfd5fd06c7b6e2db02c9bac57471 100644 --- a/alfa-client/libs/bescheid-shared/src/test/bescheid.ts +++ b/alfa-client/libs/bescheid-shared/src/test/bescheid.ts @@ -25,16 +25,11 @@ import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { faker } from '@faker-js/faker'; import { toResource } from 'libs/tech-shared/test/resource'; import { times } from 'lodash-es'; -import { createApiError } from '../../../tech-shared/test/error'; +import { createBinaryFileResource } from '../../../binary-file-shared/test/binary-file'; +import { createSuccessfullyDoneCommandStateResource } from '../../../command-shared/test/command'; +import { createProblemDetail } from '../../../tech-shared/test/error'; import { BescheidListLinkRel } from '../lib/bescheid.linkrel'; -import { - Bescheid, - BescheidListResource, - BescheidResource, - BescheidSendBy, - BescheidStatus, - UploadFileInProgress, -} from '../lib/bescheid.model'; +import { Bescheid, BescheidAttachments, BescheidDocument, BescheidListResource, BescheidResource, BescheidSendBy, BescheidStatus, BescheidWizardStep, UploadFileInProgress, Wizard, } from '../lib/bescheid.model'; export function createBescheid(): Bescheid { return { @@ -53,14 +48,12 @@ export function createBescheidResource(linkRel: string[] = []): BescheidResource return toResource(createBescheid(), linkRel); } -export function createBescheidStateResource( - linkRel: string[] = [], -): StateResource<BescheidResource> { +export function createBescheidStateResource(linkRel: string[] = []): StateResource<BescheidResource> { return createStateResource(createBescheidResource(linkRel)); } export function createUploadFileInProgress(): UploadFileInProgress { - return { loading: true, fileName: faker.person.firstName(), error: createApiError() }; + return { loading: true, fileName: faker.person.firstName(), error: createProblemDetail() }; } export function createBescheidResources(linkRelations: string[] = []): BescheidResource[] { @@ -75,3 +68,54 @@ export function createBescheidListResource( [BescheidListLinkRel.BESCHEID_LIST]: bescheide, }); } + +export function createBescheidAttachments(): BescheidAttachments { + return { + upload: createUploadFileInProgress(), + items: [createBinaryFileResource()], + uploadStateResource: createStateResource(createBinaryFileResource()), + }; +} + +export function createBescheidDocument(): BescheidDocument { + return { + upload: createUploadFileInProgress(), + create: createSuccessfullyDoneCommandStateResource(), + documentUri: faker.internet.url(), + resource: createBinaryFileResource(), + }; +} + +export function createSuccessfulUpload(): UploadFileInProgress { + return { + loading: false, + error: null, + fileName: faker.system.fileName(), + }; +} + +export function createPendingUpload(): UploadFileInProgress { + return { + loading: true, + fileName: faker.system.fileName(), + error: null, + }; +} + +export function createErrorUpload(): UploadFileInProgress { + return { + loading: false, + error: createProblemDetail(), + fileName: faker.system.fileName(), + }; +} + +export function createWizard(): Wizard { + return { + empfaenger: faker.person.fullName(), + sendBy: BescheidSendBy.MANUAL, + bescheidCreated: false, + canBeSend: true, + activeStep: BescheidWizardStep.BescheidVersenden, + }; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html index dd3c548c5ab8b1d8b0811314cc637153af596aab..d63d7046e6e03287fae28cd1e019ff1fe55ce0f6 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.html @@ -27,28 +27,25 @@ <div class="fixed inset-0 z-10 w-screen overflow-y-auto"> <div class="flex h-full items-center justify-center p-8"> <div - class="relative h-full w-full max-w-7xl transform overflow-hidden rounded-lg bg-background-200 px-6 py-10 text-left shadow-xl transition-all" + class="relative h-full w-full max-w-7xl transform overflow-hidden rounded-lg bg-background-200 py-9 pl-6 pr-9 text-left shadow-xl transition-all" > - <ng-container *ngIf="bescheidDraftStateResource$ | async as bescheidStateResource"> - <ods-button - variant="ghost" - size="fit" - class="absolute right-0 top-0 text-text" - (clickEmitter)="cancelWizard(bescheidStateResource.resource)" - data-test-id="close-bescheid" - > - <ods-close-icon icon /> - </ods-button> - <alfa-bescheid-wizard - [vorgangWithEingangResource]="vorgangWithEingangResource" - [activeStep]="bescheidService.getActiveStep() | async" - [bescheidStateResource]="bescheidStateResource" - [submitStateResource]="submitStateResource$ | async" - (weiterClickEmitter)="onWeiter($event)" - (vorgangAbgeschlossen)="onVorgangAbgeschlossen()" - data-test-id="bescheid-wizard" - ></alfa-bescheid-wizard> - </ng-container> + @let bescheidStateResource = bescheidDraftStateResource$ | async; + <ods-button + variant="ghost" + size="fit" + class="absolute right-0 top-0 text-text" + (clickEmitter)="cancelWizard(bescheidStateResource.resource)" + dataTestId="close-bescheid" + > + <ods-close-icon icon /> + </ods-button> + <alfa-bescheid-wizard + [vorgangWithEingangResource]="vorgangWithEingangResource" + [activeStep]="activeStep$ | async" + [bescheidStateResource]="bescheidStateResource" + (vorgangAbgeschlossen)="onVorgangAbgeschlossen()" + data-test-id="bescheid-wizard" + ></alfa-bescheid-wizard> </div> </div> </div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts index 55cca698c53bc342a4a2546ce9bde17a57b5e889..1fe204ade444f7609bea459484de54ed0ab5a829 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.spec.ts @@ -21,21 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BescheidResource, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; import { CommandOrder, CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, createStateResource, ESCAPE_KEY, StateResource } from '@alfa-client/tech-shared'; import { - ESCAPE_KEY, - StateResource, - createEmptyStateResource, - createErrorStateResource, - createStateResource, -} from '@alfa-client/tech-shared'; -import { - DialogRefMock, - Mock, createDialogRefMock, + DialogRefMock, existsAsHtmlElement, getElementFromFixtureByType, + Mock, mock, triggerEvent, useFromMock, @@ -47,15 +41,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonComponent, CloseIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource, createBescheidStateResource } from '../../../../bescheid-shared/src/test/bescheid'; -import { - createCommandErrorResource, - createCommandResource, - createSuccessfullyDoneCommandResource, - createSuccessfullyDoneCommandStateResource, -} from '../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../tech-shared/test/data-test'; -import { createApiError } from '../../../../tech-shared/test/error'; +import { createCommandErrorResource, createSuccessfullyDoneCommandResource } from '../../../../command-shared/test/command'; +import { getDataTestIdAttributeOf, getDataTestIdOf } from '../../../../tech-shared/test/data-test'; import { singleColdCompleted } from '../../../../tech-shared/test/marbles'; import { createKeydownKeyboardEvent } from '../../../../test-utils/src/lib/keyboard'; import { createVorgangWithEingangResource } from '../../../../vorgang-shared/test/vorgang'; @@ -73,9 +62,9 @@ describe('BescheidWizardContainerComponent', () => { let fixture: ComponentFixture<BescheidWizardContainerComponent>; const bescheidWizard: string = getDataTestIdOf('bescheid-wizard'); - const closeButton: string = getDataTestIdOf('close-bescheid'); + const closeButton: string = getDataTestIdAttributeOf('close-bescheid'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let ozgcloudDialogService: Mock<OzgcloudDialogService>; let formService: Mock<BescheidFormService>; let wizardDialogRef: DialogRefMock<BescheidWizardDialogResult>; @@ -83,7 +72,8 @@ describe('BescheidWizardContainerComponent', () => { const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); + bescheidService.getBescheidCreated.mockReturnValue(EMPTY); ozgcloudDialogService = mock(OzgcloudDialogService); formService = mock(BescheidFormService); wizardDialogRef = createDialogRefMock(); @@ -115,7 +105,7 @@ describe('BescheidWizardContainerComponent', () => { useValue: { vorgangWithEingangResource }, }, { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, { @@ -160,6 +150,14 @@ describe('BescheidWizardContainerComponent', () => { expect(formService.setVorgangWithEingangResource).toHaveBeenCalledWith(vorgangWithEingangResource); }); + it('should set active step', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + component.ngOnInit(); + + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + it('should subscribe to bescheid resource', () => { component.subscribeToBescheidResourceIfExists = jest.fn(); @@ -231,74 +229,6 @@ describe('BescheidWizardContainerComponent', () => { }); }); - describe('onWeiter', () => { - beforeEach(() => { - formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(true); - bescheidService.getBescheidDraft.mockReturnValue(of(createBescheidStateResource())); - }); - - it('should submit form', () => { - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - expect(formService.submit).toHaveBeenCalled(); - }); - - it('should increment step on created bescheid', () => { - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); - - it('should increment step on updated bescheid', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); - - it('should not increment step on command resource error', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createApiError()))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on command resource loading', () => { - component.isBescheidSuccessfullyCreated = jest.fn().mockReturnValue(false); - formService.submit = jest.fn().mockReturnValue(of(createStateResource(createCommandResource(), true))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on bescheid resource error', () => { - bescheidService.getBescheidDraft.mockReturnValue(of(createErrorStateResource(createApiError()))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - - it('should not increment step on bescheid loading', () => { - bescheidService.getBescheidDraft.mockReturnValue(of(createStateResource(null, true))); - - component.onWeiter(BescheidWizardStep.DokumenteHochladen); - - component.submitStateResource$.subscribe(); - expect(bescheidService.setActiveStep).not.toHaveBeenCalled(); - }); - }); - describe('isBescheidSuccessfullyCreated', () => { it('should return true', () => { const createBescheidCommandResource: CommandResource = { @@ -498,81 +428,60 @@ describe('BescheidWizardContainerComponent', () => { }); describe('template', () => { - describe('alfa-bescheid-wizard', () => { + describe('wizard', () => { function getElementComponent(): BescheidWizardComponent { return getElementFromFixtureByType(fixture, BescheidWizardComponent); } - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); - - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); - - it('should set activeStep', () => { - bescheidService.getActiveStep.mockReturnValue(of(2)); - - fixture.detectChanges(); - - expect(getElementComponent().activeStep).toBe(2); - }); - - it('should set bescheidStateResource', () => { - const bescheidStateResource: StateResource<BescheidResource> = createBescheidStateResource(); - component.bescheidDraftStateResource$ = of(bescheidStateResource); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.DokumenteHochladen)); + const bescheidStateResource: StateResource<BescheidResource> = createBescheidStateResource(); + component.bescheidDraftStateResource$ = of(bescheidStateResource); + component.ngOnInit(); - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().bescheidStateResource).toBe(bescheidStateResource); - }); + expect(getElementComponent().vorgangWithEingangResource).toEqual(component.vorgangWithEingangResource); + expect(getElementComponent().activeStep).toEqual(2); + expect(getElementComponent().bescheidStateResource).toEqual(bescheidStateResource); }); describe('output', () => { - it('should call onWeiter', () => { - component.onWeiter = jest.fn(); + describe('vorgangAbgeschlossen', () => { + it('should call onVorgangAbgeschlossen', () => { + component.onVorgangAbgeschlossen = jest.fn(); - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: bescheidWizard, - }); - - expect(component.onWeiter).toHaveBeenCalled(); - }); - - it('should call onVorgangAbgeschlossen', () => { - component.onVorgangAbgeschlossen = jest.fn(); + triggerEvent({ + fixture, + name: 'vorgangAbgeschlossen', + elementSelector: bescheidWizard, + }); - triggerEvent({ - fixture, - name: 'vorgangAbgeschlossen', - elementSelector: bescheidWizard, + expect(component.onVorgangAbgeschlossen).toHaveBeenCalled(); }); - - expect(component.onVorgangAbgeschlossen).toHaveBeenCalled(); }); }); }); - describe('ods-button close', () => { - it('should show', () => { + describe('close button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, closeButton); }); describe('output', () => { - it('should call cancelWizard', () => { - component.cancelWizard = jest.fn(); + describe('clickEmitter', () => { + it('should call cancelWizard', () => { + component.cancelWizard = jest.fn(); - triggerEvent({ - fixture, - name: 'clickEmitter', - elementSelector: closeButton, - }); + triggerEvent({ + fixture, + name: 'clickEmitter', + elementSelector: closeButton, + }); - expect(component.cancelWizard).toHaveBeenCalled(); + expect(component.cancelWizard).toHaveBeenCalled(); + }); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts index d3be996f4a86c3236bbc64cfb9ec74baa5f9b761..cba4185d1a3d6805f5291ad6972c11965ed40fc5 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard-container.component.ts @@ -21,28 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { CommandOrder, CommandResource, isSuccessfulDone } from '@alfa-client/command-shared'; -import { - StateResource, - createEmptyStateResource, - hasStateResourceError, - isEscapeKey, - isLoaded, - isNotLoading, - isNotNil, -} from '@alfa-client/tech-shared'; +import { BescheidResource, BescheidWizardDialogResult, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { CommandOrder, CommandResource, CommandService, isSuccessfulDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, isEscapeKey, isNotLoading, isNotNil, ResourceRepository, StateResource, } from '@alfa-client/tech-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { getEmpfaenger } from '@alfa-client/vorgang-shared-ui'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject, OnDestroy, OnInit, ViewContainerRef } from '@angular/core'; -import { Resource, hasLink } from '@ngxp/rest'; -import { Observable, Subscription, filter, first, of, switchMap, tap } from 'rxjs'; -import { - BescheidWizardCancelDialogContainerComponent, - CancelWizardDialogData, - CancelWizardDialogResult, -} from './bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; +import { Component, inject, OnDestroy, OnInit, ViewContainerRef } from '@angular/core'; +import { hasLink } from '@ngxp/rest'; +import { BescheidResourceService, createBescheidResourceService } from 'libs/bescheid-shared/src/lib/bescheid-resource-service'; +import { filter, first, Observable, of, Subscription, switchMap } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; +import { BescheidWizardCancelDialogContainerComponent, CancelWizardDialogData, CancelWizardDialogResult, } from './bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; import { BescheidFormService } from './bescheid.formservice'; export interface BescheidWizardDialogData { @@ -52,42 +43,63 @@ export interface BescheidWizardDialogData { @Component({ selector: 'alfa-bescheid-wizard-container', templateUrl: './bescheid-wizard-container.component.html', - providers: [BescheidFormService], + providers: [ + BescheidFormService, + BescheidService2, + { + provide: BescheidResourceService, + useFactory: createBescheidResourceService, + deps: [ResourceRepository, CommandService, VorgangService], + }, + ], }) export class BescheidWizardContainerComponent implements OnInit, OnDestroy { + private readonly bescheidService = inject(BescheidService2); + private readonly ozgcloudDialogService = inject(OzgcloudDialogService); + private readonly dialogData: BescheidWizardDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + private readonly formService = inject(BescheidFormService); + readonly viewContainerRef = inject(ViewContainerRef); + public bescheidDraftStateResource$: Observable<StateResource<BescheidResource>> = of(createEmptyStateResource<BescheidResource>()); - public submitStateResource$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>()); + public activeStep$: Observable<BescheidWizardStep>; cancelDialogRef: DialogRef<CancelWizardDialogResult>; vorgangWithEingangResource: VorgangWithEingangResource; keydownEventsSubscription: Subscription; - constructor( - @Inject(DIALOG_DATA) private readonly dialogData: BescheidWizardDialogData, - private readonly dialogRef: DialogRef<BescheidWizardDialogResult>, - readonly viewContainerRef: ViewContainerRef, - public readonly formService: BescheidFormService, - readonly bescheidService: BescheidService, - private readonly ozgcloudDialogService: OzgcloudDialogService, - ) { - this.vorgangWithEingangResource = dialogData.vorgangWithEingangResource; + constructor() { + this.vorgangWithEingangResource = this.dialogData.vorgangWithEingangResource; } ngOnInit(): void { this.bescheidService.init(); + this.bescheidService.setNachrichtEmpfaenger(getEmpfaenger(this.vorgangWithEingangResource)); this.formService.setVorgangWithEingangResource(this.vorgangWithEingangResource); + this.activeStep$ = this.bescheidService.getActiveStep(); this.subscribeToBescheidResourceIfExists(); this.handleEscapeKey(); } ngOnDestroy(): void { this.keydownEventsSubscription.unsubscribe(); + this.bescheidService.exit(); } subscribeToBescheidResourceIfExists(): void { if (hasLink(this.vorgangWithEingangResource, VorgangWithEingangLinkRel.BESCHEID_DRAFT)) { this.bescheidDraftStateResource$ = this.bescheidService.getBescheidDraft(); + } else { + this.bescheidService + .getBescheidCreated() + .pipe( + filter((created: boolean) => created), + first(), + ) + .subscribe(() => { + this.bescheidDraftStateResource$ = this.bescheidService.selectBescheidResource(); + }); } } @@ -103,23 +115,6 @@ export class BescheidWizardContainerComponent implements OnInit, OnDestroy { }); } - public onWeiter(nextStep: BescheidWizardStep): void { - this.submitStateResource$ = this.formService.submit().pipe( - switchMap((commandStateResource: StateResource<CommandResource>) => { - if (this.isBescheidSuccessfullyCreated(commandStateResource.resource)) { - this.bescheidDraftStateResource$ = this.bescheidService.getBescheidDraft(); - return this.bescheidDraftStateResource$; - } - return of(commandStateResource); - }), - tap((stateResource: StateResource<Resource>) => { - if (isLoaded(stateResource) && !hasStateResourceError(stateResource)) { - this.bescheidService.setActiveStep(nextStep); - } - }), - ); - } - isBescheidSuccessfullyCreated(commandResource: CommandResource): boolean { return isSuccessfulDone(commandResource) && commandResource.order === CommandOrder.CREATE_BESCHEID; } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.html similarity index 100% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.html diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts similarity index 82% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts index 82b7402b1b2792d8ddd554934d8b9a5fb8071811..52f9b2e3270123a2dbf0204ef563ba4a38ab5e9c 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.spec.ts @@ -21,31 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - createDialogRefMock, - DialogRefMock, - existsAsHtmlElement, - mock, - Mock, - triggerEvent, - useFromMock, -} from '@alfa-client/test-utils'; -import { OzgcloudDialogService } from '@alfa-client/ui'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; +import { createDialogRefMock, DialogRefMock, existsAsHtmlElement, mock, Mock, triggerEvent, useFromMock, } from '@alfa-client/test-utils'; +import { createDialogResult, OzgcloudDialogCommandResult, OzgcloudDialogService } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; -import { - createDialogResult, - OzgcloudDialogCommandResult, -} from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; -import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { - AbschliessenDialogData, - BescheidWizardAbschliessenDialogContainerComponent, -} from '../abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; +import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, } from '../abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-abschliessen-button.component'; describe('BescheidWizardAbschliessenButtonComponent', () => { @@ -89,14 +76,16 @@ describe('BescheidWizardAbschliessenButtonComponent', () => { it('should open dialog', () => { const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const bescheidResource: BescheidResource = createBescheidResource(); component.vorgangWithEingangResource = vorgangWithEingangResource; + component.bescheidResource = bescheidResource; component.onClick(); expect(ozgcloudDialogService.openInCallingComponentContext).toHaveBeenCalledWith( BescheidWizardAbschliessenDialogContainerComponent, component.viewContainerRef, - { vorgangWithEingangResource } as AbschliessenDialogData, + { vorgangWithEingangResource, bescheidResource } as AbschliessenDialogData, ); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts similarity index 70% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts index 506fee1b6090c5bfcaf238d866b95b8cf284c711..c6622e64f1f3ee3dce37cef72ed5371892a7893c 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component.ts @@ -21,15 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DialogRef } from '@angular/cdk/dialog'; -import { Component, EventEmitter, Input, Output, ViewContainerRef } from '@angular/core'; +import { Component, EventEmitter, inject, Input, Output, ViewContainerRef } from '@angular/core'; import { filter } from 'rxjs'; import { - OzgcloudDialogCommandResult, isDialogSuccessfullyCompleted, -} from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; + OzgcloudDialogCommandResult, +} from '../../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, @@ -38,35 +39,33 @@ import { @Component({ selector: 'alfa-bescheid-wizard-abschliessen-button', templateUrl: './bescheid-wizard-abschliessen-button.component.html', + styles: [':host {@apply flex-1 flex items-end}'], }) export class BescheidWizardAbschliessenButtonComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; + @Input() bescheidResource: BescheidResource; @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); - constructor( - private readonly ozgclouDialogService: OzgcloudDialogService, - readonly viewContainerRef: ViewContainerRef, - ) {} + private readonly ozgcloudDialogService = inject(OzgcloudDialogService); + readonly viewContainerRef = inject(ViewContainerRef); public onClick(): void { const dialogData: AbschliessenDialogData = { vorgangWithEingangResource: this.vorgangWithEingangResource, + bescheidResource: this.bescheidResource, }; - const dialogRef: DialogRef<OzgcloudDialogCommandResult> = - this.ozgclouDialogService.openInCallingComponentContext( - BescheidWizardAbschliessenDialogContainerComponent, - this.viewContainerRef, - dialogData, - ); + const dialogRef: DialogRef<OzgcloudDialogCommandResult> = this.ozgcloudDialogService.openInCallingComponentContext( + BescheidWizardAbschliessenDialogContainerComponent, + this.viewContainerRef, + dialogData, + ); this.handleDialogClosed(dialogRef); } handleDialogClosed(dialogRef: DialogRef<OzgcloudDialogCommandResult>): void { - dialogRef.closed - .pipe(filter(isDialogSuccessfullyCompleted)) - .subscribe(() => this.vorgangAbgeschlossen.emit()); + dialogRef.closed.pipe(filter(isDialogSuccessfullyCompleted)).subscribe(() => this.vorgangAbgeschlossen.emit()); } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html similarity index 100% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.html diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts similarity index 75% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts index 01d76234027235a6d5417fd1ec6758d5d6c4f24b..df6b0e09d088b27f5601ba9b12abf43363b8a0a7 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.spec.ts @@ -21,33 +21,24 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; import { StateResource } from '@alfa-client/tech-shared'; -import { - createDialogRefMock, - DialogRefMock, - getElementComponentFromFixtureByCss, - mock, - Mock, - triggerEvent, -} from '@alfa-client/test-utils'; -import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; +import { createDialogRefMock, DialogRefMock, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent, } from '@alfa-client/test-utils'; +import { createDialogResult, OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIcon } from '@angular/material/icon'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; -import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; -import { createDialogResult } from '../../../../../../ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.result'; -import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { - AbschliessenDialogData, - BescheidWizardAbschliessenDialogContainerComponent, -} from './bescheid-wizard-abschliessen-dialog-container.component'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../../tech-shared/test/marbles'; +import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; +import { AbschliessenDialogData, BescheidWizardAbschliessenDialogContainerComponent, } from './bescheid-wizard-abschliessen-dialog-container.component'; describe('BescheidWizardAbschliessenDialogContainerComponent', () => { let component: BescheidWizardAbschliessenDialogContainerComponent; @@ -57,13 +48,14 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { const confirmButtonDataTestId: string = getDataTestIdOf('ueberspringen-abschliessen-button'); const cancelButtonDataTestId: string = getDataTestIdOf('ueberspringen-abbrechen-button'); const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); - const dialogData: AbschliessenDialogData = { vorgangWithEingangResource }; + const bescheidResource: BescheidResource = createBescheidResource(); + const dialogData: AbschliessenDialogData = { vorgangWithEingangResource, bescheidResource }; let dialogRef: DialogRefMock; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); dialogRef = createDialogRefMock(); }); @@ -84,7 +76,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { useValue: dialogRef, }, { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, ], @@ -111,16 +103,16 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { describe('onConfirm', () => { it('should call bescheid service', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); - expect(bescheidService.bescheidErstellungUeberspringen).toHaveBeenCalledWith(vorgangWithEingangResource); + expect(bescheidService.skipBescheidCreation).toHaveBeenCalledWith(vorgangWithEingangResource, bescheidResource); }); it('should set abschliessen$', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); @@ -129,7 +121,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { it('should close dialog', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidErstellungUeberspringen.mockReturnValue(of(commandStateResource)); + bescheidService.skipBescheidCreation.mockReturnValue(of(commandStateResource)); component.onConfirm(); component.abschliessen$.subscribe(); @@ -140,7 +132,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { }); describe('template', () => { - describe('button close', () => { + describe('close button', () => { describe('output', () => { it('should call onClose', () => { component.onClose = jest.fn(); @@ -152,7 +144,7 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { }); }); - describe('ozgcloud-stroked-button-with-spinner Überspringen und abschließen', () => { + describe('überspringen und abschließen button', () => { function getElementComponent(): OzgcloudStrokedButtonWithSpinnerComponent { return getElementComponentFromFixtureByCss(fixture, confirmButtonDataTestId); } @@ -172,18 +164,14 @@ describe('BescheidWizardAbschliessenDialogContainerComponent', () => { it('should call onConfirm', () => { component.onConfirm = jest.fn(); - triggerEvent({ - fixture, - name: 'click', - elementSelector: confirmButtonDataTestId, - }); + triggerEvent({ fixture, name: 'click', elementSelector: confirmButtonDataTestId }); expect(component.onConfirm).toHaveBeenCalled(); }); }); }); - describe('ozgcloud-stroked-button-with-spinner Abbrechen', () => { + describe('abbrechen button', () => { it('should call onClose', () => { component.onClose = jest.fn(); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts similarity index 78% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts index f147cfea08b03a214884c2d4d5d5c8414df4b4be..5a8ace4040ce03c2e7cff5f2efc3f24877d0f201 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component.ts @@ -21,17 +21,19 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { createDialogResult } from '@alfa-client/ui'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; export interface AbschliessenDialogData { vorgangWithEingangResource: VorgangWithEingangResource; + bescheidResource: BescheidResource; } @Component({ @@ -39,21 +41,20 @@ export interface AbschliessenDialogData { templateUrl: './bescheid-wizard-abschliessen-dialog-container.component.html', }) export class BescheidWizardAbschliessenDialogContainerComponent { - public abschliessen$: Observable<StateResource<CommandResource>>; + private readonly dialogData: AbschliessenDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef); + private readonly bescheidService = inject(BescheidService2); - constructor( - @Inject(DIALOG_DATA) private readonly dialogData: AbschliessenDialogData, - private readonly dialogRef: DialogRef, - private readonly bescheidService: BescheidService, - ) {} + public abschliessen$: Observable<StateResource<CommandResource>>; public onClose(): void { this.dialogRef.close(); } public onConfirm(): void { + // @ts-ignore this.abschliessen$ = this.bescheidService - .bescheidErstellungUeberspringen(this.dialogData.vorgangWithEingangResource) + .skipBescheidCreation(this.dialogData.vorgangWithEingangResource, this.dialogData.bescheidResource) .pipe( tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => this.dialogRef.close(createDialogResult(commandStateResource)), diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html similarity index 75% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html index 6d9e44922fc835eaffab2615c9a54659f928a195..025f01d04b1065869baaffd5dc7814c956f6850f 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.html @@ -23,29 +23,25 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="mt-2 grid h-full grid-cols-[min-content_1fr_1fr] gap-7"> - <alfa-bescheid-wizard-stepper - [activeStep]="bescheidWizardStep.AntragBescheiden" - data-test-id="wizard-stepper" - ></alfa-bescheid-wizard-stepper> - <div> - <alfa-bescheid-wizard-step-title label="Antrag bescheiden" data-test-id="wizard-step-title"></alfa-bescheid-wizard-step-title> +<alfa-step-content-layout [activeStep]="BescheidWizardStep.AntragBescheiden"> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title label="Antrag bescheiden" data-test-id="wizard-step-title" /> <alfa-bescheid-wizard-antrag-bescheiden-form [vorgangWithEingangResource]="vorgangWithEingangResource" [bescheidResource]="bescheidResource" - [submitStateResource]="submitStateResource" - (weiterClickEmitter)="weiterClickEmitter.emit(bescheidWizardStep.DokumenteHochladen)" + (weiterClickEmitter)="onWeiterClick()" data-test-id="antrag-bescheiden-form" ></alfa-bescheid-wizard-antrag-bescheiden-form> <alfa-bescheid-wizard-abschliessen-button [vorgangWithEingangResource]="vorgangWithEingangResource" + [bescheidResource]="bescheidResource" (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" data-test-id="wizard-abschliessen-button" ></alfa-bescheid-wizard-abschliessen-button> - </div> - <alfa-bescheid-wizard-summary data-test-id="wizard-summary"> + </ng-container> + <ng-container summary> <alfa-bescheid-wizard-antrag-bescheiden-summary data-test-id="antrag-bescheiden-summary" ></alfa-bescheid-wizard-antrag-bescheiden-summary> - </alfa-bescheid-wizard-summary> -</div> + </ng-container> +</alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts similarity index 54% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts index a2a12395ea886598dae1607d5836a41dc2602097..d3452acaabaa91d8cced04afc925138dd1d2d546 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.spec.ts @@ -21,44 +21,43 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { Mock, existsAsHtmlElement, getElementFromFixtureByType, mock, triggerEvent, useFromMock } from '@alfa-client/test-utils'; +import { existsAsHtmlElement, getElementFromFixtureByType, Mock, mock, triggerEvent, useFromMock } from '@alfa-client/test-utils'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent } from 'ng-mocks'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; -import { createCommandStateResource } from '../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang'; -import { BescheidWizardAbschliessenButtonComponent } from '../abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; -import { BescheidWizardAntragBescheidenComponent } from './bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAbschliessenButtonComponent } from './abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './bescheid-wizard-antrag-bescheiden-container.component'; import { BescheidWizardAntragBescheidenFormComponent } from './form/bescheid-wizard-antrag-bescheiden-form.component'; import { BescheidWizardAntragBescheidenSummaryComponent } from './summary/bescheid-wizard-antrag-bescheiden-summary.component'; describe('BescheidWizardAntragBescheidenComponent', () => { - let component: BescheidWizardAntragBescheidenComponent; - let fixture: ComponentFixture<BescheidWizardAntragBescheidenComponent>; + let component: BescheidWizardAntragBescheidenContainerComponent; + let fixture: ComponentFixture<BescheidWizardAntragBescheidenContainerComponent>; - const wizardStepper: string = getDataTestIdOf('wizard-stepper'); const wizardStepTitle: string = getDataTestIdOf('wizard-step-title'); const antragBescheidenForm: string = getDataTestIdOf('antrag-bescheiden-form'); const abschliessenButton: string = getDataTestIdOf('wizard-abschliessen-button'); - const wizardSummary: string = getDataTestIdOf('wizard-summary'); const antragBescheidenSummary: string = getDataTestIdOf('antrag-bescheiden-summary'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); }); beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ - BescheidWizardAntragBescheidenComponent, + BescheidWizardAntragBescheidenContainerComponent, + MockComponent(StepContentLayoutComponent), MockComponent(BescheidWizardStepTitleComponent), MockComponent(BescheidWizardAntragBescheidenFormComponent), MockComponent(BescheidWizardSummaryComponent), @@ -68,15 +67,14 @@ describe('BescheidWizardAntragBescheidenComponent', () => { ], providers: [ { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, ], }).compileComponents(); - fixture = TestBed.createComponent(BescheidWizardAntragBescheidenComponent); + fixture = TestBed.createComponent(BescheidWizardAntragBescheidenContainerComponent); component = fixture.componentInstance; - component.weiterClickEmitter = useFromMock(mock(EventEmitter<BescheidWizardStep>)); component.vorgangAbgeschlossen = useFromMock(mock(EventEmitter<void>)); fixture.detectChanges(); }); @@ -86,121 +84,75 @@ describe('BescheidWizardAntragBescheidenComponent', () => { }); describe('template', () => { - describe('alfa-bescheid-wizard-stepper', () => { - function getElementComponent(): BescheidWizardStepperComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepperComponent); + describe('wizard step title', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, wizardStepTitle); + }); + }); + + describe('antrag bescheiden form', () => { + function getElementComponent(): BescheidWizardAntragBescheidenFormComponent { + return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenFormComponent); } it('should exists', () => { - fixture.detectChanges(); - - existsAsHtmlElement(fixture, wizardStepper); + existsAsHtmlElement(fixture, antragBescheidenForm); }); - describe('input', () => { - it('should set activeStep', () => { - fixture.detectChanges(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + component.bescheidResource = createBescheidResource(); - expect(getElementComponent().activeStep).toBe(BescheidWizardStep.AntragBescheiden); - }); - }); - }); + fixture.detectChanges(); - describe('alfa-bescheid-wizard-step-title', () => { - it('should show', () => { - existsAsHtmlElement(fixture, wizardStepTitle); + expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); }); - }); - describe('alfa-bescheid-wizard-summary', () => { - it('should show', () => { - existsAsHtmlElement(fixture, wizardSummary); - }); - }); + describe('output', () => { + describe('weiterClickEmitter', () => { + it('should call handler', () => { + component.onWeiterClick = jest.fn(); - describe('alfa-bescheid-wizard-antrag-bescheiden-summary', () => { - it('should show', () => { - existsAsHtmlElement(fixture, antragBescheidenSummary); + triggerEvent({ fixture, name: 'weiterClickEmitter', elementSelector: antragBescheidenForm }); + + expect(component.onWeiterClick).toHaveBeenCalled(); + }); + }); }); }); - describe('alfa-bescheid-wizard-abschliessen-button', () => { + describe('abschliessen button', () => { function getElementComponent(): BescheidWizardAbschliessenButtonComponent { return getElementFromFixtureByType(fixture, BescheidWizardAbschliessenButtonComponent); } - it('should show', () => { + it('should exists', () => { existsAsHtmlElement(fixture, abschliessenButton); }); - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource(); + component.bescheidResource = createBescheidResource(); - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); + expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); }); describe('output', () => { - it('should call onVorgangAbgeschlossen', () => { - triggerEvent({ - fixture, - name: 'vorgangAbgeschlossen', - elementSelector: abschliessenButton, - }); + it('should call handler', () => { + triggerEvent({ fixture, name: 'vorgangAbgeschlossen', elementSelector: abschliessenButton }); expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); }); }); }); - describe('alfa-bescheid-wizard-antrag-bescheiden-form', () => { - function getElementComponent(): BescheidWizardAntragBescheidenFormComponent { - return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenFormComponent); - } - - it('should show', () => { - existsAsHtmlElement(fixture, antragBescheidenForm); - }); - - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); - - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); - - it('should set bescheidResource', () => { - component.bescheidResource = createBescheidResource(); - - fixture.detectChanges(); - - expect(getElementComponent().bescheidResource).toBe(component.bescheidResource); - }); - - it('should set submitStateResource', () => { - component.submitStateResource = createCommandStateResource(); - - fixture.detectChanges(); - - expect(getElementComponent().submitStateResource).toBe(component.submitStateResource); - }); - }); - - describe('output', () => { - it('should emit weiterClickEmitter', () => { - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: antragBescheidenForm, - }); - - expect(component.weiterClickEmitter.emit).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); + describe('antrag bescheiden summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, antragBescheidenSummary); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts similarity index 68% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts index 2dcbf71a91305c14e8c10cd4b8c4130f1609f715..9837cbe2bca5ed1e8ff4f9674d10895c476d7faf 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component.ts @@ -22,22 +22,25 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; @Component({ - selector: 'alfa-bescheid-wizard-antrag-bescheiden', - templateUrl: './bescheid-wizard-antrag-bescheiden.component.html', + selector: 'alfa-bescheid-wizard-antrag-bescheiden-container', + templateUrl: './bescheid-wizard-antrag-bescheiden-container.component.html', }) -export class BescheidWizardAntragBescheidenComponent { +export class BescheidWizardAntragBescheidenContainerComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; @Input() bescheidResource: BescheidResource; - @Input() submitStateResource: StateResource<Resource>; - @Output() weiterClickEmitter: EventEmitter<BescheidWizardStep> = new EventEmitter<BescheidWizardStep>(); @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); - public readonly bescheidWizardStep = BescheidWizardStep; + private readonly bescheidService = inject(BescheidService2); + + public readonly BescheidWizardStep = BescheidWizardStep; + + public onWeiterClick(): void { + this.bescheidService.setActiveStep(BescheidWizardStep.DokumenteHochladen); + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html index 5d3a471c46056ef89c8d3995ce0591519fd97bbc..8861db5df5fd7745a5061fecd7fead4301583384 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.html @@ -24,7 +24,7 @@ --> <div [formGroup]="formService.form" role="radiogroup" aria-label="Bescheidstatus"> - <div class="my-10 flex max-w-2xl gap-8"> + <div class="my-10 flex flex-wrap gap-8"> <ods-radio-button-card label="bewilligt" [name]="formServiceClass.FIELD_BEWILLIGT" @@ -52,12 +52,13 @@ </ozgcloud-date-editor> </div> </div> -<alfa-bescheid-wizard-weiter-button - *ngIf=" - (vorgangWithEingangResource | hasLink: vorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT) || - (bescheidResource | hasLink: bescheidLinkRel.UPDATE) - " - [submitStateResource]="submitStateResource" - (clickEmitter)="weiterClickEmitter.emit()" - data-test-id="weiter-button" -></alfa-bescheid-wizard-weiter-button> +@if ( + (vorgangWithEingangResource | hasLink: vorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT) || + (bescheidResource | hasLink: bescheidLinkRel.UPDATE) +) { + <alfa-bescheid-wizard-weiter-button + [submitStateResource]="submitStateResource$ | async" + (clickEmitter)="submit()" + data-test-id="weiter-button" + ></alfa-bescheid-wizard-weiter-button> +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts index fb9b631931e637501aefed12255c8b44284b0167..fc15a7f9282febbd25179f0b255a5781234bfb86 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.spec.ts @@ -21,9 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidLinkRel, BescheidService } from '@alfa-client/bescheid-shared'; -import { HasLinkPipe } from '@alfa-client/tech-shared'; -import { existsAsHtmlElement, mock, notExistsAsHtmlElement, triggerEvent, useFromMock } from '@alfa-client/test-utils'; +import { BescheidLinkRel } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createEmptyStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, getElementFromFixtureByType, mock, notExistsAsHtmlElement, triggerEvent, useFromMock, } from '@alfa-client/test-utils'; import { DateEditorComponent } from '@alfa-client/ui'; import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; @@ -31,8 +32,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { CloseIconComponent, RadioButtonCardComponent, StampIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../../tech-shared/test/marbles'; import { createVorgangWithEingangResource } from '../../../../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from '../../../bescheid.formservice'; import { BescheidWizardWeiterButtonComponent } from '../../weiter-button/bescheid-wizard-weiter-button.component'; @@ -47,7 +52,8 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { let formService: BescheidFormService; beforeEach(async () => { - formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService))); + formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService2))); + formService.submit = jest.fn().mockReturnValue(EMPTY); await TestBed.configureTestingModule({ declarations: [ @@ -74,12 +80,35 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + it('should call form service', () => { + component.submit(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should emit weiter click', () => { + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + }); + }); }); describe('template', () => { - describe('alfa-bescheid-wizard-weiter-button', () => { + describe('weiter button', () => { it('should exists if bescheid update link exists', () => { component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); @@ -98,7 +127,7 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { existsAsHtmlElement(fixture, weiterButton); }); - it('should not exists if update and create links missing', () => { + it('should NOT exists if update and create links missing', () => { component.vorgangWithEingangResource = createVorgangWithEingangResource(); component.bescheidResource = createBescheidResource(); @@ -107,7 +136,7 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { notExistsAsHtmlElement(fixture, weiterButton); }); - it('should not exists if update link missing', () => { + it('should NOT exists if update link missing', () => { component.bescheidResource = createBescheidResource(); fixture.detectChanges(); @@ -115,19 +144,36 @@ describe('BescheidWizardAntragBescheidenFormComponent', () => { notExistsAsHtmlElement(fixture, weiterButton); }); + it('should have been called with inputs', (done) => { + component.vorgangWithEingangResource = createVorgangWithEingangResource([ + VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT, + ]); + + fixture.detectChanges(); + + const weiterButtonComponent: BescheidWizardWeiterButtonComponent = getElementFromFixtureByType( + fixture, + BescheidWizardWeiterButtonComponent, + ); + + component.submitStateResource$.subscribe((submitStateResource: StateResource<CommandResource>) => { + expect(weiterButtonComponent.submitStateResource).toEqual(submitStateResource); + done(); + }); + }); + describe('output', () => { - it('should emit weiterClickEmitter', () => { - component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + describe('clickEmitter', () => { + it('should submit', () => { + component.submit = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); - fixture.detectChanges(); + fixture.detectChanges(); - triggerEvent({ - fixture, - name: 'clickEmitter', - elementSelector: weiterButton, - }); + triggerEvent({ fixture, name: 'clickEmitter', elementSelector: weiterButton }); - expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + expect(component.submit).toHaveBeenCalled(); + }); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts index 5806f5dcf9a2ecb1cf45d737419fe19da8f546ec..5c9c0ab6365f39586a6b9809fbd41ecba860a869 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component.ts @@ -22,10 +22,11 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; -import { StateResource } from '@alfa-client/tech-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { Observable, of } from 'rxjs'; import { BescheidFormService } from '../../../bescheid.formservice'; @Component({ @@ -35,13 +36,20 @@ import { BescheidFormService } from '../../../bescheid.formservice'; export class BescheidWizardAntragBescheidenFormComponent { @Input() vorgangWithEingangResource: VorgangWithEingangResource; @Input() bescheidResource: BescheidResource; - @Input() submitStateResource: StateResource<Resource>; @Output() weiterClickEmitter = new EventEmitter<void>(); + public readonly formService = inject(BescheidFormService); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + public readonly vorgangWithEingangLinkRel = VorgangWithEingangLinkRel; public readonly bescheidLinkRel = BescheidLinkRel; public readonly formServiceClass = BescheidFormService; - constructor(public readonly formService: BescheidFormService) {} + public submit(): void { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.weiterClickEmitter.emit())); + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts index e4d89586aec9b233d612f87877efdd1298a8c318..571478e90cb9e5e00e8f79f7d695c475416cf95e 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component.spec.ts @@ -60,18 +60,20 @@ describe('BescheidWizardAntragBescheidenSummaryComponent', () => { }); describe('template', () => { - describe('ods-bescheid-status-text', () => { + describe('status text', () => { function getElementComponent(): BescheidStatusTextComponent { return getElementFromFixtureByType(fixture, BescheidStatusTextComponent); } - it('should subscribe to bescheid value form changes', () => { + it('should exists', () => { + formService.getBescheidFormValueChanges.mockReturnValue(of(createBescheid())); + fixture.detectChanges(); - expect(formService.getBescheidFormValueChanges).toHaveBeenCalled(); + existsAsHtmlElement(fixture, bescheidStatusText); }); - it('should NOT show', () => { + it('should NOT exists', () => { formService.getBescheidFormValueChanges.mockReturnValue(EMPTY); fixture.detectChanges(); @@ -79,41 +81,21 @@ describe('BescheidWizardAntragBescheidenSummaryComponent', () => { notExistsAsHtmlElement(fixture, bescheidStatusText); }); - it('should show', () => { - formService.getBescheidFormValueChanges.mockReturnValue(of(createBescheid())); - + it('should subscribe to bescheid value form changes', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, bescheidStatusText); + expect(formService.getBescheidFormValueChanges).toHaveBeenCalled(); }); - describe('input', () => { - it('should set bewilligt', () => { - const bescheid: Bescheid = createBescheid(); - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - - fixture.detectChanges(); - - expect(getElementComponent().bewilligt).toBe(bescheid.bewilligt); - }); - - it('should set dateText', () => { - const bescheid: Bescheid = { ...createBescheid(), beschiedenAm: '2024-01-01' }; - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); + it('should have been called with inputs', () => { + const bescheid: Bescheid = createBescheid(); + formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - fixture.detectChanges(); - - expect(getElementComponent().dateText).toBe('01.01.2024'); - }); - - it('should set hasBescheidDraft', () => { - const bescheid: Bescheid = createBescheid(); - formService.getBescheidFormValueChanges.mockReturnValue(of(bescheid)); - - fixture.detectChanges(); + fixture.detectChanges(); - expect(getElementComponent().hasBescheidDraft).toBeFalsy(); - }); + expect(getElementComponent().bewilligt).toBe(bescheid.bewilligt); + expect(getElementComponent().dateText).toBe('01.01.2024'); + expect(getElementComponent().hasBescheidDraft).toBeFalsy(); }); }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html new file mode 100644 index 0000000000000000000000000000000000000000..622107cd6a88a6410e8c7bcdc7e08fd262f1635b --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.html @@ -0,0 +1,21 @@ +<ods-attachment-wrapper> + @for (attachment of attachments; track $index) { + <alfa-binary-file2-container + [file]="attachment" + [deletable]="deletable" + (startDelete)="delete.emit($event)" + [attr.data-test-id]="(attachment.name | convertForDataTest) + '-file2-container'" + > + </alfa-binary-file2-container> + } + @if (upload.loading || upload.error) { + <ods-attachment + [loadingCaption]="upload.fileName" + errorCaption="Fehler beim Hochladen" + [errorMessages]="upload.error | convertProblemDetailToErrorMessages" + description="Anhang wird hochgeladen" + [isLoading]="upload.loading" + data-test-id="attachment-upload-in-progress" + ></ods-attachment> + } +</ods-attachment-wrapper> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..92f027903e7ddb01410294bcced6f60759882b68 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.spec.ts @@ -0,0 +1,165 @@ +import { BescheidAttachments, createEmptyBescheidAttachments, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file'; +import { ConvertForDataTestPipe, ConvertProblemDetailToErrorMessagesPipe, ProblemDetail } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidAttachments } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../tech-shared/test/error'; +import { BescheidWizardAttachmentFilesComponent } from './bescheid-wizard-attachment-files.component'; + +describe('BescheidWizardAttachmentFileComponent', () => { + let component: BescheidWizardAttachmentFilesComponent; + let fixture: ComponentFixture<BescheidWizardAttachmentFilesComponent>; + + const convertForDataTest: ConvertForDataTestPipe = new ConvertForDataTestPipe(); + const convertProblemDetailsToErrorMessage: ConvertProblemDetailToErrorMessagesPipe = + new ConvertProblemDetailToErrorMessagesPipe(); + + const attachments: BescheidAttachments = createBescheidAttachments(); + + const binaryFileContainerTestId: string = getDataTestIdOf( + convertForDataTest.transform(attachments.items[0].name) + '-file2-container', + ); + const attachmentUploadTestId: string = getDataTestIdOf('attachment-upload-in-progress'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardAttachmentFilesComponent, + MockComponent(BinaryFile2ContainerComponent), + MockComponent(AttachmentComponent), + MockComponent(AttachmentWrapperComponent), + ConvertForDataTestPipe, + ConvertProblemDetailToErrorMessagesPipe, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardAttachmentFilesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyUploadInProgress()); + expect(component.attachments).toEqual(createEmptyBescheidAttachments().items); + }); + + describe('set attachments', () => { + it('should set attachments', () => { + component.attachments = attachments; + + expect(component.attachments).toEqual(attachments.items); + }); + + it('should set upload', () => { + component.attachments = attachments; + + expect(component.upload).toEqual(attachments.upload); + }); + }); + }); + + describe('template', () => { + describe('attachment binary file container', () => { + it('should exists', () => { + component.attachments = attachments; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, binaryFileContainerTestId); + }); + + it('should have been called with inputs', () => { + component.attachments = attachments; + + fixture.detectChanges(); + const binaryFileComponent: BinaryFile2ContainerComponent = + getElementComponentFromFixtureByCss<BinaryFile2ContainerComponent>(fixture, binaryFileContainerTestId); + + expect(binaryFileComponent.file).toEqual(attachments.items[0]); + expect(binaryFileComponent.deletable).toEqual(component.deletable); + }); + + describe('output', () => { + describe('startDelete', () => { + it('should emit', () => { + component.attachments = attachments; + component.delete.emit = jest.fn(); + + fixture.detectChanges(); + + triggerEvent({ + fixture, + elementSelector: binaryFileContainerTestId, + name: 'startDelete', + data: attachments.items[0], + }); + + expect(component.delete.emit).toHaveBeenCalledWith(attachments.items[0]); + }); + }); + }); + }); + + describe('upload attachment', () => { + it('should exists on loading', () => { + component.attachments = { ...attachments, upload: { ...attachments.upload, loading: true, error: null } }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should exists on error', () => { + component.attachments = { + ...attachments, + upload: { ...attachments.upload, loading: false, error: createProblemDetail() }, + }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should NOT exists', () => { + component.attachments = { + ...attachments, + upload: { ...attachments.upload, loading: false, error: null }, + }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, attachmentUploadTestId); + }); + + it('should have been called with inputs', () => { + component.attachments = attachments; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + attachmentUploadTestId, + ); + + expect(attachmentComponent.loadingCaption).toEqual(attachments.upload.fileName); + expect(attachmentComponent.errorMessages).toEqual( + convertProblemDetailsToErrorMessage.transform(attachments.upload.error as ProblemDetail), + ); + expect(attachmentComponent.isLoading).toEqual(attachments.upload.loading); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5a60cd795a7f6b7b918ce39a5fd5b45c1b3cb63 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component.ts @@ -0,0 +1,30 @@ +import { + BescheidAttachments, + createEmptyBescheidAttachments, + createEmptyUploadInProgress, + UploadFileInProgress, +} from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-attachment-files', + templateUrl: './bescheid-wizard-attachment-files.component.html', +}) +export class BescheidWizardAttachmentFilesComponent { + @Input() set attachments(value: BescheidAttachments) { + this._attachments = value; + this.upload = value.upload; + } + + get attachments(): BinaryFileResource[] { + return this._attachments.items; + } + + @Input() deletable: boolean; + + @Output() delete: EventEmitter<BinaryFileResource> = new EventEmitter(); + + public upload: UploadFileInProgress = createEmptyUploadInProgress(); + private _attachments: BescheidAttachments = createEmptyBescheidAttachments(); +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c34bfce43f0959f56aa16e8a993f31b61bec0839 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-attachment-files + [attachments]="attachments$ | async" + [deletable]="(activeStep$ | async) === bescheidWizardStep.DokumenteHochladen" + (delete)="deleteAttachment($event)" + data-test-id="bescheid-attachments" +></alfa-bescheid-wizard-attachment-files> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c2cdd8df598bfddfb8b6fc3512066f44d58cc65 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.spec.ts @@ -0,0 +1,123 @@ +import { BescheidAttachments, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidAttachments } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { createBinaryFileResource } from '../../../../../../binary-file-shared/test/binary-file'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardAttachmentFilesComponent } from './attachment-files/bescheid-wizard-attachment-files.component'; +import { BescheidWizardAttachmentFilesContainerComponent } from './bescheid-wizard-attachment-files-container.component'; + +describe('BescheidWizardAttachmentFileContainerComponent', () => { + let component: BescheidWizardAttachmentFilesContainerComponent; + let fixture: ComponentFixture<BescheidWizardAttachmentFilesContainerComponent>; + + const attachmentsFilesTestId: string = getDataTestIdOf('bescheid-attachments'); + + const attachments: BescheidAttachments = createBescheidAttachments(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardAttachmentFilesContainerComponent, MockComponent(BescheidWizardAttachmentFilesComponent)], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardAttachmentFilesContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should set attachments', () => { + bescheidService.getAttachments.mockReturnValue(of(attachments)); + + component.ngOnInit(); + + expect(component.attachments$).toBeObservable(singleColdCompleted(attachments)); + }); + + it('should set active step', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + component.ngOnInit(); + + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + }); + + describe('deleteAttachment', () => { + it('should call service', () => { + component.deleteAttachment = jest.fn(); + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + + component.deleteAttachment(binaryFileResource); + + expect(component.deleteAttachment).toHaveBeenCalledWith(binaryFileResource); + }); + }); + }); + + describe('template', () => { + describe('attachment files', () => { + function getComponent(): BescheidWizardAttachmentFilesComponent { + return getElementComponentFromFixtureByCss<BescheidWizardAttachmentFilesComponent>(fixture, attachmentsFilesTestId); + } + + it('should exists', () => { + existsAsHtmlElement(fixture, attachmentsFilesTestId); + }); + + it('should have been called with attachments', () => { + component.attachments$ = of(attachments); + + fixture.detectChanges(); + + expect(getComponent().attachments).toEqual(attachments); + }); + + it('should have been called with deletable true', () => { + component.activeStep$ = of(BescheidWizardStep.DokumenteHochladen); + + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(true); + }); + + it('should have been called with deletable false', () => { + component.activeStep$ = of(BescheidWizardStep.BescheidVersenden); + + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(false); + }); + + describe('output', () => { + describe('delete', () => { + it('should call handler', () => { + const binaryFileResource: BinaryFileResource = createBinaryFileResource(); + component.deleteAttachment = jest.fn(); + + triggerEvent({ fixture, elementSelector: attachmentsFilesTestId, name: 'delete', data: binaryFileResource }); + + expect(component.deleteAttachment).toHaveBeenCalledWith(binaryFileResource); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..50d2dea88ea12ba5fec926d895ff47044f017409 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component.ts @@ -0,0 +1,27 @@ +import { BescheidAttachments, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { Component, inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-attachment-files-container', + templateUrl: './bescheid-wizard-attachment-files-container.component.html', +}) +export class BescheidWizardAttachmentFilesContainerComponent implements OnInit { + public readonly bescheidService = inject(BescheidService2); + + public attachments$: Observable<BescheidAttachments>; + public activeStep$: Observable<BescheidWizardStep>; + + public readonly bescheidWizardStep = BescheidWizardStep; + + ngOnInit(): void { + this.attachments$ = this.bescheidService.getAttachments(); + this.activeStep$ = this.bescheidService.getActiveStep(); + } + + public deleteAttachment(binaryFileResource: BinaryFileResource): void { + this.bescheidService.deleteAttachment(binaryFileResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ebb663b568ce2cddf824bba0988d46ed38c3c6e8 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.html @@ -0,0 +1,30 @@ +<alfa-step-content-layout + [activeStep]="bescheidWizardStep.BescheidVersenden" + (stepChange)="onStepChange($event)" + data-test-id="step-content-layout" +> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title + label="Antrag bescheiden" + [inactiveStep]="true" + data-test-id="antrag-bescheiden-step-title" + /> + <alfa-bescheid-wizard-step-title + label="Dokumente hinzufügen" + [inactiveStep]="true" + data-test-id="dokumente-hochladen-step-title" + /> + <alfa-bescheid-wizard-step-title label="Bescheid versenden" /> + <alfa-bescheid-wizard-bescheid-versenden-form + [bescheidResource]="bescheidResource" + (sendBy)="onSendBy($event)" + data-test-id="bescheid-wizard-bescheid-versenden-form" + /> + </ng-container> + <ng-container summary> + <alfa-bescheid-wizard-bescheid-versenden-summary + [bescheidResource]="bescheidResource" + [wizard]="wizard$ | async" + data-test-id="bescheiden-result" + /> </ng-container +></alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..abdb3be7cef699e775c5bbc324911d1ef71b7127 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.spec.ts @@ -0,0 +1,184 @@ +import { BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createWizard } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; +import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-wizard-bescheid-versenden-container.component'; +import { BescheidWizardBescheidVersendenFormComponent } from './form/bescheid-wizard-bescheid-versenden-form.component'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './summary/bescheid-wizard-bescheid-versenden-summary.component'; + +describe('BescheidWizardBescheidVersendenComponent', () => { + let component: BescheidWizardBescheidVersendenContainerComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenContainerComponent>; + + const stepContentLayout: string = getDataTestIdOf('step-content-layout'); + const antragBescheidenStepTitleTestId: string = getDataTestIdOf('antrag-bescheiden-step-title'); + const dokumenteHochladenStepTitleTestId: string = getDataTestIdOf('dokumente-hochladen-step-title'); + const formTestId: string = getDataTestIdOf('bescheid-wizard-bescheid-versenden-form'); + const versendenSummaryTestId: string = getDataTestIdOf('bescheiden-result'); + + const bescheidResource: BescheidResource = createBescheidResource(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenContainerComponent, + MockComponent(StepContentLayoutComponent), + MockComponent(BescheidWizardStepTitleComponent), + MockComponent(BescheidWizardBescheidVersendenFormComponent), + MockComponent(BescheidWizardSummaryComponent), + MockComponent(BescheidWizardBescheidVersendenSummaryComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + const wizard: Wizard = createWizard(); + bescheidService.getWizard.mockReturnValue(of(wizard)); + + createComponent(); + + expect(component.wizard$).toBeObservable(singleColdCompleted(wizard)); + }); + + it('should set bescheid resource', () => { + component.bescheidResource = bescheidResource; + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + + it('should set send by', () => { + component.bescheidResource = bescheidResource; + + expect(bescheidService.setSendBy).toHaveBeenCalledWith(bescheidResource.sendBy); + }); + + describe('onSendBy', () => { + it('should call service', () => { + component.onSendBy(BescheidSendBy.MANUAL); + + expect(bescheidService.setSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + + describe('onStepChange', () => { + it('should call service', () => { + component.onStepChange(BescheidWizardStep.DokumenteHochladen); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); + }); + }); + }); + + describe('template', () => { + describe('step content layout', () => { + describe('output', () => { + describe('stepChange', () => { + it('should call handler', () => { + component.onStepChange = jest.fn(); + + triggerEvent({ + fixture, + elementSelector: stepContentLayout, + name: 'stepChange', + data: BescheidWizardStep.DokumenteHochladen, + }); + + expect(component.onStepChange).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); + }); + }); + }); + }); + + describe('antrag bescheid step title', () => { + it('should have inputs', () => { + const stepTitleComponent: BescheidWizardStepTitleComponent = + getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>(fixture, antragBescheidenStepTitleTestId); + + expect(stepTitleComponent.inactiveStep).toEqual(true); + }); + }); + + describe('dokumente hochladen step title', () => { + it('should have inputs', () => { + const stepTitleComponent: BescheidWizardStepTitleComponent = + getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>(fixture, dokumenteHochladenStepTitleTestId); + + expect(stepTitleComponent.inactiveStep).toEqual(true); + }); + }); + + describe('bescheid versenden form', () => { + it('should have inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const formComponent: BescheidWizardBescheidVersendenFormComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenFormComponent>(fixture, formTestId); + + expect(formComponent.bescheidResource).toEqual(component.bescheidResource); + }); + + describe('output', () => { + describe('sendBy', () => { + it('should call handler', () => { + component.onSendBy = jest.fn(); + + triggerEvent({ fixture, elementSelector: formTestId, name: 'sendBy', data: BescheidSendBy.MANUAL }); + + expect(component.onSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + }); + }); + + describe('bescheid versenden summary', () => { + it('should exists', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, versendenSummaryTestId); + }); + + it('should have inputs', () => { + const wizard: Wizard = createWizard(); + bescheidService.getWizard.mockReturnValue(of(wizard)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const summaryComponent: BescheidWizardBescheidVersendenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSummaryComponent>(fixture, versendenSummaryTestId); + + expect(summaryComponent.bescheidResource).toEqual(bescheidResource); + expect(summaryComponent.wizard).toEqual(wizard); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..70408d0b23afb74630248f0a140e07f8f0ccf60a --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component.ts @@ -0,0 +1,35 @@ +import { BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-container', + templateUrl: './bescheid-wizard-bescheid-versenden-container.component.html', +}) +export class BescheidWizardBescheidVersendenContainerComponent { + @Input() set bescheidResource(value: BescheidResource) { + this._bescheidResource = value; + this.bescheidService.setSendBy(value.sendBy); + } + + get bescheidResource(): BescheidResource { + return this._bescheidResource; + } + + private readonly bescheidService: BescheidService2 = inject(BescheidService2); + + public readonly wizard$: Observable<Wizard> = this.bescheidService.getWizard(); + + private _bescheidResource: BescheidResource; + + public readonly bescheidWizardStep = BescheidWizardStep; + + public onSendBy(sendBy: BescheidSendBy): void { + this.bescheidService.setSendBy(sendBy); + } + + public onStepChange(step: BescheidWizardStep): void { + this.bescheidService.setActiveStep(step); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b9ebc81cb5beee11821a7ecdba7e340bc1883fbe --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.html @@ -0,0 +1,33 @@ +<div + [formGroup]="formService.form" + class="mt-5 flex w-full max-w-72 flex-col gap-4" + role="radiogroup" + aria-level="Bescheid versenden" +> + @if (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN_UND_SENDEN) { + <ods-radio-button-card + label="Als neue Nachricht an den Antragsteller senden" + [value]="bescheidSendBy.NACHRICHT" + [name]="formServiceClass.FIELD_SEND_BY" + variant="bescheid_save" + [fullWidthText]="true" + (change)="changeSendBy(bescheidSendBy.NACHRICHT)" + data-test-id="send-to-antragsteller-button" + > + <ods-send-icon size="large"></ods-send-icon> + </ods-radio-button-card> + @if (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN) { + <ods-radio-button-card + label="Nur speichern" + [value]="bescheidSendBy.MANUAL" + [name]="formServiceClass.FIELD_SEND_BY" + variant="bescheid_save" + [fullWidthText]="true" + (change)="changeSendBy(bescheidSendBy.MANUAL)" + data-test-id="save-button" + > + <ods-save-icon size="large"></ods-save-icon> + </ods-radio-button-card> + } + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc058c004dce9f0e1c8e22efc3960498c03e0d90 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.spec.ts @@ -0,0 +1,177 @@ +import { BescheidLinkRel, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { RadioButtonCardComponent, SaveIconComponent, SendIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardBescheidVersendenFormComponent } from './bescheid-wizard-bescheid-versenden-form.component'; + +describe('BescheidWizardBescheidVersendenFormComponent', () => { + let component: BescheidWizardBescheidVersendenFormComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenFormComponent>; + + const sendBescheidMessageTestId: string = getDataTestIdOf('send-to-antragsteller-button'); + const saveBeschedTestId: string = getDataTestIdOf('save-button'); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new FormBuilder(), null); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenFormComponent, + MockComponent(RadioButtonCardComponent), + MockComponent(SendIconComponent), + MockComponent(SaveIconComponent), + HasLinkPipe, + ReactiveFormsModule, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('changeSendBy', () => { + it('should emit', () => { + component.sendBy.emit = jest.fn(); + + component.changeSendBy(BescheidSendBy.NACHRICHT); + + expect(component.sendBy.emit).toHaveBeenCalledWith(BescheidSendBy.NACHRICHT); + }); + }); + }); + + describe('template', () => { + describe('als neue nachricht radio button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, sendBescheidMessageTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, sendBescheidMessageTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + const radioButton: RadioButtonCardComponent = getElementComponentFromFixtureByCss<RadioButtonCardComponent>( + fixture, + sendBescheidMessageTestId, + ); + + expect(radioButton.value).toEqual(BescheidSendBy.NACHRICHT); + expect(radioButton.name).toEqual(BescheidFormService.FIELD_SEND_BY); + expect(radioButton.fullWidthText).toEqual(true); + }); + + describe('output', () => { + describe('change', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + component.changeSendBy = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: sendBescheidMessageTestId, name: 'change', data: BescheidSendBy.NACHRICHT }); + + expect(component.changeSendBy).toHaveBeenCalledWith(BescheidSendBy.NACHRICHT); + }); + }); + }); + }); + + describe('nur speichern radio button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN, BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missing bescheiden und send link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missing bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should NOT exists if on missinglinks', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, saveBeschedTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN, BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + const radioButton: RadioButtonCardComponent = getElementComponentFromFixtureByCss<RadioButtonCardComponent>( + fixture, + saveBeschedTestId, + ); + + expect(radioButton.value).toEqual(BescheidSendBy.MANUAL); + expect(radioButton.name).toEqual(BescheidFormService.FIELD_SEND_BY); + expect(radioButton.fullWidthText).toEqual(true); + }); + + describe('output', () => { + describe('change', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([ + BescheidLinkRel.BESCHEIDEN_UND_SENDEN, + BescheidLinkRel.BESCHEIDEN, + ]); + component.changeSendBy = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: saveBeschedTestId, name: 'change', data: BescheidSendBy.MANUAL }); + + expect(component.changeSendBy).toHaveBeenCalledWith(BescheidSendBy.MANUAL); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..de149b55c7e9e215a9d3284fe4a441a5bbf19c30 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component.ts @@ -0,0 +1,23 @@ +import { BescheidLinkRel, BescheidResource, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-form', + templateUrl: './bescheid-wizard-bescheid-versenden-form.component.html', +}) +export class BescheidWizardBescheidVersendenFormComponent { + @Input() bescheidResource: BescheidResource; + + @Output() sendBy: EventEmitter<BescheidSendBy> = new EventEmitter<BescheidSendBy>(); + + public readonly formService: BescheidFormService = inject(BescheidFormService); + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly formServiceClass = BescheidFormService; + public readonly bescheidSendBy = BescheidSendBy; + + public changeSendBy(sendBy: BescheidSendBy): void { + this.sendBy.emit(sendBy); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html new file mode 100644 index 0000000000000000000000000000000000000000..be23ec4fce623714a97ce620605b74fd7b09a9ae --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.html @@ -0,0 +1,15 @@ +<section tabindex="0" class="h-full"> + @if (wizard.sendBy === bescheidSendBy.MANUAL) { + <alfa-bescheid-wizard-bescheid-versenden-speichern + [bescheidResource]="bescheidResource" + data-test-id="bescheid-versenden-speichern" + ></alfa-bescheid-wizard-bescheid-versenden-speichern> + } + @if (wizard.sendBy === bescheidSendBy.NACHRICHT) { + <alfa-bescheid-wizard-bescheid-versenden-senden + [bescheidResource]="bescheidResource" + [wizard]="wizard" + data-test-id="bescheid-versenden-senden" + ></alfa-bescheid-wizard-bescheid-versenden-senden> + } +</section> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..83b9df452df3cde3a70ef32cc1cc032123f43cd5 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.spec.ts @@ -0,0 +1,105 @@ +import { BescheidResource, BescheidSendBy } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidResource, createWizard } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './bescheid-wizard-bescheid-versenden-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './senden/bescheid-wizard-bescheid-versenden-senden.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './speichern/bescheid-wizard-bescheid-versenden-speichern.component'; + +describe('BescheidWizardBescheidVersendenSummaryComponent', () => { + let component: BescheidWizardBescheidVersendenSummaryComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSummaryComponent>; + + const bescheidVersendenSpeichernTestId: string = getDataTestIdOf('bescheid-versenden-speichern'); + const bescheidVersendenSendenTestId: string = getDataTestIdOf('bescheid-versenden-senden'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSummaryComponent, + MockComponent(BescheidWizardBescheidVersendenSpeichernComponent), + MockComponent(BescheidWizardBescheidVersendenSendenComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSummaryComponent); + component = fixture.componentInstance; + component.wizard = createWizard(); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + + describe('bescheid versenden speichern', () => { + it('should exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidVersendenSpeichernTestId); + }); + + it('should NOT exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidVersendenSpeichernTestId); + }); + + it('should have inputs', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const speichernComponent: BescheidWizardBescheidVersendenSpeichernComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSpeichernComponent>( + fixture, + bescheidVersendenSpeichernTestId, + ); + + expect(speichernComponent.bescheidResource).toEqual(bescheidResource); + }); + }); + + describe('bescheid versenden senden', () => { + it('should exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidVersendenSendenTestId); + }); + + it('should NOT exists', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.MANUAL }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidVersendenSendenTestId); + }); + + it('should have inputs', () => { + component.wizard = { ...createWizard(), sendBy: BescheidSendBy.NACHRICHT }; + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const sendenComponent: BescheidWizardBescheidVersendenSendenComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenSendenComponent>( + fixture, + bescheidVersendenSendenTestId, + ); + + expect(sendenComponent.bescheidResource).toEqual(bescheidResource); + expect(sendenComponent.wizard).toEqual(component.wizard); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..da53ce4b8adedd2adeb59a8829653b85d983c3fa --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component.ts @@ -0,0 +1,14 @@ +import { BescheidLinkRel, BescheidResource, BescheidSendBy, Wizard } from '@alfa-client/bescheid-shared'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-summary', + templateUrl: './bescheid-wizard-bescheid-versenden-summary.component.html', +}) +export class BescheidWizardBescheidVersendenSummaryComponent { + @Input() bescheidResource: BescheidResource; + @Input() wizard: Wizard; + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly bescheidSendBy = BescheidSendBy; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0631bc2d3607a669dc82fd6185fce16cc3593113 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.html @@ -0,0 +1,45 @@ +<div class="flex h-full flex-col justify-between"> + <div> + <div data-test-id="bescheid-nachricht-an-antragsteller"> + <h3 class="mb-3 font-medium text-primary">Neue Nachricht</h3> + @if (wizard?.empfaenger) { + <p data-test-id="bescheid-nachricht-empfaenger" class="mb-2 text-sm font-medium">An: {{ wizard.empfaenger }}</p> + } + </div> + <div [formGroup]="formService.form"> + <ods-text-editor + [formControlName]="formServiceClass.FIELD_NACHRICHT_SUBJECT" + label="Betreff" + placeholder="Betreff hier eingeben" + [focus]="focusBetreff" + [isRequired]="true" + > + </ods-text-editor> + + <ods-textarea-editor + [formControlName]="formServiceClass.FIELD_NACHRICHT_TEXT" + label="Text" + placeholder="Nachrichtentext hier eingeben" + [focus]="focusNachricht" + [isRequired]="true" + > + </ods-textarea-editor> + </div> + + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="false" + data-test-id="bescheid-versenden-dokumente" + ></alfa-bescheid-wizard-dokumente-hochladen-summary> + </div> + @if ( + (bescheidResource | hasLink: bescheidLinkRel.UPDATE) || (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN_UND_SENDEN) + ) { + <ods-button-with-spinner + class="self-end" + [stateResource]="submitStateResource$ | async" + text="Bescheid senden" + (clickEmitter)="submit()" + data-test-id="send-button" + ></ods-button-with-spinner> + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f90d5f49aead888a0b1eff751476d748859fe07 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.spec.ts @@ -0,0 +1,314 @@ +import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + Mock, + notExistsAsHtmlElement, + triggerEvent, + useFromMock, +} from '@alfa-client/test-utils'; +import { DialogRef } from '@angular/cdk/dialog'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { expect } from '@jest/globals'; +import { ButtonWithSpinnerComponent, TextareaEditorComponent, TextEditorComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createWizard } from '../../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../../tech-shared/test/error'; +import { singleColdCompleted } from '../../../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../../../bescheid.formservice'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from '../../../dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './bescheid-wizard-bescheid-versenden-senden.component'; + +describe('BescheidWizardBescheidVersendenSendenComponent', () => { + let component: BescheidWizardBescheidVersendenSendenComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSendenComponent>; + + const dokumenteTestsId: string = getDataTestIdOf('bescheid-versenden-dokumente'); + const submitButtonTestId: string = getDataTestIdOf('send-button'); + const empfaengerTestId: string = getDataTestIdOf('bescheid-nachricht-empfaenger'); + + let bescheidService: Mock<BescheidService2>; + let formService: BescheidFormService; + let dialogRef: Mock<DialogRef<BescheidWizardDialogResult>>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + formService = new BescheidFormService(new FormBuilder(), useFromMock(bescheidService)); + formService.submit = jest.fn(); + dialogRef = mock(DialogRef<BescheidWizardDialogResult>); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSendenComponent, + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(ButtonWithSpinnerComponent), + MockComponent(TextareaEditorComponent), + MockComponent(TextEditorComponent), + HasLinkPipe, + ReactiveFormsModule, + ], + providers: [ + { provide: BescheidFormService, useValue: formService }, + { provide: DialogRef<BescheidWizardDialogResult>, useValue: dialogRef }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSendenComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + beforeEach(() => { + formService.submit = jest.fn().mockReturnValue(EMPTY); + component._resetFocus = jest.fn(); + }); + + it('should reset focus', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._resetFocus).toHaveBeenCalled(); + }); + + it('should call form service', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should close dialog', () => { + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).toHaveBeenCalledWith({ reloadVorgang: true } as BescheidWizardDialogResult); + }); + + it('should NOT close dialog on pending send', () => { + formService.submit = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should NOT close dialog on failed send', () => { + formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should focus to first invalid control', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).toHaveBeenCalled(); + }); + + it('should NOT focus to first invalid control on pending submit', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).not.toHaveBeenCalled(); + }); + + it('should NOT focus to first invalid control on successful submit', () => { + component._focusToFirstInvalidControl = jest.fn(); + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(component._focusToFirstInvalidControl).not.toHaveBeenCalled(); + }); + }); + + describe('_focusToFirstInvalidControl', () => { + beforeEach(() => { + component._resetFocus = jest.fn(); + + formService.isBetreffInvalid = jest.fn(); + formService.isNachrichtInvalid = jest.fn(); + }); + + it('should check betreff', () => { + component._focusToFirstInvalidControl(); + + expect(formService.isBetreffInvalid).toHaveBeenCalled(); + }); + + it('should check nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(formService.isNachrichtInvalid).toHaveBeenCalled(); + }); + + it('should NOT check nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(formService.isNachrichtInvalid).not.toHaveBeenCalled(); + }); + + it('should focus betreff', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(component.focusBetreff).toBe(true); + }); + + it('should NOT focus betreff', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(component.focusBetreff).toBe(false); + }); + + it('should focus nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(false); + formService.isNachrichtInvalid = jest.fn().mockReturnValue(true); + + component._focusToFirstInvalidControl(); + + expect(component.focusNachricht).toBe(true); + }); + + it('should NOT focus nachricht', () => { + formService.isBetreffInvalid = jest.fn().mockReturnValue(true); + formService.isNachrichtInvalid = jest.fn().mockReturnValue(false); + + component._focusToFirstInvalidControl(); + + expect(component.focusNachricht).toBe(false); + }); + }); + }); + + describe('template', () => { + describe('empfaenger', () => { + it('should exists', () => { + component.wizard = createWizard(); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, empfaengerTestId); + }); + + it('should NOT exits', () => { + component.wizard = { ...createWizard(), empfaenger: null }; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, empfaengerTestId); + }); + }); + + describe('dokumente hochladen summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should have inputs', () => { + const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + + expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + }); + + describe('submit button', () => { + it('should exists with update link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should exists with bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should NOT exists on missing links', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, submitButtonTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + const submitCommandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(submitCommandStateResource); + + fixture.detectChanges(); + const submitButtonComponent: ButtonWithSpinnerComponent = + getElementComponentFromFixtureByCss<ButtonWithSpinnerComponent>(fixture, submitButtonTestId); + + expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN_UND_SENDEN]); + component.submit = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: submitButtonTestId, name: 'clickEmitter' }); + + expect(component.submit).toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d03f994ed85918c979d7101e8d6b4ec14a59ee3 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component.ts @@ -0,0 +1,48 @@ +import { BescheidLinkRel, BescheidResource, BescheidWizardDialogResult, Wizard } from '@alfa-client/bescheid-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone, tapOnFailedCommand } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { DialogRef } from '@angular/cdk/dialog'; +import { Component, inject, Input } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { BescheidFormService } from '../../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-senden', + templateUrl: './bescheid-wizard-bescheid-versenden-senden.component.html', +}) +export class BescheidWizardBescheidVersendenSendenComponent { + @Input() bescheidResource: BescheidResource; + @Input() wizard: Wizard; + + public readonly formService: BescheidFormService = inject(BescheidFormService); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + public focusBetreff: boolean = false; + public focusNachricht: boolean = false; + + public readonly bescheidLinkRel = BescheidLinkRel; + public readonly formServiceClass = BescheidFormService; + + public submit(): void { + this._resetFocus(); + this.submitStateResource$ = this.formService.submit().pipe( + tapOnFailedCommand(() => this._focusToFirstInvalidControl()), + tapOnCommandSuccessfullyDone(() => this.dialogRef.close({ reloadVorgang: true })), + ); + } + + _focusToFirstInvalidControl(): void { + if (this.formService.isBetreffInvalid()) { + this.focusBetreff = true; + } else if (this.formService.isNachrichtInvalid()) { + this.focusNachricht = true; + } + } + + _resetFocus(): void { + this.focusBetreff = false; + this.focusNachricht = false; + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html new file mode 100644 index 0000000000000000000000000000000000000000..a19c2b53db33741056c2cc6844e7b83536512f5d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.html @@ -0,0 +1,20 @@ +<div class="flex h-full flex-col justify-between"> + <div> + <alfa-bescheid-wizard-antrag-bescheiden-summary></alfa-bescheid-wizard-antrag-bescheiden-summary> + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="false" + data-test-id="bescheid-versenden-dokumente" + ></alfa-bescheid-wizard-dokumente-hochladen-summary> + <p class="mb-8 text-base font-normal text-text">Der Bescheid muss manuell versendet werden.</p> + </div> + + @if ((bescheidResource | hasLink: bescheidLinkRel.UPDATE) || (bescheidResource | hasLink: bescheidLinkRel.BESCHEIDEN)) { + <ods-button-with-spinner + class="self-end" + [stateResource]="submitStateResource$ | async" + text="Antrag bescheiden und speichern" + (clickEmitter)="submit()" + data-test-id="confirm-and-save-button" + ></ods-button-with-spinner> + } +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4382985e2f96fcff9aee1b1604a7622641202420 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.spec.ts @@ -0,0 +1,186 @@ +import { BescheidLinkRel, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + Mock, + mock, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { DialogRef } from '@angular/cdk/dialog'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { ButtonWithSpinnerComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { createBescheidResource } from '../../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../../tech-shared/test/error'; +import { singleColdCompleted } from '../../../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../../../bescheid.formservice'; +import { BescheidWizardAntragBescheidenSummaryComponent } from '../../../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from '../../../dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './bescheid-wizard-bescheid-versenden-speichern.component'; + +describe('BescheidWizardBescheidVersendenSpeichernComponent', () => { + let component: BescheidWizardBescheidVersendenSpeichernComponent; + let fixture: ComponentFixture<BescheidWizardBescheidVersendenSpeichernComponent>; + + const dokumenteTestsId: string = getDataTestIdOf('bescheid-versenden-dokumente'); + const submitButtonTestId: string = getDataTestIdOf('confirm-and-save-button'); + + let formService: Mock<BescheidFormService>; + let dialogRef: Mock<DialogRef<BescheidWizardDialogResult>>; + + beforeEach(() => { + formService = mock(BescheidFormService); + formService.submit = jest.fn(); + dialogRef = mock(DialogRef<BescheidWizardDialogResult>); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardBescheidVersendenSpeichernComponent, + MockComponent(BescheidWizardAntragBescheidenSummaryComponent), + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(ButtonWithSpinnerComponent), + HasLinkPipe, + ], + providers: [ + { provide: BescheidFormService, useValue: formService }, + { provide: DialogRef<BescheidWizardDialogResult>, useValue: dialogRef }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardBescheidVersendenSpeichernComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.submitStateResource$).toBeObservable(singleColdCompleted(createEmptyStateResource())); + }); + + describe('submit', () => { + beforeEach(() => { + formService.submit.mockReturnValue(EMPTY); + }); + + it('should call form service', () => { + component.submit(); + component.submitStateResource$.subscribe(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should close dialog', () => { + formService.submit.mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).toHaveBeenCalled(); + }); + + it('should NOT close dialog on pending send', () => { + formService.submit.mockReturnValue(of(createLoadingStateResource())); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + + it('should NOT close dialog on failed send', () => { + formService.submit.mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + component.submit(); + component.submitStateResource$.subscribe(); + + expect(dialogRef.close).not.toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('dokumente hochladen summary', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should have inputs', () => { + const dokumentComponent: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>(fixture, dokumenteTestsId); + + expect(dokumentComponent.isBescheidDocumentMissing).toBe(false); + }); + + describe('submit button', () => { + it('should exists with update link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should exists with bescheiden link', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, dokumenteTestsId); + }); + + it('should NOT exists on missing links', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, submitButtonTestId); + }); + + it('should have inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + const submitCommandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(submitCommandStateResource); + + fixture.detectChanges(); + const submitButtonComponent: ButtonWithSpinnerComponent = + getElementComponentFromFixtureByCss<ButtonWithSpinnerComponent>(fixture, submitButtonTestId); + + expect(submitButtonComponent.stateResource).toEqual(submitCommandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.BESCHEIDEN]); + component.submit = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: submitButtonTestId, name: 'clickEmitter' }); + + expect(component.submit).toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7ee9b36506b3b783c70df4e5238eb690a7bb0c2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component.ts @@ -0,0 +1,28 @@ +import { BescheidLinkRel, BescheidResource, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { DialogRef } from '@angular/cdk/dialog'; +import { Component, inject, Input } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { BescheidFormService } from '../../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-bescheid-versenden-speichern', + templateUrl: './bescheid-wizard-bescheid-versenden-speichern.component.html', +}) +export class BescheidWizardBescheidVersendenSpeichernComponent { + @Input() bescheidResource: BescheidResource; + + private readonly formService: BescheidFormService = inject(BescheidFormService); + private readonly dialogRef = inject(DialogRef<BescheidWizardDialogResult>); + + public submitStateResource$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>()); + + public readonly bescheidLinkRel = BescheidLinkRel; + + public submit(): void { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.dialogRef.close({ reloadVorgang: true }))); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html index c7041e1f2afb7f84f09f5f6591815279ae82a87f..178a0f574555303c350994f4696c6e9e42f1fc52 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.html @@ -32,18 +32,27 @@ <form [formGroup]="formService.form" class="h-full"> <div class="grid h-full"> - <alfa-bescheid-wizard-antrag-bescheiden - *ngIf="activeStep === bescheidWizardStep.AntragBescheiden" - [vorgangWithEingangResource]="vorgangWithEingangResource" - [bescheidResource]="bescheidStateResource.resource" - [submitStateResource]="submitStateResource" - (weiterClickEmitter)="weiterClickEmitter.emit($event)" - (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" - data-test-id="antrag-bescheiden-step" - ></alfa-bescheid-wizard-antrag-bescheiden> - <alfa-bescheid-wizard-dokumente-hochladen - *ngIf="activeStep === bescheidWizardStep.DokumenteHochladen" - data-test-id="dokumente-hochladen-step" - ></alfa-bescheid-wizard-dokumente-hochladen> + @switch (activeStep) { + @case (bescheidWizardStep.AntragBescheiden) { + <alfa-bescheid-wizard-antrag-bescheiden-container + [vorgangWithEingangResource]="vorgangWithEingangResource" + [bescheidResource]="bescheidResource" + (vorgangAbgeschlossen)="vorgangAbgeschlossen.emit()" + data-test-id="antrag-bescheiden-step" + ></alfa-bescheid-wizard-antrag-bescheiden-container> + } + @case (bescheidWizardStep.DokumenteHochladen) { + <alfa-bescheid-wizard-dokumente-hochladen-container + [bescheidResource]="bescheidResource" + data-test-id="dokumente-hochladen-step" + ></alfa-bescheid-wizard-dokumente-hochladen-container> + } + @case (bescheidWizardStep.BescheidVersenden) { + <alfa-bescheid-wizard-bescheid-versenden-container + [bescheidResource]="bescheidResource" + data-test-id="bescheid-versenden-step" + ></alfa-bescheid-wizard-bescheid-versenden-container> + } + } </div> </form> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts index 0f84df6c0fb722b9b4c8cded349b71edf8b039a9..c818a3613876e7b6533d508d5714fbbfa5881330 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.spec.ts @@ -21,12 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { HasLinkPipe, StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + HasLinkPipe, + StateResource, +} from '@alfa-client/tech-shared'; import { - Mock, existsAsHtmlElement, - getElementFromFixtureByType, + getElementComponentFromFixtureByCss, + Mock, mock, notExistsAsHtmlElement, triggerEvent, @@ -37,15 +43,18 @@ import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared'; import { EventEmitter } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; +import { expect } from '@jest/globals'; import { MockComponent } from 'ng-mocks'; -import { createBescheidStateResource } from '../../../../../bescheid-shared/src/test/bescheid'; -import { createSuccessfullyDoneCommandStateResource } from '../../../../../command-shared/test/command'; +import { BescheidService2 } from '../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidResource, createBescheidStateResource } from '../../../../../bescheid-shared/src/test/bescheid'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../tech-shared/test/error'; import { createVorgangWithEingangResource } from '../../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from '../bescheid.formservice'; -import { BescheidWizardAntragBescheidenComponent } from './antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component'; import { BescheidWizardComponent } from './bescheid-wizard.component'; -import { BescheidWizardDokumenteHochladenComponent } from './dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component'; import { BescheidWizardStepperComponent } from './stepper/bescheid-wizard-stepper.component'; describe('BescheidWizardComponent', () => { @@ -55,12 +64,13 @@ describe('BescheidWizardComponent', () => { const bescheidLoadingSpinner: string = getDataTestIdOf('bescheid-loading-spinner'); const antragBescheidenStep: string = getDataTestIdOf('antrag-bescheiden-step'); const dokumenteHochladenStep: string = getDataTestIdOf('dokumente-hochladen-step'); + const bescheidVersendenStepTestId: string = getDataTestIdOf('bescheid-versenden-step'); - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let formService: BescheidFormService; beforeEach(() => { - bescheidService = mock(BescheidService); + bescheidService = mock(BescheidService2); formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(bescheidService)); }); @@ -69,8 +79,9 @@ describe('BescheidWizardComponent', () => { declarations: [ BescheidWizardComponent, MockComponent(BescheidWizardStepperComponent), - MockComponent(BescheidWizardAntragBescheidenComponent), - MockComponent(BescheidWizardDokumenteHochladenComponent), + MockComponent(BescheidWizardAntragBescheidenContainerComponent), + MockComponent(BescheidWizardDokumenteHochladenContainerComponent), + MockComponent(BescheidWizardBescheidVersendenContainerComponent), MockComponent(SpinnerComponent), HasLinkPipe, ], @@ -85,7 +96,6 @@ describe('BescheidWizardComponent', () => { fixture = TestBed.createComponent(BescheidWizardComponent); component = fixture.componentInstance; - component.weiterClickEmitter = useFromMock(mock(EventEmitter<BescheidWizardStep>)); component.vorgangAbgeschlossen = useFromMock(mock(EventEmitter<void>)); fixture.detectChanges(); }); @@ -117,6 +127,30 @@ describe('BescheidWizardComponent', () => { expect(component.bescheidStateResource).toEqual(component.bescheidStateResource); }); + + it('should set bescheid resource if loaded', () => { + component.bescheidStateResource = createBescheidStateResource(); + + expect(component.bescheidResource).toEqual(component.bescheidStateResource.resource); + }); + + it('should NOT set bescheid resource on pending load', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.bescheidStateResource = createLoadingStateResource(); + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + + it('should NOT set bescheid resource on failed load', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.bescheidStateResource = createErrorStateResource(createProblemDetail()); + + expect(component.bescheidResource).toEqual(bescheidResource); + }); }); }); @@ -125,7 +159,7 @@ describe('BescheidWizardComponent', () => { component.bescheidStateResource = createBescheidStateResource(); }); - describe('ozgcloud-spinner', () => { + describe('spinner', () => { it('should exists', () => { component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); component.bescheidStateResource = createEmptyStateResource(); @@ -153,110 +187,126 @@ describe('BescheidWizardComponent', () => { notExistsAsHtmlElement(fixture, bescheidLoadingSpinner); }); - describe('input', () => { - it('should set stateResource', () => { - component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); - component.bescheidStateResource = createEmptyStateResource(); + it('should have been called with inputs', () => { + component.vorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); + component.bescheidStateResource = createEmptyStateResource(); - fixture.detectChanges(); + fixture.detectChanges(); + const spinnerComponent: SpinnerComponent = getElementComponentFromFixtureByCss<SpinnerComponent>( + fixture, + bescheidLoadingSpinner, + ); - expect(getElementFromFixtureByType(fixture, SpinnerComponent).stateResource).toEqual(component.bescheidStateResource); - }); + expect(spinnerComponent.stateResource).toEqual(component.bescheidStateResource); }); }); - describe('alfa-bescheid-wizard-antrag-bescheiden', () => { - function getElementComponent(): BescheidWizardAntragBescheidenComponent { - return getElementFromFixtureByType(fixture, BescheidWizardAntragBescheidenComponent); - } - - it('should show', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); + describe('antrag bescheiden', () => { + it('should exists', () => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); existsAsHtmlElement(fixture, antragBescheidenStep); }); - it.each([2, 3])('should NOT show in step %d', (step: number) => { + it.each([2, 3])('should NOT exists in step %d', (step: number) => { givenActiveStep(step); - givenLoadedBescheidStateResrouce(); notExistsAsHtmlElement(fixture, antragBescheidenStep); }); - describe('input', () => { - it('should set vorgangWithEingangResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - component.vorgangWithEingangResource = createVorgangWithEingangResource(); - - fixture.detectChanges(); + it('should have been called with inputs', () => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); + givenLoadedBescheidStateResource(); + givenLoadedBescheidStateResource(); + component.vorgangWithEingangResource = createVorgangWithEingangResource(); - expect(getElementComponent().vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); - }); + fixture.detectChanges(); - it('should set bescheidResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); + const antragBescheidenComponent: BescheidWizardAntragBescheidenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardAntragBescheidenContainerComponent>(fixture, antragBescheidenStep); - fixture.detectChanges(); + expect(antragBescheidenComponent.vorgangWithEingangResource).toBe(component.vorgangWithEingangResource); + expect(antragBescheidenComponent.bescheidResource).toEqual(component.bescheidResource); + }); - expect(getElementComponent().bescheidResource).toEqual(component.bescheidStateResource.resource); + describe('output', () => { + beforeEach(() => { + givenActiveStep(BescheidWizardStep.AntragBescheiden); + givenLoadedBescheidStateResource(); }); - it('should set submitStateResource', () => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - component.submitStateResource = createSuccessfullyDoneCommandStateResource(); + describe('vorgangAbgeschlossen', () => { + it('should emit', () => { + triggerEvent({ + fixture, + name: 'vorgangAbgeschlossen', + elementSelector: antragBescheidenStep, + }); - fixture.detectChanges(); - - expect(getElementComponent().submitStateResource).toEqual(component.submitStateResource); + expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); + }); }); }); + }); - describe('output', () => { - beforeEach(() => { - givenActiveStep(1); - givenLoadedBescheidStateResrouce(); - }); + describe('dokumente hochladen', () => { + beforeEach(() => { + givenActiveStep(BescheidWizardStep.DokumenteHochladen); + fixture.detectChanges(); + }); - it('should emit weiterClickEmitter', () => { - triggerEvent({ - fixture, - name: 'weiterClickEmitter', - elementSelector: antragBescheidenStep, - data: BescheidWizardStep.DokumenteHochladen, - }); + it('should exists', () => { + existsAsHtmlElement(fixture, dokumenteHochladenStep); + }); - expect(component.weiterClickEmitter.emit).toHaveBeenCalledWith(BescheidWizardStep.DokumenteHochladen); - }); + it.each([1, 3])('should NOT exists in step %d', (step: number) => { + givenActiveStep(step); + + notExistsAsHtmlElement(fixture, dokumenteHochladenStep); + }); - it('should emit vorgangAbgeschlossen', () => { - triggerEvent({ + it('should have been called with inputs', () => { + givenActiveStep(BescheidWizardStep.DokumenteHochladen); + + fixture.detectChanges(); + + const dokumenteHochladenComponent: BescheidWizardDokumenteHochladenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenContainerComponent>( fixture, - name: 'vorgangAbgeschlossen', - elementSelector: antragBescheidenStep, - }); + dokumenteHochladenStep, + ); - expect(component.vorgangAbgeschlossen.emit).toHaveBeenCalled(); - }); + expect(dokumenteHochladenComponent.bescheidResource).toEqual(component.bescheidResource); }); }); - describe('alfa-bescheid-wizard-dokumente-hochladen', () => { - it('should show', () => { - givenActiveStep(2); - givenLoadedBescheidStateResrouce(); + describe('bescheid versenden', () => { + beforeEach(() => { + component.activeStep = BescheidWizardStep.BescheidVersenden; + fixture.detectChanges(); + }); - existsAsHtmlElement(fixture, dokumenteHochladenStep); + it('should exists', () => { + existsAsHtmlElement(fixture, bescheidVersendenStepTestId); }); - it.each([1, 3])('should NOT show in step %d', (step: number) => { + it.each([1, 2])('should NOT exists in step %d', (step: number) => { givenActiveStep(step); - givenLoadedBescheidStateResrouce(); - notExistsAsHtmlElement(fixture, dokumenteHochladenStep); + notExistsAsHtmlElement(fixture, bescheidVersendenStepTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidStateResource = createBescheidStateResource(); + + fixture.detectChanges(); + const bescheidVersendenComponent: BescheidWizardBescheidVersendenContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardBescheidVersendenContainerComponent>( + fixture, + bescheidVersendenStepTestId, + ); + + expect(bescheidVersendenComponent.bescheidResource).toEqual(component.bescheidResource); }); }); }); @@ -266,10 +316,11 @@ describe('BescheidWizardComponent', () => { fixture.detectChanges(); } - function givenLoadedBescheidStateResrouce(): StateResource<BescheidResource> { - const resource: StateResource<BescheidResource> = createBescheidStateResource(); - component.bescheidStateResource = resource; + function givenLoadedBescheidStateResource(): StateResource<BescheidResource> { + const stateResource: StateResource<BescheidResource> = createBescheidStateResource(); + component.bescheidStateResource = stateResource; + component.bescheidResource = stateResource.resource; fixture.detectChanges(); - return resource; + return stateResource; } }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts index bbeb757952ace3785c2fafbd24e0e80f862b9959..d601c79c77cbfe839e4563419004d503810b012e 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component.ts @@ -22,10 +22,9 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { StateResource, isLoaded } from '@alfa-client/tech-shared'; +import { isLoaded, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Resource } from '@ngxp/rest'; import { BescheidFormService } from '../bescheid.formservice'; @Component({ @@ -38,6 +37,7 @@ export class BescheidWizardComponent { @Input() set bescheidStateResource(value: StateResource<BescheidResource>) { if (isLoaded(value)) { this.formService.patchValues(value.resource); + this.bescheidResource = value.resource; } this._bescheidStateResource = value; } @@ -46,12 +46,11 @@ export class BescheidWizardComponent { return this._bescheidStateResource; } - @Input() activeStep: number; - @Input() submitStateResource: StateResource<Resource>; + @Input() activeStep: BescheidWizardStep; - @Output() weiterClickEmitter: EventEmitter<BescheidWizardStep> = new EventEmitter<BescheidWizardStep>(); @Output() vorgangAbgeschlossen: EventEmitter<void> = new EventEmitter<void>(); + public bescheidResource: BescheidResource; private _bescheidStateResource: StateResource<BescheidResource>; public readonly vorgangWithEingangLinkRel = VorgangWithEingangLinkRel; diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts index 2e4c13bcb369d85dba5df9be85adff92e41bb760..5dfde26e4da2a928be6046e7c14d50b60790900a 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.spec.ts @@ -21,36 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidService } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; -import { StateResource, createErrorStateResource } from '@alfa-client/tech-shared'; -import { - DialogRefMock, - Mock, - createDialogRefMock, - existsAsHtmlElement, - getElementComponentFromFixtureByCss, - mock, - triggerEvent, -} from '@alfa-client/test-utils'; +import { createErrorStateResource, StateResource } from '@alfa-client/tech-shared'; +import { createDialogRefMock, DialogRefMock, existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent, } from '@alfa-client/test-utils'; import { OzgcloudStrokedButtonWithSpinnerComponent } from '@alfa-client/ui'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; import { MockComponent } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; -import { - createCommandStateResource, - createSuccessfullyDoneCommandStateResource, -} from '../../../../../../command-shared/test/command'; +import { createCommandStateResource, createSuccessfullyDoneCommandStateResource, } from '../../../../../../command-shared/test/command'; import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; import { createApiError } from '../../../../../../tech-shared/test/error'; import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; import { BescheidFormService } from '../../bescheid.formservice'; -import { - BescheidWizardCancelDialogContainerComponent, - CancelWizardDialogData, -} from './bescheid-wizard-cancel-dialog-container.component'; +import { BescheidWizardCancelDialogContainerComponent, CancelWizardDialogData, } from './bescheid-wizard-cancel-dialog-container.component'; describe('BescheidWizardCancelDialogContainerComponent', () => { let component: BescheidWizardCancelDialogContainerComponent; @@ -64,21 +51,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }; let formService: Mock<BescheidFormService>; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; let dialogRef: DialogRefMock; beforeEach(() => { - formService = { ...mock(BescheidFormService), submit: jest.fn().mockReturnValue(EMPTY) }; - bescheidService = { ...mock(BescheidService), bescheidVerwerfen: jest.fn().mockReturnValue(EMPTY) }; + formService = mock(BescheidFormService); + formService.submit = jest.fn().mockReturnValue(EMPTY); + bescheidService = mock(BescheidService2); + bescheidService.deleteBescheid.mockReturnValue(EMPTY); dialogRef = createDialogRefMock(); }); - beforeEach(async () => { + async function configureTestingModule(dialogData: CancelWizardDialogData) { await TestBed.configureTestingModule({ declarations: [BescheidWizardCancelDialogContainerComponent, MockComponent(OzgcloudStrokedButtonWithSpinnerComponent)], providers: [ { - provide: BescheidService, + provide: BescheidService2, useValue: bescheidService, }, { @@ -99,13 +88,33 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { fixture = TestBed.createComponent(BescheidWizardCancelDialogContainerComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); + } - it('should create', () => { - expect(component).toBeTruthy(); + beforeEach(async () => { + await configureTestingModule(dialogData); }); describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should lock bescheid sending', () => { + component.ngOnInit(); + + expect(bescheidService.lockBescheidSending).toHaveBeenCalled(); + }); + }); + + describe('ngOnDestroy', () => { + it('should unlock bescheid sending', () => { + component.ngOnDestroy(); + + expect(bescheidService.unlockBescheidSending).toHaveBeenCalled(); + }); + }); + describe('save', () => { beforeEach(() => { component.closeDialogWithWizard = jest.fn(); @@ -117,7 +126,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(formService.submit).toHaveBeenCalled(); }); - it('should emit save command state resource', () => { + it('should set save state resource', () => { const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -126,7 +135,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.saveStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); }); - it('should handle successfully saved bescheid', () => { + it('should close dialog with wizard', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -136,7 +145,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.closeDialogWithWizard).toHaveBeenCalled(); }); - it('should NOT handle successfully saved bescheid', () => { + it('should NOT close dialog with wizard', () => { const commandStateResource: StateResource<CommandResource> = createErrorStateResource(createApiError()); formService.submit = jest.fn().mockReturnValue(of(commandStateResource)); @@ -155,20 +164,20 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should delete bescheid', () => { component.cancel(); - expect(bescheidService.bescheidVerwerfen).toHaveBeenCalled(); + expect(bescheidService.deleteBescheid).toHaveBeenCalled(); }); - it('should NOT delete bescheid', () => { - component.bescheidResource = null; + it('should NOT delete bescheid', async () => { + await configureTestingModule({} as CancelWizardDialogData); component.cancel(); - expect(bescheidService.bescheidVerwerfen).not.toHaveBeenCalled(); + expect(bescheidService.deleteBescheid).not.toHaveBeenCalled(); }); - it('should emit delete command state resource', () => { + it('should set delete command state resource', () => { const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); @@ -177,7 +186,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should close dialog on success', () => { const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); component.deleteStateResource$.subscribe(); @@ -187,7 +196,7 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { it('should NOT close dialog on error', () => { const commandStateResource: StateResource<CommandResource> = createErrorStateResource(createApiError()); - bescheidService.bescheidVerwerfen = jest.fn().mockReturnValue(of(commandStateResource)); + bescheidService.deleteBescheid = jest.fn().mockReturnValue(of(commandStateResource)); component.cancel(); component.deleteStateResource$.subscribe(); @@ -195,8 +204,9 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { expect(component.closeDialogWithWizard).not.toHaveBeenCalled(); }); - it('should close dialog with cancel result on non existing bescheid', () => { - component.bescheidResource = null; + it('should close dialog with cancel result on non existing bescheid', async () => { + await configureTestingModule({} as CancelWizardDialogData); + component.closeDialogWithWizard = jest.fn(); component.cancel(); @@ -214,25 +224,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }); describe('template', () => { - describe('ozgcloud-stroked-button-with-spinner Entwurf speichern', () => { - it('should show', () => { + describe('save button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, speichernButton); }); - describe('input', () => { - it('should set stateResource', () => { - const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - component.saveStateResource$ = of(commandStateResource); + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + component.saveStateResource$ = of(commandStateResource); - const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( - fixture, - speichernButton, - ); + const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( + fixture, + speichernButton, + ); - fixture.detectChanges(); + fixture.detectChanges(); - expect(elementComponent.stateResource).toBe(commandStateResource); - }); + expect(elementComponent.stateResource).toBe(commandStateResource); }); describe('output', () => { @@ -246,25 +254,23 @@ describe('BescheidWizardCancelDialogContainerComponent', () => { }); }); - describe('ozgcloud-stroked-button-with-spinner Verwerfen', () => { - it('should show', () => { + describe('delete button', () => { + it('should exists', () => { existsAsHtmlElement(fixture, verwerfenButton); }); - describe('input', () => { - it('should set stateResource', () => { - const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); - component.deleteStateResource$ = of(commandStateResource); + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createCommandStateResource(); + component.deleteStateResource$ = of(commandStateResource); - const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( - fixture, - verwerfenButton, - ); + const elementComponent: OzgcloudStrokedButtonWithSpinnerComponent = getElementComponentFromFixtureByCss( + fixture, + verwerfenButton, + ); - fixture.detectChanges(); + fixture.detectChanges(); - expect(elementComponent.stateResource).toBe(commandStateResource); - }); + expect(elementComponent.stateResource).toBe(commandStateResource); }); describe('output', () => { diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts index ae452113e7c35d55c6341ba1c79aa0fadb2005d3..2b2ee2327c607f41cc889b00a62c84ff3b9560b2 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component.ts @@ -21,13 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource } from '@alfa-client/bescheid-shared'; import { tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; -import { StateResource, isNotNil } from '@alfa-client/tech-shared'; +import { isNotNil, StateResource } from '@alfa-client/tech-shared'; import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; -import { Component, Inject } from '@angular/core'; +import { Component, inject, OnDestroy, OnInit } from '@angular/core'; import { Resource } from '@ngxp/rest'; import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; import { BescheidFormService } from '../../bescheid.formservice'; export interface CancelWizardDialogData { @@ -41,19 +42,23 @@ export interface CancelWizardDialogResult { @Component({ templateUrl: './bescheid-wizard-cancel-dialog-container.component.html', }) -export class BescheidWizardCancelDialogContainerComponent { +export class BescheidWizardCancelDialogContainerComponent implements OnInit, OnDestroy { + private readonly dialogData: CancelWizardDialogData = inject(DIALOG_DATA); + private readonly dialogRef = inject(DialogRef); + private readonly bescheidService = inject(BescheidService2); + private readonly formService = inject(BescheidFormService); + public saveStateResource$: Observable<StateResource<Resource>>; public deleteStateResource$: Observable<StateResource<Resource>>; - bescheidResource: BescheidResource; + private readonly bescheidResource: BescheidResource = this.dialogData.bescheidResource; + + ngOnInit(): void { + this.bescheidService.lockBescheidSending(); + } - constructor( - @Inject(DIALOG_DATA) readonly dialogData: CancelWizardDialogData, - public dialogRef: DialogRef<CancelWizardDialogResult>, - private readonly bescheidService: BescheidService, - private readonly formService: BescheidFormService, - ) { - this.bescheidResource = dialogData.bescheidResource; + ngOnDestroy(): void { + this.bescheidService.unlockBescheidSending(); } public save(): void { @@ -63,7 +68,7 @@ export class BescheidWizardCancelDialogContainerComponent { public cancel(): void { if (isNotNil(this.bescheidResource)) { this.deleteStateResource$ = this.bescheidService - .bescheidVerwerfen() + .deleteBescheid() .pipe(tapOnCommandSuccessfullyDone(() => this.closeDialogWithWizard())); } else { this.closeDialogWithWizard(); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..e1c9cb9a825ec71879a005c00d792e406280dfc3 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-create-document-button + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (clickEmitter)="createBescheidDocument()" + data-test-id="bescheid-wizard-create-button" +></alfa-bescheid-wizard-create-document-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..578b614b16d24e6b9d40ed36e1a0608b04781e24 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.spec.ts @@ -0,0 +1,100 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from './bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardCreateDocumentButtonComponent } from './create-document-button/bescheid-wizard-create-document-button.component'; + +describe('BescheidWizardCreateDocumentButtonContainerComponent', () => { + let component: BescheidWizardCreateDocumentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardCreateDocumentButtonContainerComponent>; + + const buttonTestId: string = getDataTestIdOf('bescheid-wizard-create-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + const bescheidResource: BescheidResource = createBescheidResource(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardCreateDocumentButtonContainerComponent, + MockComponent(BescheidWizardCreateDocumentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardCreateDocumentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('createBescheidDocument', () => { + it('should call service', () => { + component.createBescheidDocument(); + + expect(bescheidService.createBescheidDocument).toHaveBeenCalledWith(component.bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('create button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, buttonTestId); + }); + + it('should have been called with inputs', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + + const buttonComponent: BescheidWizardCreateDocumentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardCreateDocumentButtonComponent>(fixture, buttonTestId); + + expect(buttonComponent.bescheidResource).toEqual(bescheidResource); + expect(buttonComponent.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.createBescheidDocument = jest.fn(); + + triggerEvent({ fixture, elementSelector: buttonTestId, name: 'clickEmitter' }); + + expect(component.createBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..63c525d76932091bdf971c5789c843568afd8112 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-create-document-button-container', + templateUrl: './bescheid-wizard-create-document-button-container.component.html', +}) +export class BescheidWizardCreateDocumentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + + public createBescheidDocument(): void { + this.bescheidService.createBescheidDocument(this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..db9307187ec8c100d91ff2c2ffc7b99dd22fc5e2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.html @@ -0,0 +1,12 @@ +@if (bescheidResource | hasLink: BescheidLinkRel.CREATE_DOCUMENT) { + <ods-button-card + class="w-full max-w-72" + [isLoading]="bescheidDocument.create.loading" + (click)="clickEmitter.emit()" + text="Bescheiddokument" + subText="automatisch erstellen" + data-test-id="create-bescheid-document-button" + > + <ods-bescheid-generate-icon icon /> + </ods-button-card> +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0870d4c34bd3f5dab6ae510dfe171877bc700590 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.spec.ts @@ -0,0 +1,119 @@ +import { BescheidDocument, BescheidLinkRel, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + Mock, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { BescheidGenerateIconComponent, ButtonCardComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardCreateDocumentButtonComponent } from './bescheid-wizard-create-document-button.component'; + +describe('BescheidWizardAutomatischErstellenButtonComponent', () => { + let component: BescheidWizardCreateDocumentButtonComponent; + let fixture: ComponentFixture<BescheidWizardCreateDocumentButtonComponent>; + + const createButtonTestId: string = getDataTestIdOf('create-bescheid-document-button'); + + let formService: Mock<BescheidFormService>; + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + beforeEach(() => { + formService = mock(BescheidFormService); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardCreateDocumentButtonComponent, + MockComponent(ButtonCardComponent), + MockComponent(BescheidGenerateIconComponent), + HasLinkPipe, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardCreateDocumentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.bescheidDocument).toEqual(createEmptyBescheidDocument()); + }); + + describe('set bescheid document', () => { + it('should set value', () => { + component.bescheidDocument = bescheidDocument; + + expect(component.bescheidDocument).toEqual(bescheidDocument); + }); + + it('should call form service', () => { + component.bescheidDocument = bescheidDocument; + + expect(formService.updateBescheidDocumentFile).toHaveBeenCalledWith(bescheidDocument.documentUri); + }); + }); + }); + + describe('template', () => { + describe('create button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, createButtonTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, createButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + component.bescheidDocument = bescheidDocument; + + fixture.detectChanges(); + const buttonComponent: ButtonCardComponent = getElementComponentFromFixtureByCss<ButtonCardComponent>( + fixture, + createButtonTestId, + ); + + expect(buttonComponent.isLoading).toEqual(bescheidDocument.create.loading); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should emit', () => { + component.clickEmitter.emit = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.CREATE_DOCUMENT]); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: createButtonTestId, name: 'click' }); + + expect(component.clickEmitter.emit).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..083aec95ac2ddd1d4b030e8ab57a3baf6b55f72e --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component.ts @@ -0,0 +1,28 @@ +import { BescheidDocument, BescheidLinkRel, BescheidResource, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-create-document-button', + templateUrl: './bescheid-wizard-create-document-button.component.html', +}) +export class BescheidWizardCreateDocumentButtonComponent { + @Input() bescheidResource: BescheidResource; + + @Input() set bescheidDocument(value: BescheidDocument) { + this._bescheidDocument = value; + this.formService.updateBescheidDocumentFile(value.documentUri); + } + + get bescheidDocument(): BescheidDocument { + return this._bescheidDocument; + } + + @Output() clickEmitter: EventEmitter<void> = new EventEmitter<void>(); + + private readonly formService = inject(BescheidFormService); + + private _bescheidDocument: BescheidDocument = createEmptyBescheidDocument(); + + public readonly BescheidLinkRel = BescheidLinkRel; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..dcf2a2ac6fc332f13bd56c900007dd25d16a2375 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.html @@ -0,0 +1,7 @@ +<alfa-bescheid-wizard-document-file + [bescheidDocument]="bescheidDocument$ | async" + [deletable]="(activeStep$ | async) === bescheidWizardStep.DokumenteHochladen" + (deleteFile)="deleteBescheidDocument()" + data-test-id="bescheid-document" +> +</alfa-bescheid-wizard-document-file> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9171b0143e8af45416b48d4a779d6e277ad0a5ef --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.spec.ts @@ -0,0 +1,123 @@ +import { BescheidDocument, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidFormService } from '../../bescheid.formservice'; +import { BescheidWizardDocumentFileContainerComponent } from './bescheid-wizard-document-file-container.component'; +import { BescheidWizardDocumentFileComponent } from './document-file/bescheid-wizard-document-file.component'; + +describe('BescheidWizardDocumentFileContainerComponent', () => { + let component: BescheidWizardDocumentFileContainerComponent; + let fixture: ComponentFixture<BescheidWizardDocumentFileContainerComponent>; + + const documentFileTestId: string = getDataTestIdOf('bescheid-document'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + let formService: Mock<BescheidFormService>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + formService = mock(BescheidFormService); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardDocumentFileContainerComponent, MockComponent(BescheidWizardDocumentFileComponent)], + providers: [ + { provide: BescheidService2, useValue: bescheidService }, + { provide: BescheidFormService, useValue: formService }, + ], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardDocumentFileContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + expect(component.activeStep$).toBeObservable(singleColdCompleted(BescheidWizardStep.BescheidVersenden)); + }); + + describe('deleteBescheidDocument', () => { + it('should call form service', () => { + component.deleteBescheidDocument(); + + expect(formService.clearBescheidDocumentFile).toHaveBeenCalled(); + expect(bescheidService.deleteBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('document file', () => { + function getComponent(): BescheidWizardDocumentFileComponent { + return getElementComponentFromFixtureByCss<BescheidWizardDocumentFileComponent>(fixture, documentFileTestId); + } + + it('should exists', () => { + existsAsHtmlElement(fixture, documentFileTestId); + }); + + it('should have been called with bescheid document', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().bescheidDocument).toEqual(bescheidDocument); + }); + + it('should have been called with deletable true', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.DokumenteHochladen)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(true); + }); + + it('should have been called with deletable false', () => { + bescheidService.getActiveStep.mockReturnValue(of(BescheidWizardStep.BescheidVersenden)); + + createComponent(); + fixture.detectChanges(); + + expect(getComponent().deletable).toEqual(false); + }); + + describe('output', () => { + describe('deleteFile', () => { + it('should call handler', () => { + component.deleteBescheidDocument = jest.fn(); + + triggerEvent({ fixture, elementSelector: documentFileTestId, name: 'deleteFile' }); + + expect(component.deleteBescheidDocument).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f50758a6f2914eacb0f1f0a3711e6d0eec3f5d13 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component.ts @@ -0,0 +1,24 @@ +import { BescheidDocument, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { Component, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { BescheidFormService } from '../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-document-file-container', + templateUrl: './bescheid-wizard-document-file-container.component.html', +}) +export class BescheidWizardDocumentFileContainerComponent { + private readonly bescheidService = inject(BescheidService2); + private readonly formService = inject(BescheidFormService); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + public readonly activeStep$: Observable<BescheidWizardStep> = this.bescheidService.getActiveStep(); + + public readonly bescheidWizardStep = BescheidWizardStep; + + public deleteBescheidDocument(): void { + this.formService.clearBescheidDocumentFile(); + this.bescheidService.deleteBescheidDocument(); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c77ff1d88a92fcc3b6141fb911ac50580ffa9b95 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.html @@ -0,0 +1,28 @@ +<ods-attachment-wrapper> + @if (showAutomaticCreation) { + <ods-attachment + errorCaption="Fehler beim automatischen Erstellen" + loadingCaption="Bescheiddokument" + description="Bescheiddokument wird erstellt" + [isLoading]="bescheidDocument.create.loading" + [errorMessages]="createDocumentErrorMessages" + data-test-id="create-bescheid-document-attachment" + ></ods-attachment> + } + + @if (showUpload) { + <ods-attachment + errorCaption="Fehler beim Hochladen" + [loadingCaption]="bescheidDocument.upload.fileName" + [attr.data-test-id]="'upload-bescheid-document'" + [isLoading]="bescheidDocument.upload.loading" + [errorMessages]="bescheidDocument.upload.error | convertProblemDetailToErrorMessages" + description="Bescheiddokument wird hochgeladen" + ></ods-attachment> + } + + @if (showDocument) { + <alfa-binary-file2-container [file]="bescheidDocument.resource" [deletable]="deletable" (startDelete)="deleteFile.emit()" data-test-id="bescheid-document-binary-file"> + </alfa-binary-file2-container> + } +</ods-attachment-wrapper> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..412b4eb3ff92220473ee167ef709f8fbf3baf77d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.spec.ts @@ -0,0 +1,301 @@ +import { BescheidDocument, createEmptyBescheidDocument, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file'; +import { + ConvertProblemDetailToErrorMessagesPipe, + createEmptyStateResource, + createErrorStateResource, + createLoadingStateResource, + ProblemDetail, +} from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { + createBescheidDocument, + createErrorUpload, + createPendingUpload, + createSuccessfulUpload, +} from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createProblemDetail } from '../../../../../../../tech-shared/test/error'; +import { BescheidWizardDocumentFileComponent } from './bescheid-wizard-document-file.component'; + +describe('BescheidWizardDocumentFileComponent', () => { + let component: BescheidWizardDocumentFileComponent; + let fixture: ComponentFixture<BescheidWizardDocumentFileComponent>; + + const convertProblemDetailsToErrorMessages: ConvertProblemDetailToErrorMessagesPipe = + new ConvertProblemDetailToErrorMessagesPipe(); + + const createBescheidTestId: string = getDataTestIdOf('create-bescheid-document-attachment'); + const uploadBescheidTestId: string = getDataTestIdOf('upload-bescheid-document'); + const bescheidDocumentTestId: string = getDataTestIdOf('bescheid-document-binary-file'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDocumentFileComponent, + MockComponent(AttachmentWrapperComponent), + MockComponent(AttachmentComponent), + MockComponent(BinaryFile2ContainerComponent), + ConvertProblemDetailToErrorMessagesPipe, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDocumentFileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.showAutomaticCreation).toEqual(false); + expect(component.showUpload).toEqual(false); + expect(component.showDocument).toEqual(false); + expect(component.createDocumentErrorMessages).toEqual([]); + expect(component.bescheidDocument).toEqual(createEmptyBescheidDocument()); + }); + + describe('set bescheid document', () => { + it('should update component state', () => { + component.update = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(component.update).toHaveBeenCalled(); + }); + }); + + describe('update', () => { + it('should set bescheid document', () => { + component.update(bescheidDocument); + + expect(component.bescheidDocument).toEqual(bescheidDocument); + }); + + it('should show automatic creation on loading', () => { + component.update({ ...bescheidDocument, create: createLoadingStateResource() }); + + expect(component.showAutomaticCreation).toEqual(true); + }); + + it('should show automatic creation on error', () => { + component.update({ + ...bescheidDocument, + create: createErrorStateResource(createProblemDetail()), + }); + + expect(component.showAutomaticCreation).toEqual(true); + }); + + it('should show upload on loading', () => { + component.update({ ...bescheidDocument, upload: createPendingUpload() }); + + expect(component.showUpload).toEqual(true); + }); + + it('should show upload on error', () => { + component.update({ + ...bescheidDocument, + upload: createErrorUpload(), + }); + + expect(component.showUpload).toEqual(true); + }); + + it('should show created document', () => { + component.update({ + ...bescheidDocument, + create: createSuccessfullyDoneCommandStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.showDocument).toEqual(true); + }); + + it('should show uploaded document', () => { + component.update({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createSuccessfulUpload(), + }); + + expect(component.showDocument).toEqual(true); + }); + + it('should NOT show document on pending creation', () => { + component.update({ + ...bescheidDocument, + create: createLoadingStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should NOT show document on pending upload', () => { + component.update({ + ...bescheidDocument, + create: createEmptyStateResource(), + upload: createPendingUpload(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should NOT show document if not exists', () => { + component.update({ + ...bescheidDocument, + resource: null, + create: createEmptyStateResource(), + upload: createPendingUpload(), + }); + + expect(component.showDocument).toEqual(false); + }); + + it('should have error messages', () => { + component.update({ + ...bescheidDocument, + create: createErrorStateResource(createProblemDetail()), + upload: createEmptyUploadInProgress(), + }); + + expect(component.createDocumentErrorMessages).toEqual([BescheidWizardDocumentFileComponent.CREATE_ERROR_MESSAGE]); + }); + + it('should NOT have error messages', () => { + component.update({ + ...bescheidDocument, + create: createSuccessfullyDoneCommandStateResource(), + upload: createEmptyUploadInProgress(), + }); + + expect(component.createDocumentErrorMessages).toEqual([]); + }); + }); + }); + + describe('template', () => { + describe('automatic creation attachment', () => { + it('should exists', () => { + component.showAutomaticCreation = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, createBescheidTestId); + }); + + it('should NOT exists', () => { + component.showAutomaticCreation = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, createBescheidTestId); + }); + + it('should have been called with inputs', () => { + component.showAutomaticCreation = true; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + createBescheidTestId, + ); + + expect(attachmentComponent.isLoading).toEqual(component.bescheidDocument.create.loading); + expect(attachmentComponent.errorMessages).toEqual(component.createDocumentErrorMessages); + }); + }); + + describe('upload file', () => { + it('should exists', () => { + component.showUpload = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, uploadBescheidTestId); + }); + + it('should NOT exists', () => { + component.showUpload = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, uploadBescheidTestId); + }); + + it('should have been called with inputs', () => { + component.showUpload = true; + + fixture.detectChanges(); + const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss<AttachmentComponent>( + fixture, + uploadBescheidTestId, + ); + + expect(attachmentComponent.loadingCaption).toEqual(component.bescheidDocument.upload.fileName); + expect(attachmentComponent.isLoading).toEqual(component.bescheidDocument.upload.loading); + expect(attachmentComponent.errorMessages).toEqual( + convertProblemDetailsToErrorMessages.transform(component.bescheidDocument.upload.error as ProblemDetail), + ); + }); + }); + + describe('document binary file', () => { + it('should exists', () => { + component.showDocument = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, bescheidDocumentTestId); + }); + + it('should NOT exists', () => { + component.showDocument = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, bescheidDocumentTestId); + }); + + it('should have been called with inputs', () => { + component.showDocument = true; + + fixture.detectChanges(); + const attachmentComponent: BinaryFile2ContainerComponent = + getElementComponentFromFixtureByCss<BinaryFile2ContainerComponent>(fixture, bescheidDocumentTestId); + + expect(attachmentComponent.file).toEqual(component.bescheidDocument.resource); + expect(attachmentComponent.deletable).toEqual(component.deletable); + }); + + describe('output', () => { + describe('startDelete', () => { + it('should emit', () => { + component.showDocument = true; + fixture.detectChanges(); + component.deleteFile.emit = jest.fn(); + + triggerEvent({ fixture, elementSelector: bescheidDocumentTestId, name: 'startDelete' }); + + expect(component.deleteFile.emit).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..231c486fde2bcae1b49a21eca2319751b76865c4 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component.ts @@ -0,0 +1,39 @@ +import { BescheidDocument, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { hasStateResourceError, isNotNil } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'alfa-bescheid-wizard-document-file', + templateUrl: './bescheid-wizard-document-file.component.html', +}) +export class BescheidWizardDocumentFileComponent { + static readonly CREATE_ERROR_MESSAGE = 'Bescheiddokument konnte nicht erzeugt werden.'; + + @Input() set bescheidDocument(value: BescheidDocument) { + this.update(value); + } + + get bescheidDocument(): BescheidDocument { + return this._bescheidDocument; + } + + @Input() public deletable: boolean; + + @Output() deleteFile: EventEmitter<void> = new EventEmitter<void>(); + + public showAutomaticCreation: boolean = false; + public showUpload: boolean = false; + public showDocument: boolean = false; + public createDocumentErrorMessages: string[] = []; + + private _bescheidDocument: BescheidDocument = createEmptyBescheidDocument(); + + update(value: BescheidDocument) { + this._bescheidDocument = value; + this.showAutomaticCreation = value.create.loading || hasStateResourceError(value.create); + this.showUpload = value.upload.loading || isNotNil(value.upload.error); + this.showDocument = isNotNil(value.resource) && !value.upload.loading && !value.create.loading; + this.createDocumentErrorMessages = + hasStateResourceError(value.create) ? [BescheidWizardDocumentFileComponent.CREATE_ERROR_MESSAGE] : []; + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c039d147b1d8c2f8be9d3fe0f63ef42ccd1a0972 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.html @@ -0,0 +1,53 @@ +<!-- + + Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Ministerpräsidenten des Landes Schleswig-Holstein + Staatskanzlei + Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + + Lizenziert unter der EUPL, Version 1.2 oder - sobald + diese von der Europäischen Kommission genehmigt wurden - + Folgeversionen der EUPL ("Lizenz"); + Sie dürfen dieses Werk ausschließlich gemäß + dieser Lizenz nutzen. + Eine Kopie der Lizenz finden Sie hier: + + https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + + Sofern nicht durch anwendbare Rechtsvorschriften + gefordert oder in schriftlicher Form vereinbart, wird + die unter der Lizenz verbreitete Software "so wie sie + ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + ausdrücklich oder stillschweigend - verbreitet. + Die sprachspezifischen Genehmigungen und Beschränkungen + unter der Lizenz sind dem Lizenztext zu entnehmen. + +--> +<alfa-step-content-layout + [activeStep]="BescheidWizardStep.DokumenteHochladen" + (stepChange)="onStepChange($event)" + data-test-id="step-content-layout" +> + <ng-container stepPanel> + <alfa-bescheid-wizard-step-title + label="Antrag bescheiden" + [inactiveStep]="true" + data-test-id="antrag-bescheiden-step-title" + /> + <alfa-bescheid-wizard-step-title label="Dokumente hinzufügen" /> + <alfa-bescheid-wizard-dokumente-hochladen-form + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (weiterClickEmitter)="onWeiterClick()" + (bescheidDocumentMissing)="onBescheidDocumentMissing($event)" + data-test-id="bescheid-wizard-dokumente-hochladen-form" + /> + </ng-container> + <ng-container summary> + <alfa-bescheid-wizard-antrag-bescheiden-summary /> + <alfa-bescheid-wizard-dokumente-hochladen-summary + [isBescheidDocumentMissing]="isBescheidDocumentMissing" + data-test-id="bescheid-wizard-dokumente-hochladen-summary" + /> + </ng-container> +</alfa-step-content-layout> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..749ab02b1417d171af7d7549c1c2994d4116fc04 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.spec.ts @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardAntragBescheidenSummaryComponent } from '../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { StepContentLayoutComponent } from '../step-content-layout/step-content-layout.component'; +import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; +import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './bescheid-wizard-dokumente-hochladen-container.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './form/bescheid-wizard-dokumente-hochladen-form.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './summary/bescheid-wizard-dokumente-hochladen-summary.component'; + +describe('BescheidWizardDokumenteHochladenComponent', () => { + let component: BescheidWizardDokumenteHochladenContainerComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenContainerComponent>; + + const stepContentLayout: string = getDataTestIdOf('step-content-layout'); + const antragBescheidenStepTitleTestId: string = getDataTestIdOf('antrag-bescheiden-step-title'); + const dokumenteHochladenFormTestId: string = getDataTestIdOf('bescheid-wizard-dokumente-hochladen-form'); + const dokumenteHochladenSummaryTestId: string = getDataTestIdOf('bescheid-wizard-dokumente-hochladen-summary'); + + const bescheidResource: BescheidResource = createBescheidResource(); + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenContainerComponent, + MockComponent(StepContentLayoutComponent), + MockComponent(BescheidWizardSummaryComponent), + MockComponent(BescheidWizardAntragBescheidenSummaryComponent), + MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), + MockComponent(BescheidWizardStepTitleComponent), + MockComponent(BescheidWizardDokumenteHochladenFormComponent), + MockComponent(BescheidWizardStepperComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('ngOnInit', () => { + it('should load files', () => { + component.ngOnInit(); + + expect(bescheidService.loadFiles).toHaveBeenCalled(); + }); + }); + + describe('set bescheid resource', () => { + it('should set value', () => { + component.bescheidResource = bescheidResource; + + expect(component.bescheidResource).toEqual(bescheidResource); + }); + }); + + describe('onWeiterClick', () => { + it('should finish adding attachments', () => { + component.onWeiterClick(); + + expect(bescheidService.finishAddingAttachments).toHaveBeenCalled(); + }); + + it('should finish adding bescheid document', () => { + component.onWeiterClick(); + + expect(bescheidService.finishAddingBescheidDocument).toHaveBeenCalled(); + }); + + it('should change active step', () => { + component.onWeiterClick(); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.BescheidVersenden); + }); + }); + + describe('onBescheidDocumentMissing', () => { + it('should set value', () => { + component.isBescheidDocumentMissing = false; + + component.onBescheidDocumentMissing(true); + + expect(component.isBescheidDocumentMissing).toEqual(true); + }); + }); + + describe('onStepChange', () => { + it('should change step', () => { + component.onStepChange(BescheidWizardStep.AntragBescheiden); + + expect(bescheidService.setActiveStep).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); + }); + + describe('template', () => { + describe('step content layout', () => { + describe('output', () => { + it('should call handler', () => { + component.onStepChange = jest.fn(); + + triggerEvent({ + fixture, + name: 'stepChange', + elementSelector: stepContentLayout, + data: BescheidWizardStep.AntragBescheiden, + }); + + expect(component.onStepChange).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); + }); + + describe('antrag bescheiden step title', () => { + it('should have been called with inputs', () => { + const stepTitle: BescheidWizardStepTitleComponent = getElementComponentFromFixtureByCss<BescheidWizardStepTitleComponent>( + fixture, + antragBescheidenStepTitleTestId, + ); + + expect(stepTitle.inactiveStep).toBeTruthy(); + }); + }); + + describe('hochladen form', () => { + it('should have been called with inputs', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const hochladenForm: BescheidWizardDokumenteHochladenFormComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenFormComponent>( + fixture, + dokumenteHochladenFormTestId, + ); + + expect(hochladenForm.bescheidResource).toEqual(bescheidResource); + expect(hochladenForm.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('weiterClickEmitter', () => { + it('should call handler', () => { + component.onWeiterClick = jest.fn(); + + triggerEvent({ fixture, elementSelector: dokumenteHochladenFormTestId, name: 'weiterClickEmitter' }); + + expect(component.onWeiterClick).toHaveBeenCalled(); + }); + }); + + describe('bescheidDocumentMissing', () => { + it('should call handler', () => { + component.onBescheidDocumentMissing = jest.fn(); + + triggerEvent({ fixture, elementSelector: dokumenteHochladenFormTestId, name: 'bescheidDocumentMissing' }); + + expect(component.onBescheidDocumentMissing).toHaveBeenCalled(); + }); + }); + }); + }); + + describe('hochladen summary', () => { + it('should have been called with inputs', () => { + component.isBescheidDocumentMissing = true; + + fixture.detectChanges(); + const hochladenSummary: BescheidWizardDokumenteHochladenSummaryComponent = + getElementComponentFromFixtureByCss<BescheidWizardDokumenteHochladenSummaryComponent>( + fixture, + dokumenteHochladenSummaryTestId, + ); + + expect(hochladenSummary).toBeTruthy(); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb90a6109b54253184476b5b3542bd31f0851d94 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component.ts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidResource, BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-dokumente-hochladen-container', + templateUrl: './bescheid-wizard-dokumente-hochladen-container.component.html', +}) +export class BescheidWizardDokumenteHochladenContainerComponent implements OnInit { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + public isBescheidDocumentMissing: boolean = false; + + public readonly BescheidWizardStep = BescheidWizardStep; + + ngOnInit(): void { + this.bescheidService.loadFiles(this.bescheidResource); + } + + public onWeiterClick(): void { + this.bescheidService.finishAddingAttachments(); + this.bescheidService.finishAddingBescheidDocument(); + this.bescheidService.setActiveStep(BescheidWizardStep.BescheidVersenden); + } + + public onBescheidDocumentMissing(value: boolean): void { + this.isBescheidDocumentMissing = value; + } + + public onStepChange(step: BescheidWizardStep): void { + this.bescheidService.setActiveStep(step); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html similarity index 51% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html index 95c0c3895cacf7701e2b189c74964fa72072056f..fd2a2ab6c43b6e00ba06a0347278e2ab53b0c5aa 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html @@ -23,15 +23,24 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="mt-2 grid h-full grid-cols-[min-content_1fr_1fr] gap-7"> - <alfa-bescheid-wizard-stepper [activeStep]="bescheidWizardStep.DokumenteHochladen"></alfa-bescheid-wizard-stepper> - <div> - <alfa-bescheid-wizard-step-title label="Antrag bescheiden" [inactiveStep]="true"></alfa-bescheid-wizard-step-title> - <alfa-bescheid-wizard-step-title label="Dokumente hochladen"></alfa-bescheid-wizard-step-title> - <alfa-bescheid-wizard-dokumente-hochladen-form></alfa-bescheid-wizard-dokumente-hochladen-form> - </div> - <alfa-bescheid-wizard-summary> - <alfa-bescheid-wizard-antrag-bescheiden-summary></alfa-bescheid-wizard-antrag-bescheiden-summary> - <alfa-bescheid-wizard-dokumente-hochladen-summary></alfa-bescheid-wizard-dokumente-hochladen-summary> - </alfa-bescheid-wizard-summary> +<div class="mt-4 flex flex-col gap-4"> + <alfa-bescheid-wizard-create-document-button-container + [bescheidResource]="bescheidResource" + data-test-id="create-document-button" + ></alfa-bescheid-wizard-create-document-button-container> + <alfa-bescheid-wizard-upload-document-button-container + [bescheidResource]="bescheidResource" + data-test-id="upload-document-button" + ></alfa-bescheid-wizard-upload-document-button-container> + <alfa-bescheid-wizard-upload-attachment-button-container + [bescheidResource]="bescheidResource" + data-test-id="upload-attachment-button" + ></alfa-bescheid-wizard-upload-attachment-button-container> + @if (bescheidResource | hasLink: bescheidLinkRel.UPDATE) { + <alfa-bescheid-wizard-weiter-button + [submitStateResource]="submitStateResource$ | async" + (clickEmitter)="gotoNextStep()" + data-test-id="weiter-button" + ></alfa-bescheid-wizard-weiter-button> + } </div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..02452fe302b69a044cef2cf621ea5a1e5734d6c2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierun + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidLinkRel, createEmptyBescheidDocument } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock, notExistsAsHtmlElement, triggerEvent, } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../../../../command-shared/test/command'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from '../../create-document-button-container/bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from '../../upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from '../../upload-document-button-container/bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardWeiterButtonComponent } from '../../weiter-button/bescheid-wizard-weiter-button.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-dokumente-hochladen-form.component'; + +describe('BescheidWizardDokumenteHochladenFormComponent', () => { + let component: BescheidWizardDokumenteHochladenFormComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenFormComponent>; + + const createDocumentButtonTestId: string = getDataTestIdOf('create-document-button'); + const uploadDocumentButtonTestId: string = getDataTestIdOf('upload-document-button'); + const uploadAttachmentButtonTestId: string = getDataTestIdOf('upload-attachment-button'); + const weiterButtonTestId: string = getDataTestIdOf('weiter-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let formService: Mock<BescheidFormService>; + + beforeEach(() => { + formService = mock(BescheidFormService); + formService.submit = jest.fn().mockReturnValue(EMPTY); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenFormComponent, + MockComponent(BescheidWizardCreateDocumentButtonContainerComponent), + MockComponent(BescheidWizardUploadDocumentButtonContainerComponent), + MockComponent(BescheidWizardUploadAttachmentButtonContainerComponent), + MockComponent(BescheidWizardWeiterButtonComponent), + HasLinkPipe, + ], + providers: [{ provide: BescheidFormService, useValue: formService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('set bescheid document', () => { + it('should emit missing bescheid document false', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + + expect(component.bescheidDocumentMissing.emit).toHaveBeenCalledWith(false); + }); + + it('should NOT emit missing bescheid document', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = createEmptyBescheidDocument(); + + expect(component.bescheidDocumentMissing.emit).not.toHaveBeenCalled(); + }); + }); + + describe('gotoNextStep', () => { + it('should emit missing bescheid document true', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = createEmptyBescheidDocument(); + + component.gotoNextStep(); + + expect(component.bescheidDocumentMissing.emit).toHaveBeenCalledWith(true); + }); + + it('should submit form', () => { + component.bescheidDocumentMissing.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + + component.gotoNextStep(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should emit weiter click', () => { + component.weiterClickEmitter.emit = jest.fn(); + component.bescheidDocument = bescheidDocument; + formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + component.gotoNextStep(); + component.submitStateResource$.subscribe(); + + expect(component.weiterClickEmitter.emit).toHaveBeenCalled(); + }); + }); + }); + + describe('template', () => { + describe('create document button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, createDocumentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const createDocumentButton: BescheidWizardCreateDocumentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardCreateDocumentButtonContainerComponent>( + fixture, + createDocumentButtonTestId, + ); + + expect(createDocumentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('upload document button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, uploadDocumentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const uploadDocumentButton: BescheidWizardUploadDocumentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadDocumentButtonContainerComponent>( + fixture, + uploadDocumentButtonTestId, + ); + + expect(uploadDocumentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('upload attachment button', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, uploadAttachmentButtonTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + const uploadAttachmentButton: BescheidWizardUploadAttachmentButtonContainerComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadAttachmentButtonContainerComponent>( + fixture, + uploadDocumentButtonTestId, + ); + + expect(uploadAttachmentButton.bescheidResource).toEqual(component.bescheidResource); + }); + }); + + describe('weiter button', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, weiterButtonTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, weiterButtonTestId); + }); + + it('should have been called with inputs', () => { + const commandStateResource: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + component.submitStateResource$ = of(commandStateResource); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + + fixture.detectChanges(); + const weiterButton: BescheidWizardWeiterButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardWeiterButtonComponent>(fixture, weiterButtonTestId); + component.submitStateResource$.subscribe(); + + expect(weiterButton.submitStateResource).toEqual(commandStateResource); + }); + + describe('output', () => { + describe('clickEmitter', () => { + it('should call handler', () => { + component.gotoNextStep = jest.fn(); + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPDATE]); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: weiterButtonTestId, name: 'clickEmitter' }); + + expect(component.gotoNextStep).toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d09a24bce3dfd8a65dac3470147f42fff00aeda9 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.ts @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidDocument, BescheidLinkRel, BescheidResource } from '@alfa-client/bescheid-shared'; +import { tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { isNotNil, StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { Resource } from '@ngxp/rest'; +import { isNil } from 'lodash-es'; +import { Observable } from 'rxjs'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-dokumente-hochladen-form', + templateUrl: './bescheid-wizard-dokumente-hochladen-form.component.html', +}) +export class BescheidWizardDokumenteHochladenFormComponent { + @Input() set bescheidDocument(value: BescheidDocument) { + this._bescheidDocument = value; + if (isNotNil(value.resource)) { + this.bescheidDocumentMissing.emit(false); + } + } + + @Input() bescheidResource: BescheidResource; + + @Output() weiterClickEmitter: EventEmitter<void> = new EventEmitter<void>(); + @Output() bescheidDocumentMissing: EventEmitter<boolean> = new EventEmitter<boolean>(); + + private readonly formService = inject(BescheidFormService); + + public submitStateResource$: Observable<StateResource<Resource>>; + + private _bescheidDocument: BescheidDocument; + + protected readonly bescheidLinkRel = BescheidLinkRel; + + public gotoNextStep(): void { + if (isNil(this._bescheidDocument.resource)) { + this.bescheidDocumentMissing.emit(true); + } else { + this.submitStateResource$ = this.formService + .submit() + .pipe(tapOnCommandSuccessfullyDone(() => this.weiterClickEmitter.emit())); + } + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html similarity index 65% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html index 1ce18413c69e7b7399288ffa987dfdeb0b2d4ee5..b8c80fafbcec28185f7ff568c8b5357c197b1503 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.html @@ -23,4 +23,17 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<p>bescheid-wizard-dokumente-hochladen-summary works!</p> + +@if (isBescheidDocumentMissing) { + <p data-test-id="missing-bescheid-document-error-message" class="my-4 text-base text-error"> + Bitte fügen Sie ein Bescheiddokument hinzu. + </p> +} +<div class="my-4"> + <alfa-bescheid-wizard-document-file-container data-test-id="bescheid-document-file"> + </alfa-bescheid-wizard-document-file-container> +</div> +<div class="my-4"> + <alfa-bescheid-wizard-attachment-files-container data-test-id="bescheid-attachment-files"> + </alfa-bescheid-wizard-attachment-files-container> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ed6c9e5d11f1e5ebbe9fda0b395d70bc856c323 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { BescheidWizardAttachmentFilesContainerComponent } from '../../attachment-files-container/bescheid-wizard-attachment-files-container.component'; +import { BescheidWizardDocumentFileContainerComponent } from '../../document-file-container/bescheid-wizard-document-file-container.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-dokumente-hochladen-summary.component'; + +describe('BescheidWizardDokumenteHochladenSummaryComponent', () => { + let component: BescheidWizardDokumenteHochladenSummaryComponent; + let fixture: ComponentFixture<BescheidWizardDokumenteHochladenSummaryComponent>; + + const missingBescheidErrorMessageTestId: string = getDataTestIdOf('missing-bescheid-document-error-message'); + const documentFileTestId: string = getDataTestIdOf('bescheid-document-file'); + const attachmentFilesTestId: string = getDataTestIdOf('bescheid-attachment-files'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardDokumenteHochladenSummaryComponent, + MockComponent(BescheidWizardDocumentFileContainerComponent), + MockComponent(BescheidWizardAttachmentFilesContainerComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenSummaryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('template', () => { + describe('missing bescheid error message', () => { + it('should exists', () => { + component.isBescheidDocumentMissing = true; + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, missingBescheidErrorMessageTestId); + }); + + it('should NOT exists', () => { + component.isBescheidDocumentMissing = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, missingBescheidErrorMessageTestId); + }); + }); + + describe('document file', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, documentFileTestId); + }); + }); + + describe('attachment files', () => { + it('should exists', () => { + existsAsHtmlElement(fixture, attachmentFilesTestId); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts similarity index 87% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts index 9ef966f315ee77c10a08a177d0eddc0ce2d86c61..6bf136b2492c45205aa1fe115c3a033d92c1d174 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component.ts @@ -21,10 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-bescheid-wizard-dokumente-hochladen-summary', templateUrl: './bescheid-wizard-dokumente-hochladen-summary.component.html', }) -export class BescheidWizardDokumenteHochladenSummaryComponent {} +export class BescheidWizardDokumenteHochladenSummaryComponent { + @Input() isBescheidDocumentMissing: boolean; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts deleted file mode 100644 index 3776924bd38321a3ae2e369805d408f7e0961582..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { getElementFromFixtureByType } from '@alfa-client/test-utils'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MockComponent } from 'ng-mocks'; -import { BescheidWizardAntragBescheidenSummaryComponent } from '../antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; -import { BescheidWizardStepTitleComponent } from '../step-title/bescheid-wizard-step-title.component'; -import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; -import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; -import { BescheidWizardDokumenteHochladenComponent } from './bescheid-wizard-dokumente-hochladen.component'; -import { BescheidWizardDokumenteHochladenFormComponent } from './form/bescheid-wizard-dokumente-hochladen-form.component'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './summary/bescheid-wizard-dokumente-hochladen-summary.component'; - -describe('BescheidWizardDokumenteHochladenComponent', () => { - let component: BescheidWizardDokumenteHochladenComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - BescheidWizardDokumenteHochladenComponent, - MockComponent(BescheidWizardSummaryComponent), - MockComponent(BescheidWizardAntragBescheidenSummaryComponent), - MockComponent(BescheidWizardDokumenteHochladenSummaryComponent), - MockComponent(BescheidWizardStepTitleComponent), - MockComponent(BescheidWizardDokumenteHochladenFormComponent), - MockComponent(BescheidWizardStepperComponent), - ], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('template', () => { - describe('alfa-bescheid-wizard-stepper', () => { - function getElementComponent(): BescheidWizardStepperComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepperComponent); - } - - describe('input', () => { - it('should set activeStep', () => { - fixture.detectChanges(); - - expect(getElementComponent().activeStep).toBe(BescheidWizardStep.DokumenteHochladen); - }); - }); - }); - - describe('alfa-bescheid-wizard-step-title', () => { - function getElementComponent(): BescheidWizardStepTitleComponent { - return getElementFromFixtureByType(fixture, BescheidWizardStepTitleComponent); - } - - describe('input', () => { - it('should set inactiveStep', () => { - fixture.detectChanges(); - - expect(getElementComponent().inactiveStep).toBeTruthy(); - }); - }); - }); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts deleted file mode 100644 index bcf7a846b3cca932af5613b3af7baec9a57d43d6..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-dokumente-hochladen-form.component'; - -describe('BescheidWizardDokumenteHochladenFormComponent', () => { - let component: BescheidWizardDokumenteHochladenFormComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenFormComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BescheidWizardDokumenteHochladenFormComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts deleted file mode 100644 index 3f4923a9b4a0b40edc3b6392aae2d52f2b3b4d8d..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { Component } from '@angular/core'; - -@Component({ - selector: 'alfa-bescheid-wizard-dokumente-hochladen-form', - templateUrl: './bescheid-wizard-dokumente-hochladen-form.component.html', -}) -export class BescheidWizardDokumenteHochladenFormComponent {} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts deleted file mode 100644 index 0b30871de20941b223787ab12b0e40d233dd8f9f..0000000000000000000000000000000000000000 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-dokumente-hochladen-summary.component'; - -describe('BescheidWizardDokumenteHochladenSummaryComponent', () => { - let component: BescheidWizardDokumenteHochladenSummaryComponent; - let fixture: ComponentFixture<BescheidWizardDokumenteHochladenSummaryComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BescheidWizardDokumenteHochladenSummaryComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(BescheidWizardDokumenteHochladenSummaryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html similarity index 60% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html index d147a2c6bdf7308ae737b78a7814e447702120fa..43b8946ab2d59886a58ed927028c68158785dedc 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.html @@ -1,6 +1,6 @@ <!-- - Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -23,4 +23,20 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<p>bescheid-wizard-dokumente-hochladen-form works!</p> +<div class="flex h-full gap-11"> + <div class="flex w-1/2 flex-row gap-7"> + <alfa-bescheid-wizard-stepper + [activeStep]="activeStep" + (stepChange)="stepChange.emit($event)" + data-test-id="wizard-stepper" + /> + <div class="mt-2 flex flex-1 flex-col"> + <ng-content select="[stepPanel]" /> + </div> + </div> + <div class="flex w-1/2"> + <alfa-bescheid-wizard-summary headline="Bescheid" data-test-id="wizard-summary"> + <ng-content select="[summary]" /> + </alfa-bescheid-wizard-summary> + </div> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a3c8cc809e97eb6b89cf7b3dc7ed15b6f6d81f9 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.spec.ts @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; +import { triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { BescheidWizardStepperComponent } from '../stepper/bescheid-wizard-stepper.component'; +import { BescheidWizardSummaryComponent } from '../summary/bescheid-wizard-summary.component'; +import { StepContentLayoutComponent } from './step-content-layout.component'; + +describe('StepContentLayoutComponent', () => { + let component: StepContentLayoutComponent; + let fixture: ComponentFixture<StepContentLayoutComponent>; + + const wizardStepper: string = getDataTestIdOf('wizard-stepper'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + StepContentLayoutComponent, + MockComponent(BescheidWizardStepperComponent), + MockComponent(BescheidWizardSummaryComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(StepContentLayoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('on stepper step change', () => { + it('should emit', () => { + component.stepChange.emit = jest.fn(); + + triggerEvent({ + fixture, + name: 'stepChange', + elementSelector: wizardStepper, + data: BescheidWizardStep.AntragBescheiden, + }); + + expect(component.stepChange.emit).toHaveBeenCalledWith(BescheidWizardStep.AntragBescheiden); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts similarity index 70% rename from alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts rename to alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts index c145f7b4995e9ac1193ce9dd148dc78a50e682da..8fd8d880d084fdcb16f9f121becfdbd1dc850e41 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den * Ministerpräsidenten des Landes Schleswig-Holstein * Staatskanzlei * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung @@ -22,12 +22,14 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { BescheidWizardStep } from '@alfa-client/bescheid-shared'; -import { Component } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ - selector: 'alfa-bescheid-wizard-dokumente-hochladen', - templateUrl: './bescheid-wizard-dokumente-hochladen.component.html', + selector: 'alfa-step-content-layout', + templateUrl: './step-content-layout.component.html', }) -export class BescheidWizardDokumenteHochladenComponent { - public readonly bescheidWizardStep = BescheidWizardStep; +export class StepContentLayoutComponent { + @Input() public activeStep: BescheidWizardStep; + + @Output() public stepChange: EventEmitter<BescheidWizardStep> = new EventEmitter(); } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html index b8fa88049ce906de0d08d137018d21d725c3ded3..cda7188f9d38f435d1c3f582ed9980061bb98c08 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.html @@ -23,7 +23,9 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<section class="flex h-full w-full flex-col overflow-auto rounded-xl bg-background-100 px-4 py-5"> - <h3 class="mb-4 text-base font-bold text-primary-600">Bescheid</h3> - <ng-content></ng-content> +<section class="absolute flex size-full flex-col gap-4 overflow-auto rounded-xl bg-background-100 px-4 py-5"> + <h3 class="text-base font-bold text-primary">{{ headline }}</h3> + <div class="flex-1"> + <ng-content /> + </div> </section> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts index f6ca78a11b86260c57e235229ec2333e80ff6d85..2a6b34b223a8dd367abc352356c67799274d1323 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component.ts @@ -21,10 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; @Component({ selector: 'alfa-bescheid-wizard-summary', templateUrl: './bescheid-wizard-summary.component.html', + styles: [':host {@apply relative w-full}'], }) -export class BescheidWizardSummaryComponent {} +export class BescheidWizardSummaryComponent { + @Input() public headline: string; +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0442de58d2afd83f13f0adb7f928829302ffcea2 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.html @@ -0,0 +1,5 @@ +<alfa-bescheid-wizard-upload-attachment-button + [attachments]="attachments$ | async" + (uploadFile)="uploadFile($event)" + data-test-id="upload-attachment-button" +></alfa-bescheid-wizard-upload-attachment-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6035095eb818710798ad643934245f0ad1cf503f --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.spec.ts @@ -0,0 +1,101 @@ +import { BescheidAttachments, BescheidResource } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, Mock, mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidAttachments, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../tech-shared/test/file'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from './bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadAttachmentButtonComponent } from './upload-attachment-button/bescheid-wizard-upload-attachment-button.component'; + +describe('BescheidWizardUploadAttachmentButtonContainerComponent', () => { + let component: BescheidWizardUploadAttachmentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardUploadAttachmentButtonContainerComponent>; + + const uploadAttachmentButtonTestId: string = getDataTestIdOf('upload-attachment-button'); + + const bescheidAttachments: BescheidAttachments = createBescheidAttachments(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadAttachmentButtonContainerComponent, + MockComponent(BescheidWizardUploadAttachmentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardUploadAttachmentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getAttachments.mockReturnValue(of(bescheidAttachments)); + + createComponent(); + + expect(component.attachments$).toBeObservable(singleColdCompleted(bescheidAttachments)); + }); + + describe('uploadFile', () => { + it('should call bescheid service', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + const file: File = createFile(); + component.bescheidResource = bescheidResource; + + component.uploadFile(file); + + expect(bescheidService.uploadAttachment).toHaveBeenCalledWith(file, bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('upload attachment button', () => { + it('should have been called with inputs', () => { + bescheidService.getAttachments.mockReturnValue(of(bescheidAttachments)); + createComponent(); + + const uploadAttachmentButtonComponent: BescheidWizardUploadAttachmentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadAttachmentButtonComponent>( + fixture, + uploadAttachmentButtonTestId, + ); + + expect(uploadAttachmentButtonComponent.attachments).toEqual(bescheidAttachments); + }); + + describe('output', () => { + describe('uploadFile', () => { + it('should call handler', () => { + component.uploadFile = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadAttachmentButtonTestId, name: 'uploadFile', data: file }); + + expect(component.uploadFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..620adb8db26f04e7dc6b810c37c6acdef0c12d4e --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidAttachments, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-attachment-button-container', + templateUrl: './bescheid-wizard-upload-attachment-button-container.component.html', +}) +export class BescheidWizardUploadAttachmentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly attachments$: Observable<BescheidAttachments> = this.bescheidService.getAttachments(); + + public uploadFile(file: File): void { + this.bescheidService.uploadAttachment(file, this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..daa2be54c067aee56f12918fc97895d4a9cfd87f --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.html @@ -0,0 +1,11 @@ +<div [formGroup]="formService.form"> + <ods-file-upload-editor + [parentFormArrayName]="formServiceClass.FIELD_ATTACHMENTS" + [uploadInProgress]="upload" + [fileLinkList]="fileUrls" + (newFile)="uploadFile.emit($event)" + label="Anhang hochladen" + data-test-id="bescheid-wizard-upload-editor" + > + </ods-file-upload-editor> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..7aff85b5a346f756fae78c33398f875236e24390 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.spec.ts @@ -0,0 +1,84 @@ +import { BescheidAttachments } from '@alfa-client/bescheid-shared'; +import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; +import { getElementComponentFromFixtureByCss, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { faker } from '@faker-js/faker'; +import { FileUploadEditorComponent } from '@ods/component'; +import { MockComponent } from 'ng-mocks'; +import { createBescheidAttachments } from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { createBinaryFileResource } from '../../../../../../../binary-file-shared/test/binary-file'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../../tech-shared/test/file'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardUploadAttachmentButtonComponent } from './bescheid-wizard-upload-attachment-button.component'; + +describe('BescheidWizardUploadAttachmentButtonComponent', () => { + let component: BescheidWizardUploadAttachmentButtonComponent; + let fixture: ComponentFixture<BescheidWizardUploadAttachmentButtonComponent>; + + const uploadEditorTestId: string = getDataTestIdOf('bescheid-wizard-upload-editor'); + + const bescheidAttachments: BescheidAttachments = createBescheidAttachments(); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new FormBuilder(), null); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BescheidWizardUploadAttachmentButtonComponent, MockComponent(FileUploadEditorComponent)], + providers: [{ provide: BescheidFormService, useValue: formService }], + imports: [ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardUploadAttachmentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyStateResource()); + expect(component.fileUrls).toEqual([]); + }); + }); + + describe('template', () => { + describe('upload editor', () => { + it('should have been called with inputs', () => { + component.upload = createStateResource(createBinaryFileResource()); + component.fileUrls = [faker.internet.url()]; + + fixture.detectChanges(); + const uploadEditorComponent: FileUploadEditorComponent = getElementComponentFromFixtureByCss<FileUploadEditorComponent>( + fixture, + uploadEditorTestId, + ); + + expect(uploadEditorComponent.parentFormArrayName).toEqual(BescheidFormService.FIELD_ATTACHMENTS); + expect(uploadEditorComponent.uploadInProgress).toEqual(component.upload); + expect(uploadEditorComponent.fileLinkList).toEqual(component.fileUrls); + }); + + describe('output', () => { + describe('newFile', () => { + it('should emit', () => { + component.uploadFile.emit = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadEditorTestId, name: 'newFile', data: file }); + + expect(component.uploadFile.emit).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ec17648a4f94e19a0b6184e4a2cbb68f1b6edcd --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component.ts @@ -0,0 +1,32 @@ +import { BescheidAttachments, createEmptyBescheidAttachments } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { getUrl } from '@ngxp/rest'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-attachment-button', + templateUrl: './bescheid-wizard-upload-attachment-button.component.html', +}) +export class BescheidWizardUploadAttachmentButtonComponent { + @Input() set attachments(value: BescheidAttachments) { + this.updateAttachments(value); + } + + @Output() uploadFile: EventEmitter<File> = new EventEmitter<File>(); + + public readonly formService: BescheidFormService = inject(BescheidFormService); + + public fileUrls: string[] = []; + public upload: StateResource<BinaryFileResource> = createEmptyStateResource(); + private _attachments: BescheidAttachments = createEmptyBescheidAttachments(); + + public readonly formServiceClass = BescheidFormService; + + updateAttachments(value: BescheidAttachments) { + this._attachments = value; + this.upload = value.uploadStateResource; + this.fileUrls = this._attachments.items.map((binaryFileResource: BinaryFileResource) => getUrl(binaryFileResource)); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..99efc09710ff3289b34e59461294c0a3e39596a7 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.html @@ -0,0 +1,6 @@ +<alfa-bescheid-wizard-upload-document-button + [bescheidResource]="bescheidResource" + [bescheidDocument]="bescheidDocument$ | async" + (file)="uploadBescheidDocumentFile($event)" + data-test-id="bescheid-wizard-upload-document-button" +></alfa-bescheid-wizard-upload-document-button> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aad7d40ccedf3a798acadb6be1b76e9560b43912 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.spec.ts @@ -0,0 +1,102 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { getElementComponentFromFixtureByCss, mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheidDocument, createBescheidResource } from '../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../tech-shared/test/file'; +import { singleColdCompleted } from '../../../../../../tech-shared/test/marbles'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from './bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardUploadDocumentButtonComponent } from './upload-document-button/bescheid-wizard-upload-document-button.component'; + +describe('BescheidWizardDokumentHochladenContainerButtonComponent', () => { + let component: BescheidWizardUploadDocumentButtonContainerComponent; + let fixture: ComponentFixture<BescheidWizardUploadDocumentButtonContainerComponent>; + + const uploadDocumentButtonTestId: string = getDataTestIdOf('bescheid-wizard-upload-document-button'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let bescheidService: Mock<BescheidService2>; + + beforeEach(() => { + bescheidService = mock(BescheidService2); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadDocumentButtonContainerComponent, + MockComponent(BescheidWizardUploadDocumentButtonComponent), + ], + providers: [{ provide: BescheidService2, useValue: bescheidService }], + }).compileComponents(); + + createComponent(); + }); + + function createComponent() { + fixture = TestBed.createComponent(BescheidWizardUploadDocumentButtonContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + } + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + + createComponent(); + + expect(component.bescheidDocument$).toBeObservable(singleColdCompleted(bescheidDocument)); + }); + + describe('uploadBescheidDocumentFile', () => { + it('should call bescheid service', () => { + const file: File = createFile(); + const bescheidResource: BescheidResource = createBescheidResource(); + component.bescheidResource = bescheidResource; + + component.uploadBescheidDocumentFile(file); + + expect(bescheidService.uploadBescheidDocument).toHaveBeenCalledWith(file, bescheidResource); + }); + }); + }); + + describe('template', () => { + describe('upload document button', () => { + it('should have been called with inputs', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + bescheidService.getBescheidDocument.mockReturnValue(of(bescheidDocument)); + createComponent(); + component.bescheidResource = bescheidResource; + + fixture.detectChanges(); + const uploadDocumentButtonComponent: BescheidWizardUploadDocumentButtonComponent = + getElementComponentFromFixtureByCss<BescheidWizardUploadDocumentButtonComponent>(fixture, uploadDocumentButtonTestId); + + expect(uploadDocumentButtonComponent.bescheidResource).toEqual(bescheidResource); + expect(uploadDocumentButtonComponent.bescheidDocument).toEqual(bescheidDocument); + }); + + describe('output', () => { + describe('file', () => { + it('should call handler', () => { + component.uploadBescheidDocumentFile = jest.fn(); + const file: File = createFile(); + + triggerEvent({ fixture, elementSelector: uploadDocumentButtonTestId, name: 'file', data: file }); + + expect(component.uploadBescheidDocumentFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a874617f496f42ccb8492a8fd116ae29d2384d36 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component.ts @@ -0,0 +1,20 @@ +import { BescheidDocument, BescheidResource } from '@alfa-client/bescheid-shared'; +import { Component, inject, Input } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BescheidService2 } from '../../../../../../bescheid-shared/src/lib/bescheid2.service'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-document-button-container', + templateUrl: './bescheid-wizard-upload-document-button-container.component.html', +}) +export class BescheidWizardUploadDocumentButtonContainerComponent { + @Input() bescheidResource: BescheidResource; + + private readonly bescheidService = inject(BescheidService2); + + public readonly bescheidDocument$: Observable<BescheidDocument> = this.bescheidService.getBescheidDocument(); + + public uploadBescheidDocumentFile(file: File): void { + this.bescheidService.uploadBescheidDocument(file, this.bescheidResource); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0b04ceb6fc50d6d98b70f95f7f252c6a62a11252 --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.html @@ -0,0 +1,14 @@ +<div [formGroup]="formService.form" class="w-full"> + <ods-single-file-upload-editor + *ngIf="bescheidResource | hasLink: bescheidLinkRel.UPLOAD_BESCHEID_FILE" + [uploadInProgress]="upload.loading" + [formControlName]="formServiceClass.FIELD_BESCHEID_DOCUMENT" + (newFile)="uploadFile($event)" + class="w-72" + data-test-id="bescheid-wizard-upload-document-upload-editor" + > + <ods-bescheid-upload-icon icon></ods-bescheid-upload-icon> + <ods-spinner-icon spinner size="extra-large"></ods-spinner-icon> + <div text class="text-center">Bescheiddokument hochladen</div> + </ods-single-file-upload-editor> +</div> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6616d37317a467e6a8c1976cfb1f2f5fc937ffc --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.spec.ts @@ -0,0 +1,148 @@ +import { BescheidDocument, BescheidLinkRel, createEmptyUploadInProgress } from '@alfa-client/bescheid-shared'; +import { HasLinkPipe } from '@alfa-client/tech-shared'; +import { + existsAsHtmlElement, + getElementComponentFromFixtureByCss, + mock, + notExistsAsHtmlElement, + triggerEvent, + useFromMock, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; +import { SingleFileUploadEditorComponent } from '@ods/component'; +import { BescheidUploadIconComponent, SpinnerIconComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { BescheidService2 } from '../../../../../../../bescheid-shared/src/lib/bescheid2.service'; +import { + createBescheidDocument, + createBescheidResource, + createPendingUpload, +} from '../../../../../../../bescheid-shared/src/test/bescheid'; +import { getDataTestIdOf } from '../../../../../../../tech-shared/test/data-test'; +import { createFile } from '../../../../../../../tech-shared/test/file'; +import { BescheidFormService } from '../../../bescheid.formservice'; +import { BescheidWizardUploadDocumentButtonComponent } from './bescheid-wizard-upload-document-button.component'; + +describe('BescheidWizardDokumentHochladenButtonComponent', () => { + let component: BescheidWizardUploadDocumentButtonComponent; + let fixture: ComponentFixture<BescheidWizardUploadDocumentButtonComponent>; + + const fileUploadEditorTestId: string = getDataTestIdOf('bescheid-wizard-upload-document-upload-editor'); + + const bescheidDocument: BescheidDocument = createBescheidDocument(); + + let formService: BescheidFormService; + + beforeEach(() => { + formService = new BescheidFormService(new UntypedFormBuilder(), useFromMock(mock(BescheidService2))); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BescheidWizardUploadDocumentButtonComponent, + MockComponent(SingleFileUploadEditorComponent), + MockComponent(BescheidUploadIconComponent), + MockComponent(SpinnerIconComponent), + HasLinkPipe, + ], + providers: [ + { + provide: BescheidFormService, + useValue: formService, + }, + ], + imports: [ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(BescheidWizardUploadDocumentButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set initial values', () => { + expect(component.upload).toEqual(createEmptyUploadInProgress()); + }); + + describe('set bescheid document', () => { + it('should call form service', () => { + formService.updateBescheidDocumentFile = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(formService.updateBescheidDocumentFile).toHaveBeenCalledWith(bescheidDocument.documentUri); + }); + + it('should set upload', () => { + formService.updateBescheidDocumentFile = jest.fn(); + + component.bescheidDocument = bescheidDocument; + + expect(component.upload).toEqual(bescheidDocument.upload); + }); + }); + + describe('uploadFile', () => { + it('should emit', () => { + component.file.emit = jest.fn(); + const file: File = createFile(); + + component.uploadFile(file); + + expect(component.file.emit).toHaveBeenCalledWith(file); + }); + }); + }); + + describe('template', () => { + describe('file upload editor', () => { + it('should exists', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, fileUploadEditorTestId); + }); + + it('should NOT exists', () => { + component.bescheidResource = createBescheidResource(); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, fileUploadEditorTestId); + }); + + it('should have been called with inputs', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + component.upload = createPendingUpload(); + + fixture.detectChanges(); + const fileUploadEditorComponent: SingleFileUploadEditorComponent = + getElementComponentFromFixtureByCss<SingleFileUploadEditorComponent>(fixture, fileUploadEditorTestId); + + expect(fileUploadEditorComponent.uploadInProgress).toEqual(component.upload.loading); + }); + + describe('output', () => { + describe('newFile', () => { + it('should call handler', () => { + component.bescheidResource = createBescheidResource([BescheidLinkRel.UPLOAD_BESCHEID_FILE]); + const file: File = createFile(); + component.uploadFile = jest.fn(); + fixture.detectChanges(); + + triggerEvent({ fixture, elementSelector: fileUploadEditorTestId, name: 'newFile', data: file }); + + expect(component.uploadFile).toHaveBeenCalledWith(file); + }); + }); + }); + }); + }); +}); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d48f7dbde8774df3bf2599415e84da79a123d49d --- /dev/null +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component.ts @@ -0,0 +1,36 @@ +import { + BescheidDocument, + BescheidLinkRel, + BescheidResource, + createEmptyUploadInProgress, + UploadFileInProgress, +} from '@alfa-client/bescheid-shared'; +import { Component, EventEmitter, inject, Input, Output } from '@angular/core'; +import { BescheidFormService } from '../../../bescheid.formservice'; + +@Component({ + selector: 'alfa-bescheid-wizard-upload-document-button', + templateUrl: './bescheid-wizard-upload-document-button.component.html', + styles: [':host {@apply flex grow}'], +}) +export class BescheidWizardUploadDocumentButtonComponent { + @Input() bescheidResource: BescheidResource; + + @Input() set bescheidDocument(value: BescheidDocument) { + this.formService.updateBescheidDocumentFile(value.documentUri); + this.upload = value.upload; + } + + @Output() file: EventEmitter<File> = new EventEmitter<File>(); + + public readonly formService = inject(BescheidFormService); + + public upload: UploadFileInProgress = createEmptyUploadInProgress(); + + public readonly formServiceClass = BescheidFormService; + public readonly bescheidLinkRel = BescheidLinkRel; + + public uploadFile(file: File): void { + this.file.emit(file); + } +} diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html index e02e0583599c0f9efd985994734571c1e19de055..491749c3c65e2134761b1588f930f5a29bde5561 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.html @@ -28,8 +28,8 @@ (clickEmitter)="clickEmitter.emit()" variant="primary" size="medium" - class="mt-8 flex" - data-test-id="bescheid-weiter-button" + class="mt-4 flex" text="Weiter" + dataTestId="bescheid-weiter-button" > </ods-button-with-spinner> diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts index 5f970240cbfc56e5c7bb123b1c93060e1360b195..d5f5cded5a3a08e16a482c4674febf9a5c66fd21 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component.spec.ts @@ -29,14 +29,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { MockComponent } from 'ng-mocks'; import { createCommandResource } from '../../../../../../command-shared/test/command'; -import { getDataTestIdOf } from '../../../../../../tech-shared/test/data-test'; +import { getDataTestIdAttributeOf } from '../../../../../../tech-shared/test/data-test'; import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-weiter-button.component'; describe('BescheidWizardWeiterButtonComponent', () => { let component: BescheidWizardWeiterButtonComponent; let fixture: ComponentFixture<BescheidWizardWeiterButtonComponent>; - const button: string = getDataTestIdOf('bescheid-weiter-button'); + const button: string = getDataTestIdAttributeOf('bescheid-weiter-button'); let clickEmitter: Mock<EventEmitter<MouseEvent>>; diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts index 68c46faa40d9354dfcb976a2726e533f76b96cb3..2125d0b8e171796f264901d4b22e40c269d0cc7d 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.spec.ts @@ -21,18 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidService } from '@alfa-client/bescheid-shared'; -import { formatForDatabase } from '@alfa-client/tech-shared'; +import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidWizardStep, Wizard, } from '@alfa-client/bescheid-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { createErrorStateResource, createLoadingStateResource, formatForDatabase, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import { UntypedFormBuilder } from '@angular/forms'; import { faker } from '@faker-js/faker'; +import { expect } from '@jest/globals'; import { ResourceUri } from '@ngxp/rest'; import { EMPTY, Observable, of } from 'rxjs'; -import { createBescheid, createBescheidResource } from '../../../../bescheid-shared/src/test/bescheid'; -import { singleCold } from '../../../../tech-shared/test/marbles'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; +import { createBescheid, createBescheidResource, createWizard } from '../../../../bescheid-shared/src/test/bescheid'; +import { createSuccessfullyDoneCommandStateResource } from '../../../../command-shared/test/command'; +import { createProblemDetail } from '../../../../tech-shared/test/error'; +import { singleCold, singleColdCompleted } from '../../../../tech-shared/test/marbles'; import { createVorgangWithEingangResource } from '../../../../vorgang-shared/test/vorgang'; import { BescheidFormService } from './bescheid.formservice'; @@ -40,27 +45,373 @@ registerLocaleData(localeDe); describe('BescheidFormService', () => { let service: BescheidFormService; - let bescheidService: Mock<BescheidService>; + let bescheidService: Mock<BescheidService2>; const now: Date = new Date(); Date.now = jest.fn().mockReturnValue(now); const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); beforeEach(() => { - bescheidService = mock(BescheidService); - bescheidService.createBescheid.mockReturnValue(of(EMPTY)); + bescheidService = mock(BescheidService2); service = new BescheidFormService(new UntypedFormBuilder(), useFromMock(bescheidService)); service.setVorgangWithEingangResource(vorgangWithEingangResource); }); describe('doSubmit', () => { + const wizard: Wizard = createWizard(); + + beforeEach(() => { + service._submitBescheid = jest.fn().mockReturnValue(EMPTY); + bescheidService.getWizard.mockReturnValue(of(wizard)); + }); + + it('should get wizard', () => { + service.submit().subscribe(); + + expect(bescheidService.getWizard).toHaveBeenCalled(); + }); + + it('should submit bescheid', () => { + service.submit().subscribe(); + + expect(service._submitBescheid).toHaveBeenCalledWith(wizard); + }); + + it('should return command', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._submitBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service.submit(); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('_submitBescheid', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + + beforeEach(() => { + service._updateAndSendBescheid = jest.fn().mockReturnValue(EMPTY); + service._createBescheid = jest.fn().mockReturnValue(EMPTY); + service._updateBescheid = jest.fn().mockReturnValue(EMPTY); + service.isPatch = jest.fn(); + }); + + describe('create', () => { + beforeEach(() => { + service.isPatch = jest.fn().mockReturnValue(false); + }); + + it('should create', () => { + service._submitBescheid(createWizard()).subscribe(); + + expect(service._createBescheid).toHaveBeenCalled(); + }); + + it('should return command', () => { + service._createBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(createWizard()); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('update', () => { + beforeEach(() => { + service._canSendBescheid = jest.fn().mockReturnValue(false); + }); + + it('should update on change bescheid', () => { + service.isPatch = jest.fn().mockReturnValue(true); + + service._submitBescheid(createWizard()).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should update on existing bescheid', () => { + service.isPatch = jest.fn().mockReturnValue(false); + service.patchValues(createBescheidResource()); + + service._submitBescheid(createWizard()).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should return command', () => { + service.isPatch = jest.fn().mockReturnValue(true); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(createWizard()); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + + describe('update and send', () => { + const wizard: Wizard = createWizard(); + + beforeEach(() => { + service.isPatch = jest.fn().mockReturnValue(true); + }); + + it('should update and send', () => { + service._canSendBescheid = jest.fn().mockReturnValue(true); + + service._submitBescheid(wizard).subscribe(); + + expect(service._updateAndSendBescheid).toHaveBeenCalledWith(wizard.sendBy); + }); + + it('should NOT update and send', () => { + service._canSendBescheid = jest.fn().mockReturnValue(false); + + service._submitBescheid(wizard).subscribe(); + + expect(service._updateAndSendBescheid).not.toHaveBeenCalled(); + }); + + it('should return command', () => { + service._updateAndSendBescheid = jest.fn().mockReturnValue(of(command)); + + const submit$: Observable<StateResource<CommandResource>> = service._submitBescheid(wizard); + + expect(submit$).toBeObservable(singleColdCompleted(command)); + }); + }); + }); + + describe('_canSendBescheid', () => { + it('should return true', () => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: BescheidWizardStep.BescheidVersenden, + canBeSend: true, + }); + + expect(canSendBescheid).toBeTruthy(); + }); + + it.each([BescheidWizardStep.AntragBescheiden, BescheidWizardStep.DokumenteHochladen])( + 'should return false on step %s', + (step: BescheidWizardStep) => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: step, + canBeSend: true, + }); + + expect(canSendBescheid).toBeFalsy(); + }, + ); + + it('should return false if bescheid sending locked', () => { + const canSendBescheid: boolean = service._canSendBescheid({ + ...createWizard(), + activeStep: BescheidWizardStep.BescheidVersenden, + canBeSend: false, + }); + + expect(canSendBescheid).toBeFalsy(); + }); + }); + + describe('_createBescheid', () => { + beforeEach(() => { + bescheidService.createBescheid.mockReturnValue(of(EMPTY)); + }); + it('should create bescheid', () => { const formValue: Bescheid = createBescheid(); service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); - service.submit(); + service._createBescheid(); expect(bescheidService.createBescheid).toHaveBeenCalledWith(vorgangWithEingangResource, formValue); }); + + it('should return create command', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const createCommand: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidService.createBescheid.mockReturnValue(of(createCommand)); + + const command$: Observable<StateResource<CommandResource>> = service._createBescheid(); + + expect(command$).toBeObservable(singleColdCompleted(createCommand)); + }); + }); + + describe('_updateBescheid', () => { + beforeEach(() => { + bescheidService.updateBescheid.mockReturnValue(of(EMPTY)); + }); + + it('should update bescheid', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const bescheidResource: BescheidResource = createBescheidResource(); + service.patchValues(bescheidResource); + + service._updateBescheid(); + + expect(bescheidService.updateBescheid).toHaveBeenCalledWith(bescheidResource, formValue); + }); + + it('should return create command', () => { + const formValue: Bescheid = createBescheid(); + service.getBescheidFormValue = jest.fn().mockReturnValue(formValue); + const bescheidResource: BescheidResource = createBescheidResource(); + service.patchValues(bescheidResource); + const createCommand: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + bescheidService.updateBescheid.mockReturnValue(of(createCommand)); + + const command$: Observable<StateResource<CommandResource>> = service._updateBescheid(); + + expect(command$).toBeObservable(singleColdCompleted(createCommand)); + }); + }); + + describe('_updateAndSendBescheid', () => { + beforeEach(() => { + service._updateBescheid = jest.fn().mockReturnValue(EMPTY); + }); + + describe('send manually', () => { + it('should update bescheid', () => { + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should send bescheid manually', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).toHaveBeenCalled(); + }); + + it('should not send on pending update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + + it('should not send on failed update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + + it('should return update command on pending update', () => { + const command: StateResource<CommandResource> = createLoadingStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return update command on failed update', () => { + const command: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return send bescheid command on successful update', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + bescheidService.sendBescheidManually.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.MANUAL); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should not send message', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.MANUAL).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + }); + + describe('send by nachricht', () => { + it('should update bescheid', () => { + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(service._updateBescheid).toHaveBeenCalled(); + }); + + it('should send bescheid message', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).toHaveBeenCalled(); + }); + + it('should not send on pending update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createLoadingStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + + it('should not send on failed update', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail()))); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidMessage).not.toHaveBeenCalled(); + }); + + it('should return update command on pending update', () => { + const command: StateResource<CommandResource> = createLoadingStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return update command on failed update', () => { + const command: StateResource<CommandResource> = createErrorStateResource(createProblemDetail()); + service._updateBescheid = jest.fn().mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should return send bescheid command on successful update', () => { + const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource(); + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + bescheidService.sendBescheidMessage.mockReturnValue(of(command)); + + const command$: Observable<StateResource<CommandResource>> = service._updateAndSendBescheid(BescheidSendBy.NACHRICHT); + + expect(command$).toBeObservable(singleColdCompleted(command)); + }); + + it('should not send manually', () => { + service._updateBescheid = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource())); + + service._updateAndSendBescheid(BescheidSendBy.NACHRICHT).subscribe(); + + expect(bescheidService.sendBescheidManually).not.toHaveBeenCalled(); + }); + }); }); describe('patchValues', () => { @@ -162,4 +513,30 @@ describe('BescheidFormService', () => { } as Bescheid); }); }); + + describe('clearBescheidDocumentFile', () => { + it('should update bescheid document file', () => { + service.updateBescheidDocumentFile = jest.fn(); + + service.clearBescheidDocumentFile(); + + expect(service.updateBescheidDocumentFile).toHaveBeenCalledWith(null); + }); + }); + + describe('updateBescheidDocumentFile', () => { + it('should patch form control value to null', () => { + service.updateBescheidDocumentFile(); + + expect(service.getBescheidFormValue().bescheidDocument).toBeNull(); + }); + + it('should patch form control value', () => { + const bescheidResource: BescheidResource = createBescheidResource(); + + service.updateBescheidDocumentFile(bescheidResource.bescheidDocument); + + expect(service.getBescheidFormValue().bescheidDocument).toEqual(bescheidResource.bescheidDocument); + }); + }); }); diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts index 4f9036dadf2779eff368da4ceeef7709f53df4e7..4e650ff9f6660e2e987ee53979858474096cafe2 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid.formservice.ts @@ -21,15 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Bescheid, BescheidLinkRel, BescheidResource, BescheidSendBy, BescheidService } from '@alfa-client/bescheid-shared'; -import { CommandResource } from '@alfa-client/command-shared'; -import { AbstractFormService, StateResource, convertToBoolean, formatForDatabase } from '@alfa-client/tech-shared'; +import { + Bescheid, + BescheidLinkRel, + BescheidResource, + BescheidSendBy, + BescheidWizardStep, + Wizard, +} from '@alfa-client/bescheid-shared'; +import { CommandResource, switchMapCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { AbstractFormService, convertToBoolean, formatForDatabase, isNotNil, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Injectable } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { ResourceUri, getUrl, hasLink } from '@ngxp/rest'; -import { isUndefined } from 'lodash-es'; -import { Observable, startWith } from 'rxjs'; +import { FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { getUrl, hasLink, ResourceUri } from '@ngxp/rest'; +import { isNil, isUndefined } from 'lodash-es'; +import { first, Observable, startWith, switchMap } from 'rxjs'; +import { BescheidService2 } from '../../../../bescheid-shared/src/lib/bescheid2.service'; @Injectable() export class BescheidFormService extends AbstractFormService<CommandResource> { @@ -44,10 +52,11 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { static readonly FIELD_PATH_PREFIX = 'command.body'; private vorgangWithEingangResource: VorgangWithEingangResource; + private bescheidResource: BescheidResource; constructor( formBuilder: UntypedFormBuilder, - private readonly bescheidService: BescheidService, + private readonly bescheidService: BescheidService2, ) { super(formBuilder); } @@ -65,25 +74,61 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { } protected doSubmit(): Observable<StateResource<CommandResource>> { + return this.bescheidService.getWizard().pipe( + first(), + switchMap((wizard: Wizard) => this._submitBescheid(wizard)), + ); + } + + _submitBescheid(wizard: Wizard): Observable<StateResource<CommandResource>> { + if (this.isPatch() || isNotNil(this.bescheidResource)) { + if (this._canSendBescheid(wizard)) { + return this._updateAndSendBescheid(wizard.sendBy); + } + return this._updateBescheid(); + } + return this._createBescheid(); + } + + _canSendBescheid(wizard: Wizard): boolean { + return wizard.activeStep === BescheidWizardStep.BescheidVersenden && wizard.canBeSend; + } + + _createBescheid(): Observable<StateResource<CommandResource>> { return this.bescheidService.createBescheid(this.vorgangWithEingangResource, this.getBescheidFormValue()); } + _updateBescheid(): Observable<StateResource<CommandResource>> { + return this.bescheidService.updateBescheid(this.bescheidResource, this.getBescheidFormValue()); + } + + _updateAndSendBescheid(sendBy: BescheidSendBy): Observable<StateResource<CommandResource>> { + if (sendBy === BescheidSendBy.MANUAL) { + return this._updateBescheid().pipe(switchMapCommandSuccessfullyDone(() => this.bescheidService.sendBescheidManually())); + } + if (sendBy === BescheidSendBy.NACHRICHT) { + return this._updateBescheid().pipe(switchMapCommandSuccessfullyDone(() => this.bescheidService.sendBescheidMessage())); + } + } + protected getPathPrefix(): string { return BescheidFormService.FIELD_PATH_PREFIX; } - public patchValues(bescheid: BescheidResource): void { - const bescheidDocumentUri: ResourceUri = this.getBescheidDocumentUri(bescheid); - this.bescheidService.setDocumentUri(bescheidDocumentUri); + public patchValues(bescheidResource: BescheidResource): void { + this.bescheidResource = bescheidResource; + const bescheidDocumentUri: ResourceUri = this.getBescheidDocumentUri(bescheidResource); this.patch({ - [BescheidFormService.FIELD_BESCHIEDEN_AM]: bescheid.beschiedenAm, - [BescheidFormService.FIELD_BEWILLIGT]: String(bescheid.bewilligt), + [BescheidFormService.FIELD_BESCHIEDEN_AM]: bescheidResource.beschiedenAm, + [BescheidFormService.FIELD_BEWILLIGT]: String(bescheidResource.bewilligt), [BescheidFormService.FIELD_BESCHEID_DOCUMENT]: bescheidDocumentUri, - [BescheidFormService.FIELD_SEND_BY]: isUndefined(bescheid.sendBy) ? BescheidSendBy.NACHRICHT : bescheid.sendBy, - [BescheidFormService.FIELD_NACHRICHT_SUBJECT]: bescheid.nachrichtSubject, - [BescheidFormService.FIELD_NACHRICHT_TEXT]: bescheid.nachrichtText, + [BescheidFormService.FIELD_SEND_BY]: + isUndefined(bescheidResource.sendBy) ? BescheidSendBy.NACHRICHT : bescheidResource.sendBy, + [BescheidFormService.FIELD_NACHRICHT_SUBJECT]: bescheidResource.nachrichtSubject, + [BescheidFormService.FIELD_NACHRICHT_TEXT]: bescheidResource.nachrichtText, }); - bescheid.attachments.forEach((attachmentLink) => + (this.form.controls[BescheidFormService.FIELD_ATTACHMENTS] as UntypedFormArray).clear(); + bescheidResource.attachments.forEach((attachmentLink) => (this.form.controls[BescheidFormService.FIELD_ATTACHMENTS] as UntypedFormArray).push( new UntypedFormControl(attachmentLink), ), @@ -114,4 +159,28 @@ export class BescheidFormService extends AbstractFormService<CommandResource> { public setVorgangWithEingangResource(vorgangWithEingangResource: VorgangWithEingangResource): void { this.vorgangWithEingangResource = vorgangWithEingangResource; } + + public clearBescheidDocumentFile(): void { + this.updateBescheidDocumentFile(null); + } + + public updateBescheidDocumentFile(uri?: ResourceUri): void { + if (isNil(uri)) { + this.getBescheidDocumentControl().patchValue(null); + } else { + this.getBescheidDocumentControl().patchValue(uri); + } + } + + private getBescheidDocumentControl(): FormControl { + return <FormControl>this.form.controls[BescheidFormService.FIELD_BESCHEID_DOCUMENT]; + } + + public isBetreffInvalid(): boolean { + return this.form.controls[BescheidFormService.FIELD_NACHRICHT_SUBJECT].invalid; + } + + public isNachrichtInvalid(): boolean { + return this.form.controls[BescheidFormService.FIELD_NACHRICHT_TEXT].invalid; + } } diff --git a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts index 1771b5fc23ff9ce35d049fe26904470bd8e6ffd4..1e6f131245e5bee64444aa62165617f532e2fabc 100644 --- a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts +++ b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts @@ -28,39 +28,68 @@ import { TechSharedModule } from '@alfa-client/tech-shared'; import { UiModule } from '@alfa-client/ui'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { BescheidInVorgangContainerComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang-container.component'; -import { BescheidInVorgangComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang/bescheid-in-vorgang.component'; -import { BescheidListInVorgangContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang-container.component'; -import { BescheidListInVorgangComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component'; -import { DocumentInBescheidContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/document-in-bescheid-container/document-in-bescheid-container.component'; -import { BeschiedenDateContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component'; -import { BeschiedenDateInVorgangContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-in-vorgang-container.component'; - -import { ButtonWithSpinnerComponent } from '@ods/component'; import { + ButtonWithSpinnerComponent, + FileUploadEditorComponent, + SingleFileUploadEditorComponent, + TextareaEditorComponent, + TextEditorComponent, +} from '@ods/component'; +import { + AttachmentComponent, + AttachmentWrapperComponent, + BescheidGenerateIconComponent, BescheidStatusTextComponent, + BescheidUploadIconComponent, BescheidWrapperComponent, + ButtonCardComponent, ButtonComponent, CloseIconComponent, RadioButtonCardComponent, + SaveIconComponent, + SendIconComponent, + SpinnerIconComponent, StampIconComponent, } from '@ods/system'; +import { BescheidInVorgangContainerComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang-container.component'; +import { BescheidInVorgangComponent } from './bescheid-in-vorgang-container/bescheid-in-vorgang/bescheid-in-vorgang.component'; +import { BescheidListInVorgangContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang-container.component'; +import { BescheidListInVorgangComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/bescheid-list-in-vorgang.component'; +import { DocumentInBescheidContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/document-in-bescheid-container/document-in-bescheid-container.component'; import { BescheidWizardContainerComponent } from './bescheid-wizard-container/bescheid-wizard-container.component'; -import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-container/bescheid-wizard/abschliessen-button/bescheid-wizard-abschliessen-button.component'; -import { BescheidWizardAbschliessenDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; -import { BescheidWizardAntragBescheidenComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden.component'; +import { BescheidWizardAbschliessenButtonComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-button/bescheid-wizard-abschliessen-button.component'; +import { BescheidWizardAbschliessenDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/abschliessen-dialog-container/bescheid-wizard-abschliessen-dialog-container.component'; +import { BescheidWizardAntragBescheidenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/bescheid-wizard-antrag-bescheiden-container.component'; import { BescheidWizardAntragBescheidenFormComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/form/bescheid-wizard-antrag-bescheiden-form.component'; import { BescheidWizardAntragBescheidenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/antrag-bescheiden/summary/bescheid-wizard-antrag-bescheiden-summary.component'; +import { BescheidWizardAttachmentFilesComponent } from './bescheid-wizard-container/bescheid-wizard/attachment-files-container/attachment-files/bescheid-wizard-attachment-files.component'; +import { BescheidWizardAttachmentFilesContainerComponent } from './bescheid-wizard-container/bescheid-wizard/attachment-files-container/bescheid-wizard-attachment-files-container.component'; +import { BescheidWizardBescheidVersendenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/bescheid-wizard-bescheid-versenden-container.component'; +import { BescheidWizardBescheidVersendenFormComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/form/bescheid-wizard-bescheid-versenden-form.component'; +import { BescheidWizardBescheidVersendenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/bescheid-wizard-bescheid-versenden-summary.component'; +import { BescheidWizardBescheidVersendenSendenComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/senden/bescheid-wizard-bescheid-versenden-senden.component'; +import { BescheidWizardBescheidVersendenSpeichernComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-versenden/summary/speichern/bescheid-wizard-bescheid-versenden-speichern.component'; import { BescheidWizardComponent } from './bescheid-wizard-container/bescheid-wizard/bescheid-wizard.component'; import { BescheidWizardCancelDialogContainerComponent } from './bescheid-wizard-container/bescheid-wizard/cancel-dialog-container/bescheid-wizard-cancel-dialog-container.component'; -import { BescheidWizardDokumenteHochladenComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/bescheid-wizard-dokumente-hochladen.component'; -import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/form/bescheid-wizard-dokumente-hochladen-form.component'; -import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { BescheidWizardCreateDocumentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/create-document-button-container/bescheid-wizard-create-document-button-container.component'; +import { BescheidWizardCreateDocumentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/create-document-button-container/create-document-button/bescheid-wizard-create-document-button.component'; +import { BescheidWizardDocumentFileContainerComponent } from './bescheid-wizard-container/bescheid-wizard/document-file-container/bescheid-wizard-document-file-container.component'; +import { BescheidWizardDocumentFileComponent } from './bescheid-wizard-container/bescheid-wizard/document-file-container/document-file/bescheid-wizard-document-file.component'; +import { BescheidWizardDokumenteHochladenContainerComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/bescheid-wizard-dokumente-hochladen-container.component'; +import { BescheidWizardDokumenteHochladenFormComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component'; +import { BescheidWizardDokumenteHochladenSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/summary/bescheid-wizard-dokumente-hochladen-summary.component'; +import { StepContentLayoutComponent } from './bescheid-wizard-container/bescheid-wizard/step-content-layout/step-content-layout.component'; import { BescheidWizardStepTitleComponent } from './bescheid-wizard-container/bescheid-wizard/step-title/bescheid-wizard-step-title.component'; import { BescheidWizardStepperComponent } from './bescheid-wizard-container/bescheid-wizard/stepper/bescheid-wizard-stepper.component'; import { BescheidWizardStepComponent } from './bescheid-wizard-container/bescheid-wizard/stepper/step/bescheid-wizard-step.component'; import { BescheidWizardSummaryComponent } from './bescheid-wizard-container/bescheid-wizard/summary/bescheid-wizard-summary.component'; +import { BescheidWizardUploadAttachmentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/bescheid-wizard-upload-attachment-button-container.component'; +import { BescheidWizardUploadAttachmentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/upload-attachment-button-container/upload-attachment-button/bescheid-wizard-upload-attachment-button.component'; +import { BescheidWizardUploadDocumentButtonContainerComponent } from './bescheid-wizard-container/bescheid-wizard/upload-document-button-container/bescheid-wizard-upload-document-button-container.component'; +import { BescheidWizardUploadDocumentButtonComponent } from './bescheid-wizard-container/bescheid-wizard/upload-document-button-container/upload-document-button/bescheid-wizard-upload-document-button.component'; import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container/bescheid-wizard/weiter-button/bescheid-wizard-weiter-button.component'; +import { BeschiedenDateContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component'; +import { BeschiedenDateInVorgangContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-in-vorgang-container.component'; @NgModule({ imports: [ @@ -77,6 +106,18 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container ButtonWithSpinnerComponent, RadioButtonCardComponent, ButtonComponent, + ButtonCardComponent, + BescheidGenerateIconComponent, + SingleFileUploadEditorComponent, + BescheidUploadIconComponent, + SpinnerIconComponent, + AttachmentComponent, + AttachmentWrapperComponent, + FileUploadEditorComponent, + SendIconComponent, + SaveIconComponent, + TextEditorComponent, + TextareaEditorComponent, ], declarations: [ BescheidInVorgangContainerComponent, @@ -94,14 +135,31 @@ import { BescheidWizardWeiterButtonComponent } from './bescheid-wizard-container BescheidWizardSummaryComponent, BescheidWizardWeiterButtonComponent, BescheidWizardCancelDialogContainerComponent, - BescheidWizardAntragBescheidenComponent, + BescheidWizardAntragBescheidenContainerComponent, BescheidWizardAntragBescheidenFormComponent, BescheidWizardAntragBescheidenSummaryComponent, - BescheidWizardDokumenteHochladenComponent, + BescheidWizardDokumenteHochladenContainerComponent, BescheidWizardDokumenteHochladenFormComponent, BescheidWizardDokumenteHochladenSummaryComponent, BescheidWizardAbschliessenButtonComponent, BescheidWizardAbschliessenDialogContainerComponent, + BescheidWizardCreateDocumentButtonContainerComponent, + BescheidWizardCreateDocumentButtonComponent, + BescheidWizardUploadDocumentButtonComponent, + BescheidWizardUploadDocumentButtonContainerComponent, + BescheidWizardDocumentFileComponent, + BescheidWizardDocumentFileContainerComponent, + BescheidWizardDocumentFileComponent, + BescheidWizardUploadAttachmentButtonContainerComponent, + BescheidWizardUploadAttachmentButtonComponent, + BescheidWizardAttachmentFilesContainerComponent, + BescheidWizardAttachmentFilesComponent, + BescheidWizardBescheidVersendenContainerComponent, + BescheidWizardBescheidVersendenFormComponent, + BescheidWizardBescheidVersendenSummaryComponent, + BescheidWizardBescheidVersendenSendenComponent, + BescheidWizardBescheidVersendenSpeichernComponent, + StepContentLayoutComponent, ], exports: [ BescheidInVorgangContainerComponent, diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html index 83e0a83f944e796fb61fda44e53b40d6637dda78..96927c6b043705cd333e9783282e98ceeca9bc79 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html @@ -37,7 +37,7 @@ <button *ngIf="deletable" class="flex size-10 items-center justify-center rounded-md hover:border hover:border-grayborder hover:bg-background-50" - (click)="deleteFile()" + (click)="deleteFile($event)" title="Anhang löschen" aria-label="Anhang löschen Button" > diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts index 148cf03abfaa5832df7eed67cdb819b925793c33..7f114ea64baf234b8c76d4a549464d87c21b3801 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.spec.ts @@ -89,10 +89,11 @@ describe('BinaryFile2Component', () => { describe('click on delete button', () => { it('should emit delete', () => { + const clickEvent = new Event(''); jest.spyOn(component.startDelete, 'emit'); component.file = createBinaryFileResource(); - component.deleteFile(); + component.deleteFile(clickEvent); expect(component.startDelete.emit).toHaveBeenCalledWith(component.file); }); diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts index aa28e35fead04be2f7a521f6ebbaf6c4e9c42700..6b0e9946b551196a9968ec0d3f590a876e5c1fb5 100644 --- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts +++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.ts @@ -65,7 +65,8 @@ export class BinaryFile2Component { this.startDownload.emit(this.file); } - deleteFile(): void { + deleteFile(e: Event): void { + e.stopPropagation(); this.startDelete.emit(this.file); } diff --git a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts index 33396fafe3df1fc0f053eb653f7884bf0e5d8788..f4ae75529acf2ebe89875ff3a99f1cc73bc6046e 100644 --- a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.spec.ts @@ -21,12 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource, createStateResource } from '@alfa-client/tech-shared'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createErrorStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { createCommandResource, createSuccessfullyDoneCommandStateResource } from 'libs/command-shared/test/command'; import { Observable, of } from 'rxjs'; import { CommandResource } from './command.model'; -import { tapOnCommandSuccessfullyDone } from './command.rxjs.operator'; +import { tapOnCommandSuccessfullyDone, tapOnFailedCommand } from './command.rxjs.operator'; +import { createProblemDetail } from '../../../tech-shared/test/error'; import * as CommandUtil from './command.util'; describe('Command rxjs operator', () => { @@ -54,4 +55,28 @@ describe('Command rxjs operator', () => { }); }); }); + + describe('tapOnFailedCommand', () => { + it('should call the execute the runnable if command has failed', (done) => { + const command = createErrorStateResource(createProblemDetail()); + const commandStateResource$: Observable<StateResource<CommandResource>> = of(command); + const runnable = jest.fn(); + + commandStateResource$.pipe(tapOnFailedCommand(runnable)).subscribe(() => { + expect(runnable).toHaveBeenCalledWith(command); + done(); + }); + }); + + it('should NOT execute the runnable if command was successful', (done) => { + const command = createSuccessfullyDoneCommandStateResource(); + const commandStateResource$: Observable<StateResource<CommandResource>> = of(command); + const runnable = jest.fn(); + + commandStateResource$.pipe(tapOnFailedCommand(runnable)).subscribe(() => { + expect(runnable).not.toHaveBeenCalled(); + done(); + }); + }); + }); }); diff --git a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts index 3acbebff9699ea2dbc5695212070f63e9b07a96b..9e0fddd601cc937185b27a525fab2d710bebe16f 100644 --- a/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts +++ b/alfa-client/libs/command-shared/src/lib/command.rxjs.operator.ts @@ -21,19 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource } from '@alfa-client/tech-shared'; +import { hasStateResourceError, StateResource } from '@alfa-client/tech-shared'; import { Observable, of, switchMap, tap } from 'rxjs'; import { CommandResource } from './command.model'; import { isSuccessfulDone } from './command.util'; export function tapOnCommandSuccessfullyDone( runnable: (commandStateResource: StateResource<CommandResource>) => void, -): ( - source: Observable<StateResource<CommandResource>>, -) => Observable<StateResource<CommandResource>> { - return ( - source: Observable<StateResource<CommandResource>>, - ): Observable<StateResource<CommandResource>> => { +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { return source.pipe( tap((commandStateResource: StateResource<CommandResource>) => { if (isSuccessfulDone(commandStateResource.resource)) runnable(commandStateResource); @@ -42,14 +38,22 @@ export function tapOnCommandSuccessfullyDone( }; } +export function tapOnFailedCommand( + runnable: (commandStateResource: StateResource<CommandResource>) => void, +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { + return source.pipe( + tap((commandStateResource: StateResource<CommandResource>) => { + if (hasStateResourceError(commandStateResource)) runnable(commandStateResource); + }), + ); + }; +} + export function switchMapCommandSuccessfullyDone( runnable: (command: StateResource<CommandResource>) => Observable<StateResource<CommandResource>>, -): ( - source: Observable<StateResource<CommandResource>>, -) => Observable<StateResource<CommandResource>> { - return ( - source: Observable<StateResource<CommandResource>>, - ): Observable<StateResource<CommandResource>> => { +): (source: Observable<StateResource<CommandResource>>) => Observable<StateResource<CommandResource>> { + return (source: Observable<StateResource<CommandResource>>): Observable<StateResource<CommandResource>> => { return source.pipe( switchMap((commandStateResource: StateResource<CommandResource>) => { if (isSuccessfulDone(commandStateResource.resource)) { diff --git a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html index 4a9fe0c97298f30da5307f19c7ca79cbeca42f73..ff08ce18e4ad8cc6037b84833bd941f375a6da0f 100644 --- a/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html +++ b/alfa-client/libs/design-component/src/lib/form/file-upload-editor/file-upload-editor.component.html @@ -34,7 +34,7 @@ [accept]="accept" [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-button'" [isLoading]="uploadInProgress.loading" - class="relative w-72" + class="relative w-full max-w-72" > <ods-spinner-icon spinner size="medium" /> <ods-attachment-icon icon size="medium" /> diff --git a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html index ab4172edc10957129320faf3a6533cfe9d1c77ce..837b069ad149e2e7e2eb08305e54e8ab74df16f5 100644 --- a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html +++ b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.html @@ -24,7 +24,7 @@ --> <ods-file-upload-button - class="w-72" + class="w-full max-w-72" [id]="uploadFileId" [isLoading]="uploadInProgress" [accept]="accept" diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts index ddc4a66781c0334c956a0d0b1b283b74110d2d38..d586185f3b3b3fc3329ee66325f746976e7753ab 100644 --- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts @@ -37,8 +37,7 @@ const textareaVariants = cva( variant: { default: 'border-primary-600/50 focus-visible:outline-focus focus-visible:border-background-200 hover:border-primary-hover', - error: - 'border-error/50 hover:border-error focus-visible:outline-error focus-visible:border-background-200', + error: 'border-error/50 hover:border-error focus-visible:outline-error focus-visible:border-background-200', }, }, defaultVariants: { @@ -61,7 +60,7 @@ type TextareaVariants = VariantProps<typeof textareaVariants>; [id]="id" [formControl]="fieldControl" [rows]="rows" - [ngClass]="[textareaVariants({ variant }), isResizable ? 'resize' : 'resize-none']" + [ngClass]="[textareaVariants({ variant }), isResizable ? 'resize-y' : 'resize-none']" [placeholder]="placeholder" [autocomplete]="autocomplete" [attr.aria-required]="required" diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts index e90e4a2702d5185cde6f244b5075bfc237952026..201e8100c1682cafdeb57d86521d0b60b99a7b36 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Resource, ResourceUri, getEmbeddedResource, getUrl, hasLink } from '@ngxp/rest'; +import { getEmbeddedResource, getUrl, hasLink, Resource, ResourceUri } from '@ngxp/rest'; import { isEqual, isNil, isNull } from 'lodash-es'; import { HttpError } from '../tech.model'; import { encodeUrlForEmbedding, isNotNull } from '../tech.util'; @@ -42,6 +42,10 @@ export function createEmptyStateResource<T>(loading: boolean = false): StateReso return createStateResource(null, loading); } +export function createLoadingStateResource<T>(): StateResource<T> { + return createEmptyStateResource(true); +} + export function createStateResource<T>(resource: T, loading: boolean = false): StateResource<T> { return { loading, loaded: !isNil(resource), reload: false, resource }; } @@ -50,10 +54,7 @@ export function createErrorStateResource<T>(error: HttpError): StateResource<any return { ...createEmptyStateResource<T>(), error, loaded: true }; } -export function doIfLoadingRequired( - stateResource: StateResource<any>, - runable: () => void, -): boolean { +export function doIfLoadingRequired(stateResource: StateResource<any>, runable: () => void): boolean { if (isLoadingRequired(stateResource)) { runable(); return true; @@ -82,10 +83,7 @@ export function toResourceUri(resource: Resource, linkRel?: string): string { return encodeUrlForEmbedding(url); } -export function doOnValidStateResource( - stateResource: StateResource<Resource>, - actionOnValid: () => void, -): void { +export function doOnValidStateResource(stateResource: StateResource<Resource>, actionOnValid: () => void): void { if (isValidStateResource(stateResource)) actionOnValid(); } @@ -93,10 +91,7 @@ export function isValidStateResource(stateResource: StateResource<unknown>): boo return stateResource.loaded && isNotNull(stateResource.resource); } -export function getEmbeddedResources<T>( - stateResource: StateResource<Resource>, - linkRel: string, -): T[] { +export function getEmbeddedResources<T>(stateResource: StateResource<Resource>, linkRel: string): T[] { if (isNil(stateResource) || isNil(stateResource.resource)) { return []; } @@ -115,12 +110,8 @@ export function containsLoading(stateResources: StateResource<Resource>[]): bool return stateResources.findIndex((stateResources) => stateResources.loading) > -1; } -export function getSuccessfullyLoaded<T extends Resource>( - stateResources: StateResource<T>[], -): StateResource<T>[] { - return stateResources.filter( - (stateResource) => isLoaded(stateResource) && !hasStateResourceError(stateResource), - ); +export function getSuccessfullyLoaded<T extends Resource>(stateResources: StateResource<T>[]): StateResource<T>[] { + return stateResources.filter((stateResource) => isLoaded(stateResource) && !hasStateResourceError(stateResource)); } export function isEmptyStateResource<T extends Resource>(stateResource: StateResource<T>): boolean { @@ -135,8 +126,7 @@ export function isInvalidResourceCombination<T extends Resource, B extends Resou return ( stateResource.reload || (!stateResource.loading && - ((!stateResource.loaded && isNotNull(baseResource)) || - (stateResource.loaded && isNull(baseResource)))) + ((!stateResource.loaded && isNotNull(baseResource)) || (stateResource.loaded && isNull(baseResource)))) ); } diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts index 1cd92c64d9b07060f04273c6007ac1c8920ca8d4..3db736ad9d3f16f89f8d4f0abe6a5a50ba44d208 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts @@ -21,26 +21,14 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidWizardContainerComponent } from '@alfa-client/bescheid'; import { BescheidResource, BescheidService, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; import { createEmptyStateResource, createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; -import { - getElementComponentFromFixtureByCss, - getMockComponent, - Mock, - mock, - notExistsAsHtmlElement, - tooltipExistsWithText, - triggerEvent, -} from '@alfa-client/test-utils'; +import { createDialogRefMock, DialogRefMock, getElementComponentFromFixtureByCss, getMockComponent, Mock, mock, notExistsAsHtmlElement, tooltipExistsWithText, triggerEvent, } from '@alfa-client/test-utils'; import { OzgcloudDialogService } from '@alfa-client/ui'; import { BescheidenDialogData } from '@alfa-client/vorgang-detail'; -import { - VorgangCommandService, - VorgangService, - VorgangWithEingangLinkRel, - VorgangWithEingangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangCommandService, VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource, } from '@alfa-client/vorgang-shared'; import { DialogRef } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonWithSpinnerComponent } from '@ods/component'; @@ -167,60 +155,58 @@ describe('BescheidenButtonComponent', () => { }); }); - // TODO: Use this version after completed Bescheid refactoring and delete the other version below. - // describe('openBescheidenWizard', () => { - // let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>; - // - // beforeEach(() => { - // dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>(); - // ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock); - // }); - // - // it('should open wizard dialog', () => { - // const vorgang = createVorgangWithEingangResource(); - // component.vorgang = vorgang; - // - // component.openBescheidenWizard(); - // - // expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, { - // vorgangWithEingangResource: vorgang, - // }); - // }); - // - // it('should handleBescheidWizardClosed', () => { - // component.handleBescheidWizardClosed = jest.fn(); - // const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true }; - // dialogRefMock.closed = of(dialogResult); - // - // component.openBescheidenWizard(); - // - // expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult); - // }); - // }); + describe('bescheiden icon button', () => { + beforeEach(() => { + component.showAsIconButton = true; + fixture.detectChanges(); + }); + + it('should be hidden', () => { + component.vorgang = createVorgangWithEingangResource(); + + fixture.detectChanges(); + const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton); + + expect(buttonElement).not.toBeInstanceOf(HTMLElement); + }); + + it('should be visible', () => { + component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]); + + fixture.detectChanges(); + const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton); + + expect(buttonElement).toBeInstanceOf(HTMLElement); + }); + }); describe('openBescheidenWizard', () => { - it('should init', () => { - component.openBescheidenWizard(); + let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>; - expect(bescheidService.init).toHaveBeenCalled(); + beforeEach(() => { + dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>(); + ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock); }); - it('should open bescheiden dialog with existing draft', () => { - component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]); - component.openBescheidenDialogWithExistingDraft = jest.fn(); + it('should open wizard dialog', () => { + const vorgang = createVorgangWithEingangResource(); + component.vorgang = vorgang; component.openBescheidenWizard(); - expect(component.openBescheidenDialogWithExistingDraft).toHaveBeenCalled(); + expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, { + vorgangWithEingangResource: vorgang, + }); }); - it('should open bescheiden dialog with new draft', () => { - component.vorgang = createVorgangWithEingangResource(); - component.openBescheidDialogWithNewDraft = jest.fn(); + it('should handleBescheidWizardClosed', () => { + component.handleBescheidWizardClosed = jest.fn(); + const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true }; + dialogRefMock.closed = of(dialogResult); component.openBescheidenWizard(); - expect(component.openBescheidDialogWithNewDraft).toHaveBeenCalled(); + expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult); }); }); diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts index de431e7c593b4e719514f917e3325e41fab3c644..65e3c32d26e50c662463f04804b56def5f01dfca 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.ts @@ -21,19 +21,16 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { BescheidWizardContainerComponent } from '@alfa-client/bescheid'; import { BescheidResource, BescheidService, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared'; import { CommandResource } from '@alfa-client/command-shared'; -import { StateResource, createEmptyStateResource, isLoaded, isNotNil } from '@alfa-client/tech-shared'; +import { createEmptyStateResource, isLoaded, isNotNil, StateResource } from '@alfa-client/tech-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { - VorgangCommandService, - VorgangService, - VorgangWithEingangLinkRel, - VorgangWithEingangResource, -} from '@alfa-client/vorgang-shared'; +import { VorgangCommandService, VorgangService, VorgangWithEingangLinkRel, VorgangWithEingangResource, } from '@alfa-client/vorgang-shared'; +import { DialogRef } from '@angular/cdk/dialog'; import { Component, Input, OnInit } from '@angular/core'; import { hasLink } from '@ngxp/rest'; -import { Observable, filter, first, map, of } from 'rxjs'; +import { filter, first, map, Observable, of } from 'rxjs'; import { BescheidenDialogData } from '../../vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.model'; import { VorgangDetailBescheidenComponent } from '../../vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden.component'; @@ -86,16 +83,15 @@ export class BescheidenButtonComponent implements OnInit { ); } - // TODO: Use this version after completed Bescheid refactoring and delete the other version below. - // public openBescheidenWizard(): void { - // const dialogData: BescheidenDialogData = { vorgangWithEingangResource: this.vorgang }; - // const dialogRef: DialogRef<BescheidWizardDialogResult> = this.ozgcloudDialogService.openWizard< - // BescheidWizardContainerComponent, - // BescheidenDialogData, - // BescheidWizardDialogResult - // >(BescheidWizardContainerComponent, dialogData); - // dialogRef.closed.subscribe((dialogResult: BescheidWizardDialogResult) => this.handleBescheidWizardClosed(dialogResult)); - // } + public openBescheidenWizard(): void { + const dialogData: BescheidenDialogData = { vorgangWithEingangResource: this.vorgang }; + const dialogRef: DialogRef<BescheidWizardDialogResult> = this.ozgcloudDialogService.openWizard< + BescheidWizardContainerComponent, + BescheidenDialogData, + BescheidWizardDialogResult + >(BescheidWizardContainerComponent, dialogData); + dialogRef.closed.subscribe((dialogResult: BescheidWizardDialogResult) => this.handleBescheidWizardClosed(dialogResult)); + } handleBescheidWizardClosed(dialogResult: BescheidWizardDialogResult): void { if (isNotNil(dialogResult) && dialogResult.reloadVorgang) { @@ -103,15 +99,6 @@ export class BescheidenButtonComponent implements OnInit { } } - public openBescheidenWizard(): void { - this.bescheidService.init(); - if (hasLink(this.vorgang, VorgangWithEingangLinkRel.BESCHEID_DRAFT)) { - this.openBescheidenDialogWithExistingDraft(); - } else { - this.openBescheidDialogWithNewDraft(); - } - } - openBescheidenDialogWithExistingDraft(): void { this.bescheidService .getBescheidDraftIfExists() diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html index 31596875ea050b030f15b2960650a111764a15a1..8a82e62b23b248ab3ba1b6521b34f0b6eba6538f 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-step-title/vorgang-detail-bescheiden-step-title.component.html @@ -23,6 +23,6 @@ unter der Lizenz sind dem Lizenztext zu entnehmen. --> -<div class="my-2 text-base font-bold text-primary-600" data-test-id="step-caption"> +<div class="text-base font-bold text-primary-600" data-test-id="step-caption"> {{ label }} </div>