diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts index 19cd002222b625f513309a5bf98a72aa9a982e7f..a120af6e0825c4a292affa1f14694eb0c3184411 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts @@ -927,6 +927,14 @@ describe('BescheidService', () => { singleCold(createEmptyStateResource()), ); }); + + it('should emit empty state resource uploaded attachment', () => { + service.init(); + + expect(service.getUploadedAttachment()).toBeObservable( + singleCold(createEmptyStateResource()), + ); + }); }); describe('create bescheid document', () => { @@ -1351,4 +1359,98 @@ describe('BescheidService', () => { expect(service.bescheidListService.refresh).toHaveBeenCalled(); }); }); + + describe('uploadAttachment', () => { + const bescheidResource: BescheidResource = createBescheidResource([ + BescheidLinkRel.UPLOAD_ATTACHMENT, + ]); + const file: File = createFile(); + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource( + createBinaryFileResource(), + ); + + beforeEach(() => { + binaryFileService.uploadFile.mockReturnValue(of(binaryFileStateResource)); + service.handleAttachmentUpload = jest.fn(); + }); + + it('should emit upload in progress', () => { + service.uploadAttachment(bescheidResource, file).subscribe(); + + expect(service.getUploadAttachmentInProgress()).toBeObservable( + singleCold({ fileName: file.name, loading: true } as UploadFileInProgress), + ); + }); + + it('should upload file', (done) => { + service.uploadAttachment(bescheidResource, file).subscribe(() => { + expect(binaryFileService.uploadFile).toBeCalledWith( + bescheidResource, + BescheidLinkRel.UPLOAD_ATTACHMENT, + file, + false, + ); + done(); + }); + }); + + it('should handle attachment upload', (done) => { + service.uploadAttachment(bescheidResource, file).subscribe(() => { + expect(service.handleAttachmentUpload).toBeCalledWith(binaryFileStateResource); + done(); + }); + }); + + it('should emit uploaded binary file', () => { + expect(service.uploadAttachment(bescheidResource, file)).toBeObservable( + singleColdCompleted(binaryFileStateResource), + ); + }); + }); + + describe('handleAttachmentUpload', () => { + describe('on error', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = + createErrorStateResource(createApiError()); + + it('should emit upload in progress', () => { + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getUploadAttachmentInProgress()).toBeObservable( + singleCold({ + loading: false, + error: binaryFileStateResource.error, + } as UploadFileInProgress), + ); + }); + + it('should emit binary file', () => { + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getUploadedAttachment()).toBeObservable(singleCold(binaryFileStateResource)); + }); + }); + + describe('on success', () => { + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource( + createBinaryFileResource(), + ); + + it('should emit upload in progress', () => { + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getUploadAttachmentInProgress()).toBeObservable( + singleCold({ + loading: false, + } as UploadFileInProgress), + ); + }); + + it('should emit binary file', () => { + service.handleAttachmentUpload(binaryFileStateResource); + + expect(service.getUploadedAttachment()).toBeObservable(singleCold(binaryFileStateResource)); + }); + }); + }); }); diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index 51939bd89281d0a5e4c2971c026cebf8f6ef34ce..1bb8e644829d9f5e7627f8c4aa40b09e2c43e86c 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -42,6 +42,7 @@ import { map, startWith, switchMap, + tap, } from 'rxjs'; import { ListResourceServiceConfig, @@ -97,6 +98,13 @@ export class BescheidService { readonly uploadBescheidDocumentInProgress$: BehaviorSubject<UploadFileInProgress> = new BehaviorSubject<UploadFileInProgress>({ loading: false }); + readonly uploadAttachmentInProgress$: BehaviorSubject<UploadFileInProgress> = new BehaviorSubject( + { loading: false }, + ); + + readonly uploadedAttachment$: BehaviorSubject<StateResource<BinaryFileResource>> = + new BehaviorSubject(createEmptyStateResource()); + loadBescheidDocumentSubscription: Subscription; constructor( @@ -143,6 +151,7 @@ export class BescheidService { ); this.bescheidDocumentFile$.next(createEmptyStateResource()); this.bescheidDocumentUri$.next(null); + this.uploadedAttachment$.next(createEmptyStateResource()); } public getBescheidDraft(): Observable<StateResource<BescheidResource>> { @@ -323,10 +332,10 @@ export class BescheidService { private clearCreateBescheidDocumentInProgress(): void { this.createBescheidDocumentInProgress$.next({ loading: false }); } - private initUploadBescheidDocumentInProgress(fileName: string): void { this.uploadBescheidDocumentInProgress$.next({ fileName, loading: true }); } + public getUploadBescheidDocumentInProgress(): Observable<UploadFileInProgress> { return this.uploadBescheidDocumentInProgress$.asObservable(); } @@ -521,4 +530,41 @@ export class BescheidService { public refreshList(): void { this.bescheidListService.refresh(); } + + public uploadAttachment( + bescheidResource: BescheidResource, + file: File, + ): Observable<StateResource<BinaryFileResource>> { + this.uploadAttachmentInProgress$.next({ fileName: file.name, loading: true }); + return this.binaryFileService + .uploadFile(bescheidResource, BescheidLinkRel.UPLOAD_ATTACHMENT, file, false) + .pipe( + tap((binaryFileStateResource: StateResource<BinaryFileResource>) => + this.handleAttachmentUpload(binaryFileStateResource), + ), + ); + } + + handleAttachmentUpload(binaryFileStateResource: StateResource<BinaryFileResource>) { + if (hasError(binaryFileStateResource)) { + this.uploadAttachmentInProgress$.next({ + loading: false, + error: binaryFileStateResource.error, + }); + } else { + this.uploadAttachmentInProgress$.next({ + ...this.uploadAttachmentInProgress$.value, + loading: binaryFileStateResource.loading, + }); + } + this.uploadedAttachment$.next(binaryFileStateResource); + } + + public getUploadAttachmentInProgress(): Observable<UploadFileInProgress> { + return this.uploadAttachmentInProgress$.asObservable(); + } + + public getUploadedAttachment(): Observable<StateResource<BinaryFileResource>> { + return this.uploadedAttachment$.asObservable(); + } } diff --git a/alfa-client/libs/design-system/src/lib/attachment/attachment.component.ts b/alfa-client/libs/design-system/src/lib/attachment/attachment.component.ts index d7587434211166d8695269b96f639025a72a679e..26b8e0b77783d3dd5f6de9ef1eecbdc5c7db1220 100644 --- a/alfa-client/libs/design-system/src/lib/attachment/attachment.component.ts +++ b/alfa-client/libs/design-system/src/lib/attachment/attachment.component.ts @@ -24,9 +24,15 @@ import { SpinnerIconComponent } from '../icons/spinner-icon/spinner-icon.compone <ods-spinner-icon *ngIf="isLoading && !isError" size="large" /> </div> <div class="flex grow flex-col items-start break-all text-start text-text"> - <p class="text-sm" [ngClass]="isError && 'text-error'"> + <p *ngIf="!isError && !isLoading && caption" class="text-sm"> {{ caption }} </p> + <p *ngIf="isError && errorCaption" class="text-sm text-error"> + {{ errorCaption }} + </p> + <p *ngIf="isLoading && loadingCaption" class="text-sm"> + {{ loadingCaption }} + </p> <p *ngIf="description && !isError" class="text-xs text-text/65"> {{ description }} </p> @@ -38,7 +44,9 @@ import { SpinnerIconComponent } from '../icons/spinner-icon/spinner-icon.compone </button>`, }) export class AttachmentComponent { - @Input({ required: true }) caption!: string; + @Input() caption: string = ''; + @Input() errorCaption: string = ''; + @Input() loadingCaption: string = ''; @Input() fileType: string = ''; @Input() description = ''; @Input() isLoading: boolean = false; diff --git a/alfa-client/libs/tech-shared/test/file.ts b/alfa-client/libs/tech-shared/test/file.ts index 4664c7c07c48b29995dfbef49dc2a27b7ad9b0f9..3f0fd180a866e86a1f9c2747bfae8b876a19950c 100644 --- a/alfa-client/libs/tech-shared/test/file.ts +++ b/alfa-client/libs/tech-shared/test/file.ts @@ -1,3 +1,5 @@ +import { faker } from '@faker-js/faker'; + export function createFile(): File { - return <any>{}; -} \ No newline at end of file + return <any>{ name: faker.datatype.string(10), type: 'image/png', size: 512 }; +} diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.formservice.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.formservice.ts index f7d6ea59813fa20881d5cb9d019aac71f81e6fef..dc987af324371fbc73cab82d955fa0cb935e9443 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.formservice.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/bescheiden.formservice.ts @@ -14,7 +14,6 @@ import { HttpError, StateResource, convertToBoolean, - createEmptyStateResource, formatForDatabase, isNotEmpty, isNotNil, @@ -37,7 +36,6 @@ import { Subscription, combineLatest, map, - of, startWith, } from 'rxjs'; @@ -68,8 +66,6 @@ export class BescheidenFormService extends AbstractFormService implements OnDest ].join('\n\n'); private readonly bescheidChanges$: BehaviorSubject<Bescheid>; - private attachmentUpload$: BehaviorSubject<StateResource<BinaryFileResource>>; - private bescheidFileUpload$: Observable<StateResource<BinaryFileResource>>; private readonly fileDelete$: Subject<BinaryFileResource>; private readonly showMissingBescheidDocumentError$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); @@ -80,7 +76,6 @@ export class BescheidenFormService extends AbstractFormService implements OnDest vorgangWithEingangResource: VorgangWithEingangResource; private formControlSubscriptions: Subscription; - private formChangesSubscription: Subscription; constructor( @@ -96,10 +91,6 @@ export class BescheidenFormService extends AbstractFormService implements OnDest init(): void { this.formControlSubscriptions = this.subscribeToSendBy(); - this.bescheidFileUpload$ = of(createEmptyStateResource<BinaryFileResource>()); - this.attachmentUpload$ = new BehaviorSubject<StateResource<BinaryFileResource>>( - createEmptyStateResource(), - ); this.initializeFormChanges(); } @@ -219,22 +210,6 @@ export class BescheidenFormService extends AbstractFormService implements OnDest return this.vorgangWithEingangResource; } - public getAttachmentUpload(): Observable<StateResource<BinaryFileResource>> { - return this.attachmentUpload$.asObservable(); - } - - public uploadAttachment(attachment: StateResource<BinaryFileResource>): void { - this.attachmentUpload$.next(attachment); - } - - public getBescheidFileUpload(): Observable<StateResource<BinaryFileResource>> { - return this.bescheidFileUpload$; - } - - public setBescheidFileUpload(bescheidFileUpload$: Observable<StateResource<BinaryFileResource>>) { - this.bescheidFileUpload$ = bescheidFileUpload$; - } - public deleteFile(binaryFileResource: BinaryFileResource): void { this.fileDelete$.next(binaryFileResource); } diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html index 780524bd40f6a2dbba30fdeb83df3c133076bd47..fc9bcf1ed04f5df8d10a3a92d1c6d611d827574f 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html @@ -7,12 +7,6 @@ > </alfa-binary-file2-container> <ng-container *ngFor="let attachment of uploadedAttachments"> - <ods-attachment - *ngIf="attachment.error || attachment.loading" - [caption]="getAttachmentCaption(attachment)" - [error]="attachment.error" - [isLoading]="attachment.loading" - ></ods-attachment> <alfa-binary-file2-container *ngIf="!attachment.loading && attachment.resource" [file]="attachment.resource" @@ -22,4 +16,15 @@ > </alfa-binary-file2-container> </ng-container> + <ng-container *ngIf="uploadInProgress$ | async as uploadFileInProgress"> + <ods-attachment + data-test-id="attachment-upload-in-progress" + *ngIf="uploadFileInProgress.loading || uploadFileInProgress.error" + [loadingCaption]="uploadFileInProgress.fileName" + errorCaption="Fehler beim Hochladen" + [error]="uploadFileInProgress.error" + description="Anhang wird hochgeladen" + [isLoading]="uploadFileInProgress.loading" + ></ods-attachment> + </ng-container> </ods-attachment-container> diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts index b60bd2b3fdc6b623666f52ae0b6ef799e75300f3..1e9ed7dcaa08a8f3a261a01eaf31c317eb00d7ac 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts @@ -4,7 +4,6 @@ import { BinaryFileResource } from '@alfa-client/binary-file-shared'; import { convertForDataTest, ConvertForDataTestPipe, - createEmptyStateResource, createErrorStateResource, createStateResource, FileSizePipe, @@ -21,6 +20,7 @@ import { } from '@ods/system'; import { MockComponent, MockPipe } from 'ng-mocks'; import { BehaviorSubject, EMPTY, Observable, of, Subscription } from 'rxjs'; +import { createUploadFileInProgress } from '../../../../../../../bescheid-shared/src/test/bescheid'; import { createBinaryFileResource, createLoadedBinaryFileResource, @@ -41,13 +41,12 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { beforeEach(async () => { bescheidService = mock(BescheidService); bescheidService.getAttachments.mockReturnValue(EMPTY); + bescheidService.getUploadedAttachment.mockReturnValue(EMPTY); formService = mock(BescheidenFormService); formService.getBescheidChanges.mockReturnValue( new BehaviorSubject({ beschiedenAm: new Date(), bewilligt: false }), ); - formService.getAttachmentUpload.mockReturnValue(of(createEmptyStateResource())); - formService.getBescheidFileUpload.mockReturnValue(of(createEmptyStateResource())); await TestBed.configureTestingModule({ declarations: [ @@ -88,6 +87,7 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { const dataTestId = getDataTestIdOf( `${convertForDataTest(attachment.resource.name)}-file2-container`, ); + const uploadInProgressDataTestId: string = getDataTestIdOf('attachment-upload-in-progress'); beforeEach(() => { component.uploadedAttachments = [attachment]; @@ -115,6 +115,38 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { notExistsAsHtmlElement(fixture, dataTestId); }); + + it('should render attachment in progress component when loading', () => { + component.uploadInProgress$ = of({ ...createUploadFileInProgress(), loading: true }); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, uploadInProgressDataTestId); + }); + + it('should render attachment in progress component on error', () => { + component.uploadInProgress$ = of({ + ...createUploadFileInProgress(), + loading: false, + error: createApiError(), + }); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, uploadInProgressDataTestId); + }); + + it('should not render attachment in progress component when not loading and no error', () => { + component.uploadInProgress$ = of({ + ...createUploadFileInProgress(), + loading: false, + error: null, + }); + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, uploadInProgressDataTestId); + }); }); describe('ngOnInit', () => { @@ -137,6 +169,12 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { expect(subscribeToAttachmentUpload).toHaveBeenCalled(); }); + + it('should get upload attachment in progress', () => { + component.ngOnInit(); + + expect(bescheidService.getUploadAttachmentInProgress).toHaveBeenCalled(); + }); }); describe('ngOnDestroy', () => { @@ -144,7 +182,7 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { const subscription = mock(Subscription); const observable = mock(Observable); observable.subscribe.mockReturnValue(subscription); - formService.getAttachmentUpload.mockReturnValue(observable); + bescheidService.getUploadedAttachment.mockReturnValue(observable); component.ngOnInit(); component.ngOnDestroy(); @@ -187,13 +225,7 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { beforeEach(() => { attachment = createLoadedBinaryFileResource(); - formService.getAttachmentUpload.mockReturnValue(of(attachment)); - }); - - it('should get attachment upload', () => { - component.subscribeToAttachmentUpload(); - - expect(formService.getAttachmentUpload).toHaveBeenCalled(); + bescheidService.getUploadedAttachment.mockReturnValue(of(attachment)); }); it('should should set uploaded attachments', () => { diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts index f8497323adfe75ac2e4bc428775bc7e1c6bc5a0c..2fc7831dfd9a89285b24301ca6a8aa19345f083a 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts @@ -1,4 +1,4 @@ -import { BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidService, UploadFileInProgress } from '@alfa-client/bescheid-shared'; import { BinaryFileResource } from '@alfa-client/binary-file-shared'; import { StateResource, @@ -10,7 +10,7 @@ import { } from '@alfa-client/tech-shared'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { getUrl } from '@ngxp/rest'; -import { Subscription, first } from 'rxjs'; +import { Observable, Subscription, first } from 'rxjs'; import { BescheidenFormService } from '../../bescheiden.formservice'; @Component({ @@ -23,6 +23,7 @@ export class VorgangDetailBescheidenResultAttachmentsComponent implements OnDest existingAttachments: BinaryFileResource[] = []; uploadedAttachments: StateResource<BinaryFileResource>[] = []; + uploadInProgress$: Observable<UploadFileInProgress>; private attachmentUploadSubscription: Subscription; @@ -32,6 +33,7 @@ export class VorgangDetailBescheidenResultAttachmentsComponent implements OnDest ) {} ngOnInit(): void { + this.uploadInProgress$ = this.bescheidService.getUploadAttachmentInProgress(); this.loadExistingAttachments(); this.subscribeToAttachmentUpload(); } @@ -52,8 +54,8 @@ export class VorgangDetailBescheidenResultAttachmentsComponent implements OnDest } subscribeToAttachmentUpload() { - this.attachmentUploadSubscription = this.formService - .getAttachmentUpload() + this.attachmentUploadSubscription = this.bescheidService + .getUploadedAttachment() .subscribe( (stateResource: StateResource<BinaryFileResource>) => (this.uploadedAttachments = this.buildUploadedAttachments(stateResource)), @@ -80,16 +82,4 @@ export class VorgangDetailBescheidenResultAttachmentsComponent implements OnDest (attachment) => getUrl(attachment) !== getUrl(file), ); } - - getAttachmentCaption(attachment: StateResource<BinaryFileResource>) { - if (attachment.loading) { - return 'Anhang wird hochgeladen'; - } - - if (attachment.error) { - return 'Fehler beim Hochladen'; - } - - return attachment.resource.name; - } } diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html index 3148cf1d0d907496b5b4f9164e7c1621a1aa3953..a89c65186da52532a6f73829e58afaaaf65703cd 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html @@ -17,8 +17,11 @@ </ng-container> <ods-attachment *ngIf="uploadBescheidDocumentInProgress.loading || uploadBescheidDocumentInProgress.error" - [caption]="attachmentCaption" - [attr.data-test-id]="attachmentDataTestId" + errorCaption="Fehler beim Hochladen" + [loadingCaption]="uploadBescheidDocumentInProgress.fileName" + [attr.data-test-id]=" + 'upload-bescheid-document-error-' + !!uploadBescheidDocumentInProgress.error + " [isLoading]="uploadBescheidDocumentInProgress.loading" [error]="uploadBescheidDocumentInProgress.error" ></ods-attachment> diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts index 5bd0f8b68ece0d217355d957b040611c03259381..2f71e2de6a3ef57174f129655ba0dd7f1c8ddab5 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts @@ -17,7 +17,7 @@ describe('VorgangDetailBescheidenResultDokumentComponent', () => { let fixture: ComponentFixture<VorgangDetailBescheidenResultDokumentComponent>; const createBescheidDocumentError: string = getDataTestIdOf('create-bescheid-document-error'); - const uploadBescheidDocumentError: string = getDataTestIdOf('upload-bescheid-document-error'); + const uploadBescheidDocumentError: string = getDataTestIdOf('upload-bescheid-document-error-true'); const missingBescheidDocumentErrorMessage: string = getDataTestIdOf( 'missing-bescheid-document-error-message', ); diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.ts index f6fc855c98546cb0a9d29ac6dbc03f0ddfc62d41..f46d2cbd1d7aa2719a19b7f73ae55e1efb23945e 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.ts @@ -25,30 +25,6 @@ export class VorgangDetailBescheidenResultDokumentComponent { @Output() deleteFile: EventEmitter<void> = new EventEmitter<void>(); - get attachmentCaption() { - if (this.uploadBescheidDocumentInProgress.loading) { - return 'Bescheiddokument wird hochgeladen'; - } - - if (this.uploadBescheidDocumentInProgress.error) { - return 'Fehler beim Hochladen'; - } - - return this.bescheidDocumentFile.resource.name; - } - - get attachmentDataTestId() { - if (this.uploadBescheidDocumentInProgress.loading) { - return 'upload-bescheid-document-loading'; - } - - if (this.uploadBescheidDocumentInProgress.error) { - return 'upload-bescheid-document-error'; - } - - return 'upload-bescheid-document-file'; - } - constructor(private bescheidService: BescheidService) {} handleBescheidDocument(bescheid: BescheidResource): void { diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.spec.ts index c6d4b9f293b55af444bb3a6b3da555bc5e382200..74c2aea0911f06523b5b632206a370f06cba0f15 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.spec.ts @@ -1,16 +1,17 @@ -import { BescheidLinkRel, BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; +import { BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file'; -import { BinaryFileResource, BinaryFileService } from '@alfa-client/binary-file-shared'; -import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; +import { StateResource, createStateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { FileUploadEditorComponent } from '@ods/component'; -import { cold } from 'jest-marbles'; import { MockComponent } from 'ng-mocks'; import { EMPTY, Observable, Subscription, of } from 'rxjs'; -import { createBescheidResource } from '../../../../../../../../../bescheid-shared/src/test/bescheid'; +import { createBescheidStateResource } from '../../../../../../../../../bescheid-shared/src/test/bescheid'; import { createBinaryFileResource } from '../../../../../../../../../binary-file-shared/test/binary-file'; +import { createFile } from '../../../../../../../../../tech-shared/test/file'; +import { singleColdCompleted } from '../../../../../../../../../tech-shared/test/marbles'; import { BescheidenFormService } from '../../../../bescheiden.formservice'; import { VorgangDetailBescheidenAttachmentHochladenComponent } from './vorgang-detail-bescheiden-attachment-hochladen.component'; @@ -20,15 +21,12 @@ describe('VorgangDetailBescheidenDokumentHochladenComponent', () => { const selfLink: string = 'self'; let bescheidService: Mock<BescheidService>; - let binaryFileService: Mock<BinaryFileService>; let formService: BescheidenFormService; beforeEach(async () => { bescheidService = mock(BescheidService); bescheidService.getAttachments.mockReturnValue(EMPTY); - binaryFileService = mock(BinaryFileService); - formService = new BescheidenFormService(new UntypedFormBuilder(), useFromMock(bescheidService)); await TestBed.configureTestingModule({ @@ -47,10 +45,6 @@ describe('VorgangDetailBescheidenDokumentHochladenComponent', () => { provide: BescheidService, useValue: bescheidService, }, - { - provide: BinaryFileService, - useValue: binaryFileService, - }, ], }).compileComponents(); @@ -167,90 +161,42 @@ describe('VorgangDetailBescheidenDokumentHochladenComponent', () => { }); describe('uploadFile', () => { - const file: File = <any>{ name: 'TestDatei' }; - let uploadAndGetFile: jest.Mock; + const bescheidDraftStateResource: StateResource<BescheidResource> = + createBescheidStateResource(); + const file: File = createFile(); + const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource( + createBinaryFileResource(), + ); beforeEach(() => { - uploadAndGetFile = component.uploadAndGetFile = jest.fn(); + bescheidService.uploadAttachment.mockReturnValue(of(binaryFileStateResource)); + component.bescheidDraftStateResource = bescheidDraftStateResource; }); - it('should uploadAndGetFile', () => { - uploadAndGetFile.mockReturnValue(of(createEmptyStateResource())); - + it('should upload attachment', () => { component.uploadFile(file); - expect(component.uploadAndGetFile).toHaveBeenCalledWith(file); - }); - - it('should start with loading empty state resource', () => { - const loadingStateResource = createEmptyStateResource(true); - const uploadStateResource = createStateResource(createBinaryFileResource()); - uploadAndGetFile.mockReturnValue(cold('-a', { a: uploadStateResource })); - - component.uploadFile(file); + component.uploadInProgress$.subscribe(); - expect(component.uploadInProgress$).toBeObservable( - cold('ab', { a: loadingStateResource, b: uploadStateResource }), + expect(bescheidService.uploadAttachment).toHaveBeenCalledWith( + bescheidDraftStateResource.resource, + file, ); }); - it('should call form service', () => { - formService.uploadAttachment = jest.fn(); - uploadAndGetFile.mockReturnValue(of(createEmptyStateResource())); - + it('should add to file list', () => { component.uploadFile(file); - component.uploadInProgress$.subscribe(); - expect(formService.uploadAttachment).toHaveBeenCalledWith(createEmptyStateResource()); - }); - }); - - describe('uploadAndGetFile', () => { - const file: File = <any>{ name: 'TestDatei' }; - let bescheidResource: BescheidResource; - let uploadResource: BinaryFileResource; - - beforeEach(() => { - bescheidResource = createBescheidResource(); - uploadResource = createBinaryFileResource(); - bescheidService.getBescheidDraft.mockReturnValue(of(createStateResource(bescheidResource))); - binaryFileService.uploadFile.mockReturnValue(of(createStateResource(uploadResource))); - }); - - it('should get bescheid draft', () => { - component.uploadAndGetFile(file); - - expect(bescheidService.getBescheidDraft).toHaveBeenCalled(); - }); - - it('should upload file', (done) => { - const binaryFileStateResource$ = component.uploadAndGetFile(file); - - binaryFileStateResource$.subscribe(() => { - expect(binaryFileService.uploadFile).toHaveBeenCalledWith( - bescheidResource, - BescheidLinkRel.UPLOAD_ATTACHMENT, - file, - false, - ); - done(); - }); - }); - - it('should add file to file list', (done) => { - const binaryFileStateResource$ = component.uploadAndGetFile(file); + component.uploadInProgress$.subscribe(); - binaryFileStateResource$.subscribe(() => { - expect(component.fileList[0]).toEqual(uploadResource); - done(); - }); + expect(component.fileList).toEqual([binaryFileStateResource.resource]); }); - it('should emit binary file state resource', () => { - const binaryFileStateResource$ = component.uploadAndGetFile(file); + it('should emit', () => { + component.uploadFile(file); - expect(binaryFileStateResource$).toBeObservable( - cold('(a|)', { a: createStateResource(uploadResource) }), + expect(component.uploadInProgress$).toBeObservable( + singleColdCompleted(binaryFileStateResource), ); }); }); diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.ts index 6632bbe6b17fd5739b97eb99b67f261f1a7bb672..e707f6c2dbcccc73815f858e8adf68726ba57d6a 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-attachment-hochladen/vorgang-detail-bescheiden-attachment-hochladen.component.ts @@ -1,16 +1,14 @@ -import { BescheidLinkRel, BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; -import { BinaryFileResource, BinaryFileService } from '@alfa-client/binary-file-shared'; +import { BescheidResource, BescheidService } from '@alfa-client/bescheid-shared'; +import { BinaryFileResource } from '@alfa-client/binary-file-shared'; import { StateResource, createEmptyStateResource, doOnValidStateResource, - isLoaded, isNotNil, } from '@alfa-client/tech-shared'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { getUrl } from '@ngxp/rest'; -import { Observable, Subscription, filter, first, of, startWith, switchMap } from 'rxjs'; -import { tap } from 'rxjs/operators'; +import { Observable, Subscription, first, of, tap } from 'rxjs'; import { BescheidenFormService } from '../../../../bescheiden.formservice'; @Component({ @@ -19,6 +17,8 @@ import { BescheidenFormService } from '../../../../bescheiden.formservice'; styles: [], }) export class VorgangDetailBescheidenAttachmentHochladenComponent implements OnInit, OnDestroy { + @Input() bescheidDraftStateResource: StateResource<BescheidResource>; + uploadInProgress$: Observable<StateResource<BinaryFileResource>>; fileList: BinaryFileResource[] = []; private deleteFileSubscription: Subscription; @@ -28,7 +28,6 @@ export class VorgangDetailBescheidenAttachmentHochladenComponent implements OnIn constructor( public readonly formService: BescheidenFormService, private readonly bescheidService: BescheidService, - private readonly binaryFileService: BinaryFileService, ) { this.uploadInProgress$ = of(createEmptyStateResource<BinaryFileResource>()); } @@ -63,34 +62,16 @@ export class VorgangDetailBescheidenAttachmentHochladenComponent implements OnIn return this.fileList.map((fileResource: BinaryFileResource) => getUrl(fileResource)); } - public uploadFile(file: File) { - this.uploadInProgress$ = this.uploadAndGetFile(file).pipe( - tap((stateResource) => this.formService.uploadAttachment(stateResource)), - startWith(createEmptyStateResource<BinaryFileResource>(true)), - ); - } - - uploadAndGetFile(file: File): Observable<StateResource<BinaryFileResource>> { - return this.bescheidService.getBescheidDraft().pipe( - filter(isLoaded), - first(), - switchMap((bescheidStateResource: StateResource<BescheidResource>) => - this.binaryFileService - .uploadFile( - bescheidStateResource.resource, - BescheidLinkRel.UPLOAD_ATTACHMENT, - file, - false, - ) - .pipe( - tap((stateResource: StateResource<BinaryFileResource>) => - doOnValidStateResource( - stateResource, - () => (this.fileList = [...this.fileList, stateResource.resource]), - ), - ), + public uploadFile(file: File): void { + this.uploadInProgress$ = this.bescheidService + .uploadAttachment(this.bescheidDraftStateResource.resource, file) + .pipe( + tap((stateResource: StateResource<BinaryFileResource>) => + doOnValidStateResource( + stateResource, + () => (this.fileList = [...this.fileList, stateResource.resource]), ), - ), - ); + ), + ); } } diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokumente-hinzufuegen.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokumente-hinzufuegen.component.html index 2c98dc3938883b3658342b7bf8194264c0e3bbbc..2cfc7ff99368dc650ab7807c53c4bc0414d00ea4 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokumente-hinzufuegen.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-dokumente-hinzufuegen/vorgang-detail-bescheiden-dokumente-hinzufuegen.component.html @@ -5,5 +5,7 @@ <alfa-vorgang-detail-bescheiden-dokument-hochladen [bescheidDraftStateResource]="bescheidDraftStateResource$ | async" ></alfa-vorgang-detail-bescheiden-dokument-hochladen> - <alfa-vorgang-detail-bescheiden-attachment-hochladen></alfa-vorgang-detail-bescheiden-attachment-hochladen> + <alfa-vorgang-detail-bescheiden-attachment-hochladen + [bescheidDraftStateResource]="bescheidDraftStateResource$ | async" + ></alfa-vorgang-detail-bescheiden-attachment-hochladen> </div>